Hacking on GraphHopper - a Java road routing engine. Peter has posted 62 posts at DZone. You can read more from them at their website. View Full User Profile

Mercurial Will Beam You Into A Heaven of Merging

06.18.2010
| 5744 views |
  • submit to reddit

I never understood why mercurial should be so fantastic and why merging is so much easier with hg compared to subversion. This week changed my point of view.

In subversion I couldn’t keep in mind the command to copy a revision difference e.g. into the current trunk. I nearly always was forced to do a manual and error-prone merging. Now that I am using hg for some of my free time projects and even partially at work I get very comfortable with hg. Especially the fast and network independent commits are awesome when working with hg.

Then, this week, I read an article about merging and I started to understand how merging works (much easier) with hg.

Lets get started. Assume your users or your QA found an issue in your current release. In hg it is easy to fix such an issue.

  1. go back to the state where you want to fix that issue or stay at the tip:
    hg update -C <oldRevisionNumber>

    or a go there via a named branch:

    hg update -C releaseXY
  2. now create a named branch for the issue:
    hg branch issueXY

    optionally do:

    hg commit -m "start working on issueXY"
  3. NOW FIX THE ISSUE in the code and commit:
    hg commit -m "fixed issueXY"

    optionally add

    --close-branch
  4. Go back where you want to have the fixed code. Most of the time this will be ‘default’ (svn users known as ‘trunk’) but it also could be the releaseXY branch:
    hg update default
  5. Now do the actually merging
    hg merge issueXY

    In my case I had to merge manually 4 files, but for that kdiff3 poped up (you can change this application of course). So merging was really easy and done after 2 minutes! The fix where I changed over 25 files was easily applied.

  6. … and commit the merge:
    hg commit -m "merged fix of issueXY into development sources"

This is very straightforward and worked very well in practice! I would have never thought that merging could be that easy … until I did it myself. So, try it out! Only 6 steps into the heaven of mergurial!

Hints:

  • You can always go back to the issue via:
    hg update -C issueXY
  • Before commiting things check that you are on the correct branch:
    hg branch
  • Get all branches:
    hg branches
  • View 5 commits of the logs if glog does not work for you:
    hg log -l 5
  • The steps 4 until 6 could be applied to several branches, of course
From http://karussell.wordpress.com/2010/06/17/mercurial-will-beam-you-in-the-heaven-of-merging/
Published at DZone with permission of its author, Peter Karussell.

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)

Comments

Jose Noheda replied on Fri, 2010/06/18 - 6:41am

Certainly moving to one rev or another branch keeping the same "working copy" seems really really easy under hg. And the "brach for everything" concept is something I appreciate. Now the merge itself...I don't see any difference other than the syntax-sugar. Merging between branches is a complex process not because checking out a branch is difficult but because the diffs/patches probably won't match. If you end up manually merging those 25 files...

matt inger replied on Fri, 2010/06/18 - 8:05am

This is not very different from subversion at all, and it's all syntactic sugar. From what I can tell (and i'm no hg expert), the functionality is relatively the same, except that branches are formal entities in hg. In subversion, they are simply just a path with an interpreted meaning. For me the svn commands are very easy to remember, so it just boils down to what you're more comfortable with. Plus the svn book by redbean is fantastic, and goes over merging in detail, with example commands, etc...

Andrew McVeigh replied on Fri, 2010/06/18 - 8:58am in response to: matt inger

> the functionality is relatively the same, except that branches are formal entities in hg

 i think there are differences, although to be honest I'm more familiar with hg than svn.

in hg, the pre-eminent abstraction is the changeset, which groups a set of file changes.  each changeset can refer back to a single parent.  so, if 2 separate people check into a communal repository, where the common parent is changeset 56, say, they will create 2 separate (unnamed) branches.  it's not just syntactic sugar, it's a logical outcome of the changeset abstraction.

i find the changeset notion very intuitive in hg.

Peter Karussell replied on Fri, 2010/06/18 - 9:19am

> This is not very different from subversion at all, and it's all syntactic sugar.

I think for a programmer version control should be as easy as possible. With hg I can concentrate on merging, not on thinking about which revision numbers I need to do the merge. So, no. I don't think its syntactic sugar only. Please provide me the svn commands for the same example to prove me wrong.

Daniel Neugebauer replied on Fri, 2010/06/18 - 1:58pm

The named branch is unnecessary. You shouldn't use named branches for such short-time tasks as the names will stay in the repo forever (unless you rebase it which is rather uncommon in Mercurial and may result in incompatible changeset hashes AFAIR). If you create named branches they should have reappearing constant names like "stable", "maintenance" etc. - even better is to not use them at all but create clones instead as they are more flexible. Run hg serve and visit the branch overview of the web interface after closing the branch - your branch name still appears. Imagine 30-40 branches you named for short-time bugfixing tasks and try to separate them from 2 really used branches like "stable" and "maintenance".

Instead of creating branches explicitely, use a unnamed branch (that means: don't call hg branch at all; all other steps remain basically the same). Try it. :)

BTW, hg update -C erases any changes you may have had in your work copy. If you don't use -C it will create backup copies of any files replaced. Versioned files will be replaced nevertheless (as they are already versioned).

Peter Karussell replied on Fri, 2010/06/18 - 2:04pm

Thanks Daniel for the clarifications!!

Regarding the unnamed stuff: how would I then do the merge? How would I go back to the issue if it wasn't properly fixed?

Regarding the named branch: If I call --close-branch then the I do not see the created named branch in the branches list. Or what do you mean?

Do you have a nice tutorial or other resources which covers the things you mentioned?

Daniel Neugebauer replied on Fri, 2010/06/18 - 6:41pm in response to: Peter Karussell

You can go back by the revision number or changeset hash just the way you wrote it ("hg update" followed by the rev number/hash where you want to pick up) but it doesn't make much sense if you have to merge everything that happened since then (same with branches), so I would simply commit to a more recent revision than the one where I left off if it has been a while since then. You can also search the history by "hg log -k <keyword>", so if you use prefixed commit messages like "ISSUE123: ..." you could find changesets belonging to that issue almost as easy as using a branch. If a fix can be done in a few commits I wouldn't do an extra branch or clone but just commit the fix and note the issue number in the commit message. In large projects - or if you want to keep your patches separate - it seems to be more common to prepare patches addressing single issues by mq and then combine them into one changeset. You can also combine multiple changesets into one bundle that can be committed upstream as a single changeset. You can merge with any revision you like, see hg help merge.

By calling hg serve you are hosting the current repository on the network (unprotected); accessible at http://localhost:8000/ - that's hgweb, the same interface you can use for repository hosting on central servers. If you go to "branches" on that web interface it will display all branches, open and closed, without any way to distinguish between their state. That maybe an issue that could be fixed but it currently isn't (as of Mercurial 1.5).

I read http://hgbook.red-bean.com/ last year, which is a seemingly complete guide to all aspects of Mercurial. The online version has optional user comments for each paragraph where you can sometimes find some interesting discussion or advice (although the book itself contains a lot of it already). 

Since I started using Mercurial a year ago I noticed that it's more important to think about how you want to use a DVCS repository in advance (would be the same for git) than you would using a central VCS like SVN. It's not advisable to simply adopt some other's repository workflow without considering all aspects and possible alternatives.

Peter Karussell replied on Mon, 2010/06/21 - 7:34am

Thanks Daniel! I would like to 'update my knowledge' in a new post. Would you mind to give me your email or sth. (private msg does not work here at dzone!?), so that you can correct me if necessary and I can correctly acknowledge your ideas? peathal at yahoo dot de Regards, Peter.

Fabrizio Giudici replied on Mon, 2010/06/21 - 11:30am

Actually I don't see any "pollution" problem with named branches, since you can "close" them. Closing is just a flag, of course, but this means that they don't appear on a list. I don't see any problem of having them archived somewhere, just to eventually be able to recall what happened.

For instance, these are active named branches of a project of mine (mostly named on the JIRA issue they relates):

[Mistral:Projects/jrawio/src] fritz% hg branches
default                      956:c735e06060c0
2.0                          952:b5299fe1c439
3.0                          950:91c52089e89e
1.6                          756:616fce1a805d
fix-JRW-264                  754:fe4c22e3275e
fix-JRW-261                  717:176d50455e79
fix-JRW-257                  709:35434439c597
fix-jrw-246-1                640:cbf229d7afce
fix-JRW-120                  562:a82b7ed21b94
fix-JRW-6                    560:eb9031bec74c
fix-JRW-162-and-JRW-194      367:e75735d2055c

The above is just a filtered list of named branches. The totality of them can be seen here:

[Mistral:Projects/jrawio/src] fritz% hg branches --close
default                      956:c735e06060c0
2.0                          952:b5299fe1c439
3.0                          950:91c52089e89e
1.6                          756:616fce1a805d
fix-JRW-264                  754:fe4c22e3275e
fix-JRW-261                  717:176d50455e79
fix-JRW-257                  709:35434439c597
fix-jrw-246-1                640:cbf229d7afce
fix-JRW-120                  562:a82b7ed21b94
fix-JRW-6                    560:eb9031bec74c
fix-JRW-162-and-JRW-194      367:e75735d2055c
fix-JRW-276                  909:ce254969283b (closed)
fix-JRW-275                  892:f80b6551b76d (closed)
fix-JRW-236-1                683:9e216f85561e (closed)
fix-JRW-240-1                668:ff403f3cc946 (closed)
fix-JRW-230-1                660:e93885f2ae9b (closed)
fix-JRW-203-1                632:4ce962bd50dc (closed)
nef-fixes-1                  586:ab13ced986d3 (closed)
fix-JRW-187-1                408:1a0cbede4cb8 (closed)
src                          286:d9692def01a2 (closed)
 

Peter Karussell replied on Mon, 2010/06/21 - 3:43pm

Thanks Fabrizio for the additional clarification! :-)

So, you are using named branches per issue in this project?

Fabrizio Giudici replied on Tue, 2010/06/22 - 11:05am

It depends. Clearly, on the cited project I'm doing that. It got stable enough to minimize the burden of merge, while other projects I'm working on are still in "violent" change mode (due to refactorings) either because they are very young, or because they're still going through a general reorganization (e.g. conversion from Ant to Maven). In this case, I fear that the very fact of having a merge that could last more than one-two days create problems because in the meantime many things have changed in the default branch.

Theoretically, when everything gets reasonably stable, I should go to the named branch mode for most of them.

Peter Karussell replied on Mon, 2010/07/12 - 4:48am

Check out the post

http://karussell.wordpress.com/2010/06/22/heaven-of-mergurial/

where I show the other merging-procedures (hopefully all is correct)

Rehman Khan replied on Sat, 2012/02/25 - 4:25am

I choose hg over git simply because it feels a bit better and NetBeans support is far better. I already tried git but only for a small project where I didn’t use merging so I think git is great, too

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.