{ Hi! I'm Mike }
I'm a core developer with The Horde Project and a founding parter of Horde LLC - the company behind the world's most flexible groupware platform. This is my personal blog full of random thoughts about development and life in general.
January 16, 2010

Git cherry goodness

With the recent flurry of development activity over at the Horde Project, there came an increase in the number of topic branches in our git repository.  One of the problems dealing with longer living topic branches is the question of how to keep the topic branch in sync with changes going on in the master branch. 

The best way to do this is to rebase the topic branch from master and then rebase your tracking branch against the remote topic branch.  The problem with doing this is that if you are using a post-receive hook to send out commit announcement emails, pushing your changes back to the server will result in duplicate commit messages being sent for the changes that were rebased from origin.  This makes it difficult to zero in on what the actual relevant change in the topic branch is.

After some digging around in the git documentation and some hacking on the script we use for commit messages, we have come up with a good-enough solution. The git cherry can examine the change sets between the two branches and detect if a specific commit on one branch is present on the other branch or not. What makes this so useful is that it doesn't compare commit ids, since these will be different, it actually looks at the diff of each changeset to see if they are the same change.

You can look at the full post-receive-email script we use by looking at our horde-support repository, but the basic idea is to call git cherry like so:

git cherry master [topic branch] 

and then iterate over the results, ignoring any commit ids that are prefixed with a '-'.

So now, my typical development session might go something like this (some commands added for clarity):

# Switch to master branch git checkout master
git pull --rebase

# Resolve, code, hack... 
git add
git commit
git push

 # Pull any new changes
git pull --rebase 

# Switch to my ActiveSync topic branch 
git checkout ActiveSync 

# Rebase it to keep it in sync with master 
git rebase origin/master 
git add
git commit

# rebase it against remote
git pull --rebase git push