A couple of months ago I asked an engineer to create a branch for a particular feature and merge it back to the main development branch when it was ready. I could see the disdain in his face as he looked at me as if I had asked him to do something obnoxious. And I had. SVN was our source control system, it was a legacy tool and as it never presented a major issue to warrant us changing it, we just continued using it. However modern agile engineering practices require us to quickly create new branches, switch between branches & merge branches and this is where SVN is incredibly cumbersome, so much so, that we decided it was time to change.

After a quick evaluation of Mecurial and Git it became apparent that both tools seemed to meet our needs with very little between them. Git seemed a little more complex up front, but it appeared to have more power and flexibility readily available, and as some of the engineers were fans we decided to migrate all our projects to Git. The migration process itself was pretty straight forward. We staggered the project migration over a month, moving one team at a time. We used a tool called svn2git, which allowed us to move all the source code, whilst maintaing all the codes previous commit history. After completing some dry runs, for each project migration, we asked everyone to commit  code changes on a convenient evening, ran the migration and when they got back the next day, we started to use Git.

As Git works in a fundamentally different manner to SVN, the team found it took a couple of days to get used to it. Git at its core is a distributed version control system, so the first thing engineers needed to do was get used to the concept of a local repository that is a clone of the centralized repository. The power of this, is that you can develop and commit code anywhere, including when you are offline, and later synchronize to the centralized repository. As you have a local clone, you can even get a previous version of a file when you are offline. Also, as everyone has a local repository, you can easily share changes with an individual engineer rather than having to commit to the central repository. This is very convenient when more than one engineer is working on a task.

But the real power came in its ability to branch & merge. Historically with SVN, branching was skittish. In Git, switching between branches involves running a simple command (git checkout branch_name) at the command line, and the most elegant part being that the IDE being able to handle it immediately. The days of painfully configuring each branch, within an IDE were over. Incredibly, merging a branch back is much simplified. SVN keeps deltas of each change between commits and during a merge a lot (or an awful lot) of false conflicts are highlighted. Git on the other hand keeps an image of the entire file for each checkin and manages to identify real conflicts far better. Our first major branch resulted in no conflicts to be resolved and simply took a minute, if we were using SVN, it could have been hours, and would have probably had some errors.

As we continued using GIT, we did run into some issues. On a couple of occasions we were just about to push features into staging for final validation prior to release, when we realized that a number of checkins were missing. Pretty uncomfortable to say the least. On another occasion, code that was not meant to be released was found on staging. This was even more uncomfortable.  Both these issues were caused by people forcing changes into master without fully understanding what the commands they were using actually did. I saw these as basic teething problems with people becoming familiar with a new source control system rather than failings in Git. To reduce the risk of these issues happening again, we established a set of guidelines for all the engineers which include details of how best to branch, how best to share code, how we merge etc. We also decided to lock down access to the master branch using gitolite allowing only SysOps and Tech Leads the ability to merge to master. This restriction is seen as a short term fix to allow us grow more comfortable with Git.

Here are some of the practices that we now follow:
  • When you start a new feature, create a local feature branch off of our dev branch
  • When a feature is complete, rebase+squash, then rebase from dev and merge into dev. (squashing keeps the history pertinent)
  • If you need to backup your source or share an incomplete feature, create a copy of your feature branch in origin (or any remote repo)
    • Ideally you should not rebase the shared branch until you are finished with the feature branch
    • If you need to rebase the shared repo, rebase+squash and create a branch off of the shared branch

In summary, whilst there is a learning curve, the transition has proved to be invaluable. Our plan is to be able to release code even more often, and when we do release code that it is of a high level of quality. Git is helping us achieve that goal.

- Michael