Last week we had one of our infamous tech rallies and we had a lot of fun trying to build our own Posterous clone in a day, i.e. turning emails into blog posts.

The project sources are hosted on Github. We were working on this one-day project with about 20 developers spread over 4 teams and one of the things I noticed is that most of us did not have more than the very basic Git experience. This meant that we ran into a lot of merge conflicts and solving those is not always easy. Below is a little rundown of the Git learning stages we went through in team MongoDB to deal with this.

Most of us started out with an approach that comes very natural to year-long Subversion users: just work on the master, commit your changes locally, pull to get commits made by other people, solve any merge conflicts, push to the central server. Unfortunately this approach will lead to lots of merge conflicts since other people are doing exactly the same thing. Git is pretty good at auto merging but that does create extra commits that make your history look like this:

Git Merge Hell

Improvement Attempt 1

Iwein told us about a workflow that he had been using on one of his open source projects. The first innovation is to use a small development branch on which you do all your commits while keeping the master clean. When it comes time to push to the central server, you go through a convoluted series of steps to update the master branch to the latest central version, rebase your local branch against that, merge the result back to master, and finally pushing that to the central repository. The workflow looks something like this:

git co local-dev
... do some commits...
git co master
git pull
git co local-dev
git rebase master
git co master
git merge local-dev
...run your tests again, and if they are green...
git push

This worked pretty well but it won't win any beauty prices and all those steps are bound to lead to some errors. Add to that the fact that while you are doing those steps, someone else has probably already committed again. How about something a little simpler ?

Improvement Attempt 2

Once again it was Iwein who came up with a much simpler version that brought us almost all the way back to our first approach. We worked on our local master branch (or on any branch of your choosing as long as it tracks the remote master) as before but when we pulled in changes made by other people, we used rebasing instead of merging to insert those commits into our local branch. Like so:

git co master
... do some commits...
git pull --rebase
...run your tests again, and if they are green...
git push

This worked a lot better and this was the approach that we ended up using the rest of the day.

Afterwards I did some reading and, like all things Git, there are people who say you should never do the above and there are people who swear by it. The Git Ready site has a good article about it and StackOverflow has an interesting discussion on why or why not to use this technique so you can make up your own minds.

Check out the online Pro Git book for a very good Git introduction and/or manual.