Much can be said about similarities between two popular, distributed version control systems: Git and Mercurial. For the most part, choosing between them can be a matter of taste. And because Git seems to have considerably more proponents in the Cool Kids camp, it doesn’t necessarily follow it’s a better option.
But I have found at least one specific and common scenario where Git clearly outshines Hg. Suppose you have coded yourself into a dead end: the feature you planned doesn’t pan out the way you wanted it; or you have some compatibility issues you cannot easily resolve; or you just need to escape the refactoring bathtub.
In any case, you just want to step back a few commits and pretend nothing happened, for now. The mishap might be useful later, though, so it’d be nice if we left it marked for the future.
In Git, this is easily done. You would start by creating a new branch that points to your dead end:
Afterwards, both my_feature
and __my_feature__dead_end__
refer to the same, head commit. We would then move the former a little back, sticking it to one of the earlier hashes. Let’s find a suitable target:
If it looks right, we can reset the my_feature
branch so it points to this specific commit:
Our final situation would then looks like this:
which is exactly what we wanted. Note how any further commits starting from the referent of my_feature
would fork at that point, diverging from development line which has lead us into dead end.
Why the same thing is not so easily done in Mercurial?… In general, this is mostly because of its one fundamental design decision: every commit belongs to one branch, forever and for always. Branch designation is actually part of the changeset’s metadata, just like the commit message or diff. Moving things around – like we did above – is therefore equivalent to changing history and requires tools that are capable of doing so, such as hg strip
.
There seems to be a nice debate on which model is actually better; some feel that Git branches aren’t very descriptive compared to Hg after you merge stuff. There’s this:
http://jhw.dreamwidth.org/1868.html
Yet, others still insist that yes, they still are:
http://felipec.wordpress.com/2012/05/26/no-mercurial-branches-are-still-not-better-than-git-ones-response-to-jhws-more-on-mercurial-vs-git-with-graphs/
It is a bit of a philosophical issue: on one hand it’s about what do you exactly mean by “branch”, and on the other is how much do you really care about preserving history of everything.
I don’t really know what you mean “descriptive after merge”. Branch pointer still stays where it was before, and commit history is preserved prior to it, so…
Good read and valid point indeed. when it comes to philosophy…
I used to be a big proponent of mercurial’s way of branches. My argument was “then I can easily find out what was the history of the branch, how it came into being and generally tons of useful info”. But after learning about git squashing and the way how branches/tags and especially rebases work in git + after rigorously using code review workflows and “branch per feature” I changed my mind.
If you really follow branch-per-feature + rebase + squash to one commit before final rebase, then git branches show it’s real power. After merge, you DON’T care any more what was the history of feature. You care about what changes are in the feature + you have the history of code reviews done for this feature (comments there are often important and good to refer to). This way you can see “big picture” in commits and dive into nitty-gritty details in reviews, but only if you really want. You can easily remove feature by reversing single commit.
What is really missing in both git and mercurial is lack of semantical knowledge about the language + ability to follow refactoring. That’s why PlasticSCM (http://www.plasticscm.com/) is a very interesting subject to follow. One thing that breaks the whole flow of “branch-per-feature” approach is exactly this. I will have to finally start my blog (I think about it for ages) and I believe this subject will be one of the first to cover :).
@up: Thanks for the points on rebasing & squashing. It really sounds like a good workflow.
And about PlasticSCM, I see it’s from the same folks that do http://www.semanticmerge.com/. I’ll be interesting when they start supporting more languages… and especially how they’ll tackle dynamic ones :)
Why does ‘Cool Kids camp’ leads to github.com ?