As my friend, Jason Chu recently noted, I am primarily a git user who has discovered a need to understand and use Mercurial. I am trying to refrain from judgment on Mercurial, as I’m easily bored by bikeshed discussions and holy wars. I have a pragmatic “use what you like and let me use what I like” philosophy, but when you are interacting with other people’s code, you occasionally have to use what they like.
I have read several articles that I do not intend to link to discussing the differences, and cheat sheets of hg equivalents of common git commands. These are utterly useless. Mercurial and git have different design philosophies, as Jason noted, even though the end result of their usage is much the same. If you’re comfortable with git, and interested in learning Mercurial, you may find my own eureka moment helpful.
hg commit is not the same as
Most comparisons of git and hg do not notice this distinction, but I was really puzzled by how hg could be more powerful than Subversion and supposedly equally powerful to my beloved git until I came to this realization.
In git, when you make a commit, you are creating local history that can be easily changed, modified, or ratified. You can rebase over those changes as many times as you like. You can use git commit –amend to change the commit or add changes to it. The history is not remotely considered “permanent” until you push it to a public repo, and even then, there are times when it is acceptable to rewrite it.
Conversely, in hg, when you commit, you are doing what the word actually says: committing. You are saying “this commit looks the way I want it to, I am finished with it.” You may not be pushing the commit to a remote repo any time soon, you may not be publishing it, but you have written in sandstone that this commit is complete.
I say written in sandstone, rather than stone because there are a variety of hg commands and extensions that allow local history editing, rebasing, and rollbacks. I haven’t learned how fluid these extensions are compared to equivalent history modification in git, but the feeling I am getting is that such changes would be considered much more invasive in hg than in git. History editing is a third party extension; this says to me “not officially supported” (as compared to built-in extensions like Mercurial queues). Mercurial typically desires us to think of a commit as an object that is permanently in the history. Many of the other slightly-deeper-than-cosmetic differences between the two systems seem to stem from this same basic difference.
In git, I have gotten quite used to coding first, and then creating an appropriate history later. There are numerous other potential workflows with git, but that’s the one I like. At first, I thought this was impossible or very difficult with Mercurial. However, when I realized that “commit” falls somewhere between the commands “commit” and “push” in git, things started to fall into place.
Mercurial has a powerful tool called queues that allow you to manipulate history to your heart’s content before you call commit. I’ve been using these effectively to create a workflow that I am comfortable with. It’s not the same as what I’d do in git, not remotely, but the overall outcome is similar.
A related basic understanding that is a little better documented than the difference between
hg commit and
git commit is the following:
hg branch is not the same as
hg branch lies somewhere between
git branch and
git push origin. When you call
hg branch, you are stating an intent that the branch will be public. In git, you can have as many unpublished branches as you want. In Mercurial, this behavior is better achieved by the use of bookmarks, although I’ve found that Mercurial queues are easier to work with.
There are many tutorials for new hg users coming from a svn background, and a few tutorials for those coming from a git background. If you are hoping to learn Mercurial effectively, I suggest avoiding most of those options. It is much better to study Mercurial from the perspective of a programmer who hasn’t seen version control before. Such coders don’t exist (I hope!), but this attitude allows you to learn how the new system should be used, not how to make it behave like a system you are previously used to.
For mercurial basics, I strongly recommend http://hginit.com/, an irreverent and entertaining tutorial on the simpler concepts.
I had a lot of trouble understanding hg queues until I read the hg book chapter on the topic I intend to read the entire red-bean book at some point, as it appears to be much more coherent than the official Mercurial documentation. Now that I’ve been playing with hg queues for a day or so, I have come to understand that they can cover several common git tasks that appear to be missing from hg, including stashing, rebase -i, and similar. The key takeaway is you don’t commit your queues until you are quite certain you want them to become permanent history.
I haven’t yet figured out just when to choose hg queues over hg bookmarks, but a good read for getting used to hg bookmarks can be found here.
I strongly recommend enabling the hgk extension Just add the following to your ~/.hgrc. This will enable an
hg view command that is more similar to
gitk than it should be, considering the basic differences between branches in the two systems.
[extensions] hgk = mq = bookmarks =
(The second line is for enabling hg queues and third enables bookmarks.)
Overall, I suspect that I will always prefer git to hg. However, unlike subversion, I think Mercurial does supply me with tools I need to work effectively. Different tools from git, but effective nonetheless.
One beef I have with both git and Mercurial is that they violate the “one best way to do things” principle which makes learning, communicating about, and deciding how to use them more complicated than it needs to be.