This is the second part of my „lessons learned“ from our migration from Mercurial to Git. You can find the first part here.
Beside of the migration of the repositories itself, we kind of needed to migrate the teams also.
At first look, Mercurial and Git seem quite similar: Both are distributed version control systems, both have tags and branches and a lot of concepts are named equally.
Therefore we thought that this part would be easy, but the devil lays in detail, as always.
Differences Between Mercurial and Git
The main difference our teams came across was the difference in the concept of a branch. In Git, branches are just pointers to commits. The only difference, compared to tags is the fact, that they automatically move with each new commit.
Furthermore, we have remote branches and local tracking branches. A concept, completely unknown to Mercurial users.
In Mercurial, branches are way more rigid than in Git. To create a new branch, you need to make a commit and every new commit on that branch is contained within it. Later, you can easily tell which commit was made on which branch. An information, that is usually not contained in a Git repository (IMHO nobody needs it).
Furthermore, in Mercurial, commits have a state such as draft, public or secret. Draft commits are commits that are not pushed yet, while public commits are already published to a remote repository. Secret commits on the other hand are not pushed (A concept, that sound dangerous to me.)
While the Mercurial concept is pretty simple, it is not as flexible as the Git concept. If a repository has multiple remotes, you can easily tell, which commit is in which remote in Git but it is quite complicated in Mercurial as the state of commits differs per remote.
However, the understanding of the branch concepts in Git is fundamental for somebody who works with Git on a daily basis and hence we spend our man effort in teaching the differences to Mercurial here.
The new workflow
One of our main reason for the migration was the fact, that Git integrates better with many of our tools in the company. One of which is Bitbucket Server, which currently supports only Git. (Mercurial might be coming in the future).
With Bitbucket, we have also introduced a new workflow (Bitbucket Pull Request Workflow) which allows us to do code reviews with decent tool support right after a feature or bugfix was written. Before this, we maintained the review state of files in an Excel sheet (believe it or not).
Therefore, the second part of our training was spend on the features of Bitbucket and the interplay of Bitbucket and Jenkins for continuous integration.
Diff and Merge Training
A short time after we migrated the first teams and their repositories to Git, we started a small internal survey to see how everything works out.
The result was mediocre. Git works pretty well and almost all developers see the advantages of the new pull-request workflow. However, most teams struggle with merge conflicts much more than with mercurial before.
We found the root cause for this in the lack of UI tool support for Git. Most people were using TortoiseHg for Mercurial before which automatically solves most of the conflicts in a magical way. The Git UI tools such as SourceTree just do not do this and leave this task to a dedicated merge tool (we use BeyondCompare under Windows).
Therefore, I initiated an optional Merge Training where everyone had time to configure his/her merge tool properly and to solve various kinds of merge conflicts in a playful manner. This solved the merge issues and increased our developers confidence when facing a merge conflict.
While the migration itself was technically not that complicated, migrating the people provided us with much more challenges than we initially thought.
Mercurial and Git are pretty similar from a birds view, but have a lot of small (and not so small) difference if you take a closer look:
- The branch concept
- What pull does
- Plugins and hooks
- Feature sets
- available GUI tools
One of the main issues surely was the lack of a decent GUI tool. Git provides a lot of features and there is not the one-and-only way to work with it. Therefore it is almost impossible to find an UI tool that fits all needs. Therefore it is best to leave the decision to the tool users and provide just some options:
- SourceTree is a good start. It is free but sometimes buggy and slow (at least on Windows systems) and you need to register to use it.
- SmartGit is commercial and provides a lot of features. It is pretty fast as well.
- Tower is the new kid on the block but has only the most important features. I have used Tower on Mac before and liked it a lot.
- GitKraken looks pretty but was slow and buggy when we tested it a year ago.
Most of our developers started out with SourceTree and gave SmartGit a shot as well. Some finally went with the command line. Doubtless the best client for Git.
The migration was more complex than we initially thought. But I would do it again. The new workflow helps our teams a lot and Git works much better for continuous integration in our environment.
Furthermore, the tool-switch causes our folks to relearn the version control stuff and understand it much better than before with Mercurial. We provided some opportunities to learn Git better such as a biweekly Git Club, a 15 to 30 minute format, were some aspect is discussed in detail. People were motivated to learn more because it is a new tool and such a brief format is a digestible way for new stuff.
Last but not least, nowadays it is easier to find developers familiar with Git than with Mercurial.
All in all it was a great experience to do this and it changed the way how we deal with version control, code reviews, teamwork and much more. I have learned a lot during this migration as I became the goto-person for Git questions within our department.
As always, teaching is the best way to learn.
Do you have any questions or something to add? Feel free to write a comment, connect with me via social media or share this post.