Text

One annoying thing about git, is if you push a new local branch to a remote repository and forget the -u argument (short for --set-upstream), it does not automatically set the local branch to track the remote. I forget to include this argument most of the time.

So, later on, you'll probably want to pull changes down from the remote and you'll end up seeing something similar to this

➜  store git:(zendesk) git pull --rebase                                                          [48/53]There is no tracking information for the current branch.
  Please specify which branch you want to rebase against.
  See git-pull(1) for details
  
  git pull <remote> <branch>
  
  If you wish to set tracking information for this branch you can do so with:
  
  git branch --set-upstream-to=origin/<branch> zendesk
  

Now it's not that hard to type out the suggested command above to set the upstream branch, but I got sick of having to do it so often, and I have given up trying to remember -u, so I created a git alias to automate things and save some keystrokes.

In your ~/.gitconfig under the alias section, add this

    sup = !git branch --set-upstream-to=origin/`git symbolic-ref --short HEAD`
  

You can use the alias by issuing the following command in your terminal

$ git sup
  

This will look at the current branch and set its upstream to origin/branchname

If you tend to use another remote name other than origin, change the alias accordingly.

I have a few other useful aliases which you can checkout (hah, sorry :)) in my full gitconfig.

Tags: git
Text

No one likes merge commits, they add noise to git history logs without really helping to convey what exact changes have occurred.

Usually these types of commits can be avoided by keeping feature branches up to date with git --rebase. When two branches have a direct common history, merges can be applied using the fast-forward strategy avoiding the need for a stitch-things-together merge commit.

Because the commit pointed to by the branch you merged in was directly upstream of the commit you’re on, Git moves the pointer forward. To phrase that another way, when you try to merge one commit with a commit that can be reached by following the first commit’s history.
  

http://git-scm.com/book/en/Git-Branching-Basic-Branching-and-Merging

To ensure you've kept your branches synced up with rebase and to avoid accidentally creating a merge commit, you can set git merge to only perform fast forward merges.

$ git config --global merge.ff only
  

This way, you'll get a gentle reminder to rebase. If that's not feasible then you can force through the merge with

$ git merge --no-ff
  
Tags: git
Text

Over time, a remote will have branches added and deleted. Your local working snapshot can often get littered with stale, now removed branches.

To see what branches your local repo things exists you do something like this:

$ git branch -rv
  > origin/1620-upgrade  2e0cc56 Ignore active local.xml from vc
  > origin/HEAD          -> origin/master
  > origin/cas-sso       2351be5 Add gateway logiin and logout support
  > origin/giveaways   63daf5a Use cms blocks for banner placements
  > origin/master        496c975 Merge affiliate module
  > origin/newskin      d7220c9 Optimise skin and ui images
  > origin/release       496c975 Merge affiliate module
  

So this is my local Magento git repository, many of the branches here are now defunct and no longer in the remote (i.e. I had previously had used $ git push origin :branch from another host)

To refresh then I need to prune my branches list. The git incantation to do this is

$ git remote prune origin
  > Pruning origin
  > URL: [email protected]:git/store.git
  * [pruned] origin/1620-upgrade
  * [pruned] origin/giveaways
  * [pruned] origin/newskin
  

Looking at the remote branch list again:

$ git branch -rv
  > origin/HEAD    -> origin/master
  > origin/cas-sso 2351be5 Add gateway logiin and logout support
  > origin/master  496c975 Merge affiliate module
  > origin/release 496c975 Merge affiliate module
  
Tags: git scm
Text

I am just going to give a quick example on how to this.

$ git push origin :REMOTE_BRANCH_NAME
  

For a concrete example of this in action

$ git branch -r
  > origin/develop
  > origin/master
  
  $ git push origin :develop
  > To /home/aaron/development/atestrepo.git
    - [deleted]         develop
  
  $ git branch -r
  > origin/master
  

So, why does this work, and why is the syntax so odd?

Well if we look at the push command in more detail it starts to make some sense.

If we want to push a local branch to a remote, we would do it like this

$ git push origin mybranch
  

Here, origin is the remote, and mybranch the local branch to push up. The result of this command is we now have a remote branch origin/mybranch. But what if we wanted to call the remote branch something else? We would do that like this:

$ git push origin mybranch:adiffnamefortheremotebranch
  

This syntax effectively translates to push to a branch adiffnameforremotebranch at remote origin the contents of mybranch. Now, can you see where this is going with respect to our delete? Deleting a remote branch with just a leading : (and no local branch name) is basically saying push nothing into remote branch called someremotebranch. Git takes this to mean delete the remote branch.

$ git push origin :someremotebranch
  

I find thinking of it in these terms, makes it easier to remember the syntax.

It's also worth reading the Pro Git Chapter on remotes which also covers (although, sadly, too briefly) deleting remote branches.

Text

A simple useful application for Git's stash feature came about today when I started making some amendments to a repo master branch, forgetting I wasn't on my develop branch. I didn't want to make the changes to the master branch and I didn't want to have to copy the files between the two branches manually.

Git stash to the rescue:

$ git stash save
  $ git checkout develop
  $ git stash apply
  $ git commit -m 'Apply stashed changes'
  
Tags: git scm
Text

If you have cloned a remote git repository you default into a checkout of the master branch. Odds are there will be other remote branches, and usually one called 'develop'.

To start developing on this branch instead of the master, use the following command

$ git checkout -b develop origin/develop
  > Branch develop set up to track remote branch develop from origin.
  > Switched to a new branch 'develop'
  

This command creates a local branch tracking the remote develop branch and switches your working directory to this branch.

If you already have a local develop branch and want it to track the remote you can use this instead

$ git checkout develop
  $ git branch --set-upstream develop origin/develop
  
Tags: git scm
Text

If you have an existing codebase and it's already in a git repository there's a number of ways to get it into github (or any other remote git repository). Many of these involve losing your branch history and creating a brand new repository.

This is where the git remote add command comes in handy.

$ git remote add origin [email protected]:ajbonner/foo.git
  

You can see the remotes associated with your branch:

$ git remote -v
  >> origin    [email protected]:ajbonner/foo.git (fetch)
  >> origin    [email protected]:ajbonner/foo.git (push)
  

To push the existing code to the remote:

$ git push origin master
  

You now have set up the remote and pushed your master branch into it. From here it gets tricky because subsequent git pull requests will give you an ugly error

$ git pull
  >> You asked me to pull without telling me which branch you
  want to merge with, and 'branch.master.merge' in
  your configuration file does not tell me, either. Please
  specify which branch you want to use on the command line and
  try again (e.g. 'git pull <repository> <refspec>').
  See git-pull(1) for details.
  
  If you often merge with the same branch, you may want to
  use something like the following in your configuration file:
  
  [branch "master"]
  remote = <nickname>
  merge = <remote-ref>
  
  [remote "<nickname>"]
  url = <url>
  fetch = <refspec>
  
  See git-config(1) for details.
  

There a few ways to get around this:

  1. Follow the directions given by git and edit your gitconfig
  2. Clone a fresh copy of the master branch from the remote
  3. When defining the remote add the --track option and give it the name of the master branch

    $ git remote add --track master origin [email protected]:ajbonner/foo.git

4 Refer to the remote branch using --set-upstream

$ git branch --set-upstream master origin/master
  

Personally I find option number 4 the best with the least amount of work.

You can also use:

$ git config --global branch.autosetupmerge true
  

To avoid having to do this.

Tags: git scm
Text

Edited 10th June '11 - use update site: http://download.eclipse.org/egit/updates

There is an issue at the moment when you try and install the egit/jgit plugins with Indigo versions RC3 and above.

You'll encounter an error similar to this:

An error occurred while collecting items to be installed session context was:(profile=epp.package.rcp, phase=org.eclipse.equinox.internal.p2.engine.phases.Collect, operand=, action=). No repository found containing: osgi.bundle,org.eclipse.egit,1.0.0.201106011211-rc3 No repository found containing: osgi.bundle,org.eclipse.egit.core,1.0.0.201106011211-rc3 No repository found containing: osgi.bundle,org.eclipse.egit.doc,1.0.0.201106011211-rc3 No repository found containing: osgi.bundle,org.eclipse.egit.ui,1.0.0.201106011211-rc3 No repository found containing: osgi.bundle,org.eclipse.jgit,1.0.0.201106011211-rc3

This is caused by the latest jgit packages not yet being in the indigo release p2 update repository. To get these installed until these updates are provided, add http://download.eclipse.org/egit/staging/ as an update site and you'll be able to install these plugins successfully.

I found this solution here: https://bugs.eclipse.org/bugs/show_bug.cgi?id=348183

Text

Create a new repository

$ git init <dirname>
  

Creates a new bare git repository in the current directory, or if a directory argument is given, in that directory.

Version control a file

$ git add file|dir <file|dir> ...
  

Adds, or to use git terminology ‘stages’ a file for a local commit.

Remove a version controlled file

$ git rm -rf --cached <file|dir>
  

This removes a file that has been previously staged (i.e added) for local commit. It does not remove the local file. If you omit the —cached option, the local file WILL be deleted. The rm command is roughly analagous to: $ svn del

Make a local commit

$ git commit <-a> -m 'Commit message' <file> ...
  

The -a flag will commit all pending files recursively in the current path, alternatively you can specify the exact files to commit at the end of the command separated by spaces.

See pending actions or status

$ git status <-u no|all|normal> <path> ...
  

Will show pending files and untracked files in the current working path. Optionally the -u (—untracked-files) option can be supplied to hide/show untracked files in the status report. Passing a path, or number of paths will run the status for that path rather than the current directory.

Create a bare centralised remote repository

$ git clone --bare pathtoinitialrepo <myrepo.git>
  

Alternatively if you don’t have an existing repo already:

$ git init --bare <path>
  

Often you’ll see the .git extension bandied about, particularly on github. This is a canonical reference to a bare git repository (i.e. only has the meta information and not a working copy) that is usually acts as a master or central repository.

Configuring a local repository to push to a remote

$ cd pathtoinitialrepo
  $ git remote add origin ssh:[email protected]/~/repos/myrepo.git
  $ git push origin master
  

If you initially clone from the remote repository you can skip the first step of setting up the origin. However if you have just created a new bare remote repository and want to setup an initial commit, you need to setup the origin first. Subsequent pushes to the remote repository can be done with git push origin master. This is the familiar model of subversion and svn commit.

Create a local copy of a remote git repository

$ git clone ssh:[email protected]/~/repos/myrepo.git
  

Create a local copy from remote repository created following the above approach.

Ignore changes to a tracked file

$ git update-index --assume-unchanged <file>
  

Use this command if you’ve added a file, e.g. a database defaults config file, but do not want further changes to be picked up for it.

To resume tracking changes to the file use:

$ git update-index --no-assume-unchanged <file>