Why Hg branches are broken (or at least less useful)

In one picture:


In Hg, branches are metadata included in each changeset.  In the operation above, I created a branch, but that only marked the current directory with a branch name.  The branch won’t actually show up unless I make a commit.  In fact, if I checkout to another revision, it’s as if the “hg branch” command never happened.  When I list the branches, you won’t see this new branch name.  The name in the PS window just comes from the PowerShell-Hg extension being smart.

One implication is that our team has to make phantom commits for the branch to officially “show up”.  You start to see commits like “phantom commit” early on, then later they start saying “stupid commit”.  It’s the only way we could get a branch to show up locally and on the server.

In Git, a branch is nothing more than a pointer to a commit, and the commit itself carries no information about a branch name.  A much more flexible model in my experience.

This hit me today when I wanted to move a set of commits to a different branch, which turned out to be very difficult as the branch name was embedded in to the commit names.  Rebasing helped, except that the commits were already pushed to the server.  We wound up having to back out of the commits, even though these were on a different logical branch, simply because our build server got confused about these extra commits that were marked with the wrong branch name.

Perhaps Hg branches aren’t broken and this design is intentional.  But it’s annoying and less powerful and flexible than Git’s more simple model, of just a pointer to a commit.

Side note for the Git folks – I’ve also wasted 2 hours of my life on Git when my .git folder suddenly went empty – and not from me accidentally deleting anything.  Lost all my dangling topic branches on that one.

About Jimmy Bogard

I'm a technical architect with Headspring in Austin, TX. I focus on DDD, distributed systems, and any other acronym-centric design/architecture/methodology. I created AutoMapper and am a co-author of the ASP.NET MVC in Action books.
This entry was posted in Mercurial. Bookmark the permalink. Follow any comments here with the RSS feed for this post.
  • Dave

    Hi Jimmy,

    I’ve been meaning to post to one of your posts on Hg for a while now. We use Hg branches fairly extensively. You are right that a Git branch is a pointer to a commit whereas an Hg branch is a label on a changeset. I’m not sure that means that Git’s branches are ‘simpler’, just different.

    ‘Pointer to commit’ means ‘tag’ to me. The difference between ‘tag’ and ‘Git branch’ is then that the pointer automatically moves as you commit on top of it, and that you can sync the pointers across repos. Put like that, it doesn’t sound hard to do the same thing with local Hg tags although it’s not existing functionality and it’s not part of the core mindset of Hg.

    [Personal note: I found with Git's branches that keeping all the pointers in sync across multiple repos was painful. I had to keep re-reading the docs on refspecs and the system I had kind of worked for me but I never really felt that I 'got' it. I'm sure it's very powerful, mind.]

    We name our branches with issue numbers from the bug database, which means it’s easy to go back and work out why any given sequence of commits was made. If you put issue numbers in commit messages, you are labelling the commits ok but you have to do string manipulation to find them and it’s not automatic enough for me to remember to do every time. If you don’t label your commits with issue numbers at all, it is often tricky to see the big picture in a sequence of one-line changes, which encourages bigger commits, which is bad for bisection. How would you link changesets to issue numbers in Git? That’s a genuine question, I wouldn’t be surprised if it were possible, but don’t know how.

    I guess I’m saying that we don’t really have a problem that moveable, syncable, pointers to changesets would solve, but we did have a problem that Hg branches solve.

    Oh, and to move a sequence of commits from one branch to another in Hg, you can import them into the patch queue, pop them off, change branch, push them back, and they will magically now be labelled with the new branch name. Naturally this doesn’t help when the changesets are already out there, but that’s because Hg branches are not for the same things as Git branches and your workflow should probably reflect this.



  • Jeff


    Why don’t you try Bazaar instead? It has much better Windows support, more intuitive commands and excellent Subversion integration (if required). 2.2beta4 is the version I’m using and love it.

    Branching means creating a new directory, no internal branch es to switch between which can also mean confusion by having a dev commit to the wrong branch unintentially, etc.

  • @Dave

    Tags aren’t quite like git branches, as the tag also “lives” with a commit. The closest thing is a bookmark, which is a named pointer to a commit (rather than a named commit, which is what an Hg branch is).

    We do use tags to identify versions, although we do this less and less with feature/dev/trunk branches.

    In Git, that would likely be a tag. You could use a branch (again, just a pointer to a commit, not a physical branching of code), but the typical use would be a tag.

  • @Jeff

    I think someone else suggested using different folders for branches. It’s basically the SVN model. I dunno, I kinda like being able to visualize the entire repository in one folder. It makes doing topic branches a lot easier at least.

  • Tom

    Why would you want to move the commits to a different branch?

    It seems like a bad idea to make Hg lie about the past. Merging the changes over seems like a better plan.

  • @Tom

    The problem is that the commits were:

    C1 (dev) <- C2 (dev) <- C3 (F1) <- C4 (F1)

    I had a topic branch on C1 and C2, then changed to a feature branch. I could not go back and change the branch name of C1 and C2. I wasn’t ready to merge the changes back, as the feature wasn’t done. I didn’t realize the issue until the feature branch was pushed, and by then, it’s too late, the cat’s out of the bag.

  • @bogardj

    Why are you guys using Mercurial?

  • ike

    hg branches are indeed different than git branches.
    Like you said in git it’s a pointer.

    In hg a bookmark resembles more the git branch.

    Since hg 1.6 you can push/pull bookmarks now too. However it’s a sperate process (not sure if this is always the case or only the first time)

  • Nice article! Great to see comparisons of Git vs. Hg.

    We worked with Hg Branches for about a day and then switched over to CLONING repositories, which has worked great. Check out: http://hginit.com/05.html

  • The one time I had a .git folder disappear was when the Makefile for what I was working on deleted it for me. That was very irritating, to say the least. Otherwise, the only thing I can imagine is if you used git-new-workdir and weren’t careful with it (there’s a reason it’s still in /contrib and not in the normal install), or if you had filesystem corruption (I have seen this).

  • Marcus Pope

    Hmm, sounds like you’d prefer to use hg bookmarks instead of named branches.  They behave much more like git branches. 

    But then why you’d create ghost commits just to have the branch show up in a repo is beyond me.  Why don’t you just create the branch when you have some code to actually branch?  There’s no conflict if multiple people create the branch locally and push, and I just don’t see the need to see this branch name on the server if the branch doesn’t contain any applicable code.

    The really nice part about named branches in hg is that the branch name appears in the commit log as part of the commit so you’ll know if that changeset exists on a given branch without any extra effort.

    • Anonymous

      I might try bookmarks again, but the last time I tried using them, it was a pain in the arse to try and build git-like workflows around them. It seemed that a lot of barriers were put up against performing operations (FF-merge, etc)

      It might be a preference thing, but having worked with git and Hg branches for a couple of years now, Hg branches are just a little too constraining for the workflows I like to use.