I've been using git for some time now on Windows (with msysGit) and I like the idea of distributed source control. Just recently I've been looking at Mercurial (hg) and it looks interesting. However, I can't wrap my head around the differences between hg and git.
Has anyone made a side-by-side comparison between git and hg? I'm interested to know what differs hg and git without having to jump into a fanboy discussion.
There is a great and exhaustive comparison tables and charts on git, Mercurial and Bazaar over at InfoQ's guide about DVCS.
If I understand them correctly (and I'm far from an expert on each) they fundamentally each have a different philosophy. I first used mercurial for 9 months. Now I've used git for 6.
hg is version control software. It's main goal is to track versions of a piece of software.
git is a time based file system. It's goal is to add another dimension to a file system. Most have files and folders, git adds time. That it happens to work awesome as a VCS is a byproduct of its design.
In hg, there's a history of the entire project it's always trying to maintain. By default I believe hg wants all changes to all objects by all users when pushing and pulling.
In git there's just a pool of objects and these tracking files (branches/heads) that determine which set of those objects represent the tree of files in a particular state. When pushing or pulling git only sends the objects needed for the the particular branches you are pushing or pulling, which is a small subset of all objects.
As far as git is concerned there is no "1 project". You could have 50 projects all in the same repo and git wouldn't care. Each one could be managed separately in the same repo and live fine.
Hg's concept of branches is branches off the main project or branches off branches etc. Git has no such concept. A branch in git is just a state of the tree, everything is a branch in git. Which branch is official, current, or newest has no meaning in git.
I don't know if that made any sense. If I could draw pictures hg might look like this where each commit is a
o
A tree with a single root and branches coming off of it. While git can do that and often people use it that way that's not enforced. A git picture, if there is such a thing, could easily look like this
In fact in some ways it doesn't even make sense to show branches in git.
One thing that is very confusing for the discussion, git and mercurial both have something called a "branch" but they are not remotely the same things. A branch in mercurial comes about when there are conflicts between different repos. A branch in git is apparently similar to a clone in hg. But a clone, while it might give similar behavior is most definitely not the same. Consider me trying these in git vs hg using the chromium repo which is rather large.
And now in hg using clone
Both of those are hot runs. Ie, I ran them twice and this is the second run. hg clone is the actually the same as git-new-workdir. Both of those make an entirely new working dir almost as though you had typed
cp -r project project-clone
. That's not the same as making a new branch in git. It's far more heavy weight. If there is true equivalent of git's branching in hg I don't know what it is.I understand at some level hg and git might be able to do similar things. If so then there is a still a huge difference in the workflow they lead you to. In git, the typical workflow is to create a branch for every feature.
That just created 3 branches, each based off a branch called master. (I'm sure there's some way in git to make those 1 line each instead of 2)
Now to work on one I just do
and start working. Commit things, etc. Switching between branches even in a project as big as chrome is nearly instantaneous. I actually don't know how to do that in hg. It's not part of any tutorials I've read.
One other big difference. Git's stage.
Git has this idea of a stage. You can think of it as a hidden folder. When you commit you only commit what's on the stage, not the changes in your working tree. That might sound strange. If you want to commit all the changes in your working tree you'd do
git commit -a
which adds all the modified files to the stage and then commits them.What's the point of the stage then? You can easily separate your commits. Imagine you edited joypad.cpp and gamesave.cpp and you want to commit them separately
Git even has commands to decide which particular lines in the same file you want to copy to the stage so you can split up those commits separately as well. Why would you want to do that? Because as separate commits others can pull only the ones they want or if there was an issue they can revert just the commit that had the issue.
Some people think that VCS systems have to be complicated. They encourage inventing terms and concepts on the field. They would probably think that numerous PhDs on the subject would be interesting. Among those are probably the ones that designed Git.
Mercurial is designed with a different mentality. Developers should not care much about VCS, and they should instead spend their time on their main function: software engineering. Mercurial allows users to use and happily abuse the system without letting them make any non-recoverable mistakes.
Any professional tool must come with a clearly designed and intuitive CLI. Mercurial users can do most of the work by issuing simple commands without any strange options. In Git double dash, crazy options are the norm. Mercurial has a substantial advantage if you are a CLI person (and to be honest, any self-respecting Software Engineer should be).
To give an example, suppose you do a commit by mistake. You forgot to edit some files. To undo you action in Mercurial you simply type:
$ hg rollback
You then get a message that the system undos your last transaction.
In Git you have to type:
$ git reset --soft HEAD^
So ok suppose you have an idea what reset is about. But in addition you have to know what "--soft" and "--hard" resets are (any intuitive guesses?). Oh and of course don't forget the '^' character in the end! (now what in Ritchie's name is that...)
Mercurial's integration with 3rd party tools like kdiff3 and meld is much better as well. Generate your patches merge your branches without much fuss. Mercurial also includes a simple http server that you activate by typing
hg serve
And let others browse your repository.
The bottom line is, Git does what Mercurial does, in a much more complicated way and with a far inferior CLI. Use Git if you want to turn the VCS of your project into a scientific-research field. Use Mercurial if you want to get the VCS job done without caring much about it, and focus on your real tasks.
The big difference is on Windows. Mercurial is supported natively, Git isn't. You can get very similar hosting to github.com with bitbucket.org (actually even better as you get a free private repository). I was using msysGit for a while but moved to Mercurial and been very happy with it.
If you are a Windows developer looking for basic disconnected revision control, go with Hg. I found Git to be incomprehensible while Hg was simple and well integrated with the Windows shell. I downloaded Hg and followed this tutorial (hginit.com) - ten minutes later I had a local repo and was back to work on my project.
If you are interested in a performance comparison of Mercurial and Git have a look at this article. The conclusion is: