Those who followed Is Git really better than X will enjoy this interesting article by Armin Ronacher on the finer distinctions between Git and Mercurial’s branching. (via brainsik)
Most of Scott Chacon’s points in Why Git is Better than X are spot-on. The page could even be renamed “Why distributed version control systems are better than Subversion and Perforce,” since those two are the clear losers. (And yes, Bazaar is so slow I think it deserves to be listed twice in the speed section.)
I’ve used each of Git, Mercurial, and Bazaar for several months in medium sized teams; I’ve done quite a bit of branching and merging in Mercurial and Bazaar, and a fair amount in Git. Based on that experience, I am compelled to disagree here with a few of the points, specifically with regards to Mercurial.
Cheap local branching
Chacon argues that only Git offers cheap local branching, but Mercurial allows exactly the same work-flows that he outlines, and they are just as easy. Chacon claims that Git’s branching model is different:
Git will allow you to have multiple local branches that can be entirely independent of each other…
This isn’t quite correct. The real difference between Git’s branching model and the others is that Git does not assume a one-to-one relationship between a logical branch and a directory on the file-system. In Git, you can have a single directory on the file-system and switch between different branches with the
git checkout command without changing directories.
Mercurial (and Bazaar) enforce default to1 a one-to-one relationship between a logical branch and directory on the file-system. You can, however, use the
hg clone command to make a new, “entirely independent,” branch. You can clone a local directory, a remote directory over SSH, or a remote Mercurial repository. Cloning a repository that’s on the local file-system is the way to create cheap local branches in Mercurial. Mercurial will even create hard links to save disk space and time.
For example, in Git, you make a cheap local branch with:
git branch featurebranch
git checkout featurebranch
And in Mercurial, you make a cheap local branch with:
hg clone master featurebranch
In Git, you switch between branches with
git checkout branchname. In Mercurial, since branches are in a one-to-one correspondence with directories, you switch between branches with
In Git, you pull changes from a local branch with
git merge branchname. In Mercurial, you pull changes into from a local branch with
hg pull -u ../branchname.
Chacon’s four example work-flows using cheap local branches are not only completely possible in Mercurial, they are just as trivial as they are in Git. (The first three are even equally trivial in Bazaar; I’m not sure about the last one in Bazaar, though.)
You can find ways to do some of this with other systems, but the work involved is much more difficult and error-prone.
Reasonable people might also disagree about the intuitiveness of the specific commands, but creating, updating, merging, and deleting them in Mercurial are one or two commands in the shell, just like in Git. None of these tasks are more difficult or more error-prone in Mercurial.
Chacon also says:
when you push to a remote repository, you do not have to push all of your branches. You can only share one of your branches and not all of them.
This is a little misleading. In Mercurial, since there’s usually a one-to-one correspondence between branches and local directories, and since you can’t be in two directories at once, you’re usually only pushing a single branch. In Mercurial, you generally don’t have to think about which branch you’re pushing, or whether you’re pushing other branches that shouldn’t be pushed, because you generally only ever push one branch at a time. I would actually turn this argument around, and claim that Git’s default of keeping multiple logical branches in a single directory forces you to worry about which branches you’re pushing, and actually makes cheap local branches harder and more error-prone in Git than in Mercurial.
Reasonable people might disagree about the intuitiveness of a branching model which does or does not assume default to a one-to-one relationship between logical branches and local directories, but that’s not why cheap local branches are so powerful in Git. Rather, it’s the ability to clone and merge between repositories locally that allows cheap local branches, and it’s just as easy in Mercurial as in Git, and nearly as easy in Bazaar.
GitHub is unarguably the biggest community around any distributed version control system. But Chacon goes too far when he says:
This type of community is simply not available with any of the other SCMs.
BitBucket may not be as big as GitHub, but it’s a “socially-targeted” community where Mercurial users can “fork and contribute” to other Mercurial projects. It might not have as many projects or contributors as GitHub, but a sheer difference in size doesn’t translate to “simply not available.”
Bazaar’s not listed as inferior to Git on this point, I assume because of Launchpad. If Launchpad counts, why not BitBucket?
I’d also be interested to see usage numbers comparing GitHub and everyone’s favorite open-source community brontosaurus, SourceForge. Has GitHub surpassed them in projects or users or commits or downloads?
Minor haggling points
I also disagree with Chacon about the benefits of the staging area or index, but that’s purely a matter of personal preference. I never wanted anything like the staging area before I started using Git, and I don’t miss it now when I’m using Mercurial. If anything, the extra concept of a staging area makes Git slightly harder to learn; newbies coming from any other version control system have to be taught about the
-a option to
git commit right away, or else they wonder why their changes aren’t getting committed.
In the “Easy to Learn” section, Chacon highlights the
add commands in both Mercurial and Git, indicating that they are the same; but they are pretty different. In Mercurial,
add schedules previously un-tracked files to be tracked. In Git,
add adds changes in a current file to the staging area, or index, including, but not limited to, previously un-tracked files. That section is also missing Mercurial’s
mv command. Other potentially confusing differences include Git’s
revert, which corresponds to Mercurial’s
backout; and Mercurial’s
revert, which can be duplicated using Git’s
- Update: Thanks to David Wolever, who points out that
hg bookmarkcan be used to have more than one branch per directory in Mercurial. I didn’t even know about these commands when I first wrote this post. But I think my central point still holds; creating cheap local branches in Mercurial is just as easy as in Git. [↩]
…doesn’t mean the interface has to suck: ways in which git makes the opposite of sense.
This is an excellent Illustrated Introduction to Distributed Version Control.
But once you accept this model of having your sandbox under version control, a lot of the pain (and fear) of dealing with branches evaporates. Passing around changesets and patches becomes normal and logical.
I don’t hear anything about arch, monotone, BitKeeper, codeville, SVK or darcs from anywhere except the nerdiest of SCM nerds.
I’m not a SCM nerd. I’ve never used Git, mostly because I’ve never had the time to check it out. But I am a Codeville user, and here are my thoughts about it.