Mercurial merge technique
This page is a mirrored copy of an article originally posted on the (now sadly defunct) LShift blog; see the archive index here.
Thu, 19 June 2008
We’re using Mercurial here at LShift for much of our development work, now, and we’re finding it a great tool. We make heavy use of branches (”branch per bug”) for many projects, and this is also a pretty smooth experience. One issue that has come up is policy regarding merging the trunk (”default”) into any long-lived feature/bug branches: should you do it, or should you not?
My vote is that you should merge default into long-lived branches fairly regularly; otherwise, you have a big-bang, all-at-once nightmare of a merge looming ahead of you. If you do merge frequently, though, there’s one subtlety to be aware of: hg diff
is not history aware, so in order to get an accurate, focussed picture of all the changes that have been made on your long-lived branch, you need to do one of two things:
- either, merge default into your long-lived branch right before you merge the long-lived branch back into default, and run
hg diff
after that’s complete; or - (recommended) do a throw-away test-merge of the long-lived branch into default directly.
Imagine a history like this:
(2) (3) | | \ / V | (1)
… where (1) is an ancestral revision, (2) is the default branch, and (3) is the long-lived branch - let’s call it “foo”.
Given this history, running hg update -C default
(to make the working copy be the default branch, i.e. revision (2)) followed by hg diff foo
will give you a misleading diff - one that undoes the changes (1) to (2) before doing the changes from (1) to (3). This is almost certainly not what you want!
Instead, run a test merge, by hg update -C default
followed by hg merge foo
and then plain old hg diff
. Note that this modifies your working copy! You will need to revert (by hg update -C default
) if you decide the merge isn’t ready to be committed.
The output of hg diff
after the hg merge
shows a history-aware summary of the changes that the merge would introduce to your checked-out branch. It’s this history-awareness (”three-way merge”) that makes it so much superior to the history-unaware simple diff (”two-way merge”).