Git for longtime Mercurial users

Tomasz Wróbel
4 min readAug 24, 2016

--

TL;DR: Git’s and Mercurial’s vocabularies have a lot of false friends.

When learning Git I wish I could forget everything I know about Mercurial, even though they’re so similar (especially in comparison to other VCS’es). Really. Learning Git would be much easier then. That’s because most of the resources on the web are targeted at people with no previous exposure to distrubuted VCS’es. They try to patiently transition you from SVN to a distributed VCS like Git, which is good & understandable, because it’s indeed a huge step for a lot of readers. But to someone familiar to an other DVCS like Mercurial, going through one of these tutorials often feels like a waste of time. That’s why I often resorted to a succint resource, adequately named Git Hg Rosetta Stone. Nice, but obviously at some point it’s not enough.

Moreover, most Git learning resources on the web not only feel like a waste of time for a Mercurial user, they might even be confusing, if you happen to be one! And you often end up with your questions unanswered. I think it would be really great for these tutorials to mind where the reader is comming from, be it SVN, Hg or some who’s been just emailing tarballs and patches. A side box titled “For an Hg user” would often help a lot.

A digression: Maybe separation of concerns could help both producers & consumers of technical prose. Then users with different backgrounds would know better where to jump in. After all, a newcomer to Git is learning at least 3 deeply related, but separable ideas: basic version control, secondly distributed version control and finally Git’s specific vocabulary and quirks.

Disclaimer and a polite request to you

So here’s my little attempt to make it easier for you, as I go through the process myself. Please note I’m learning Git myself at the moment, so I might be wrong on some things, or just not entirely right. I’d be more than happy if you correct me. I’d like to refine this article over time.

DVCS vocabulary’s false friends

First you have to learn that some concepts mean a totally different thing! With these differences in mind it should be a lot easier to digest other resources on the web.

  • Branches. Fortunately, these concepts are used to accomplish a similar goal. But if you assume they’re the same, soon you’ll end up in trouble.
    In Git, branch is just a pointer to a single commit. That’s it. This pointer just happens to move forward as you create subsequent commits while being on this branch (“being on this branch” is also a different concept in these systems, more on that below).
    In Mercurial, a branch (specifically a “named branch”) is a whole line of commits, starting from the one where you diverged from the original one. Moreover, in Hg a branch might be divergent itself. All these divergent lines are called “unnamed (implicit) branches”. While being on any of them you’re still rightfully on your named branch. This state is often temporary, as it’s often a result of people collaborating at the same time on one branch. You just do “hg merge” (without params) and the branch is straight again.
    Moreover, in Mercurial branches are global & forever. If your branch has a certain name in your repo, it cannot have a different one somewhere else — something which doesn’t work that way in Git. In Mercurial you have bookmarks, which are local. I won’t elaborate on that right now, maybe later.
  • Being on a branch. As I wrote above, these concepts also differ.
    In Git, it means you’re on the single commit pointed by that branch. Not only that, you have to explicitly checkout this branch, to be on that branch. If you checkout a single commit that happens to be pointed by that branch, you won’t actually be on that branch.
    In Mercurial, if your working directory is based on any of the commits (doesn’t have to be the newest one) of in the branch history, you “are on this branch”, no matter if you checked out via “hg up” to a certain branch name, or a specific commit id.
  • Head. This means a totally different thing here and there.
    In Git, HEAD is where you’re currently at. In Hg you’d call that “working directory parent”. HEAD can point to a commit or a branch.
    In Mercurial, in turn, head is any commit without children. That’s it.
  • Merging.
    In Hg merge is always getting two lines of development (two commits) together.
    In Git as well, but the process of “fast-forwarding” is also called a merge, whereas in Hg you don’t have to to this kind of thing.

Scary expressions

Some scary expressions demystified, to calm you down when you see them on your terminal:

  • Git’s “detached head”. Don’t worry, it just means you’re not on a branch. Either you’re not on the newest commit, or you are on the newest one, but you haven’t checked it out via not checked out explictly mentioning branch name. Nothing broke, you didn’t break anything.
  • Hg’s “multiple heads”. Again, don’t worry, your working dir didn’t split in two. Somebody’s just been working alongside, just “hg merge”, and it’s all fine again.

Rosetta stone additions

Here’s just a list of my additions to the aforementioned Git Hg Rosetta Stone:

  • get current commit id
# hg
hg parent
# note: hg will return two ids if you’re doing a merge)
# if you need literally the same (no additional data)
hg --template "{node}\n"
# git
git rev-parse HEAD
  • show the diff introduced by a certain commit
# hg
hg diff -c abcdef
# git
git diff abcdef^!
# alternatively (comes with additional commit data)
git show abcdef

Disclaimer again, ICYMI :)

That’s just scratching the surface, hopefully there’s more to come. As I said before, I’m going through the learning process myself at the moment, so this might be not entirely correct. I actually published this with the intention of letting someone verify my understanding. Please don’t hesitate to do it! :) Thank you for reading.

This blog post’s TODOs:

  • git pull vs hg pull
  • git push vs hg push
  • tracking branches

--

--