Engineer in Tokyo

Mercurial and named branches and hgweb

Mercurial is a nice distributed SCM system written in python which I have been using at work and at on oss projects for a little while now. Mercurial allows three types of branching, cloning, named branches, and local branches. Each of these has it's uses but I have only really used cloning and named branches in my own development.

Cloning simply allows you to create a new branch of a repository by creating a copy of it. Simple. You make a copy of the repo, make changes in that copy, and you can merge the changes back into the original branch using push or merge changes in the original into your copy using pull. This is by far the simplest way to do branching. Each branch is self contained and easily managed/copied/deleted (which may or may not be a good thing depending on how you see things).

Named branches are branches that live in the same repo. You can create a new branch make a commit, and switch back to the original branch all within the same repo. This is achieved using the branch command in mercurial. You can switch your branch like so:

hg branch mybranch

Here we just created a branch off of the current version and called it 'mybranch'. Now if we make a change and commit it this change will be marked as part of our new branch. This is kind of nice because we can switch between branches quickly and easily. Also, long lived branches can be split off within the same repo and merged easily using the merge command. You can switch between branches by updating your local repo with the following command:

hg update -C mybranch 

This command figures out what changes need to be removed and what needs to be added to get you to the HEAD of the another branch.

Unfortunately, this is where the good things about named branches end. Named branches live in the same repository so you can't selectively push or pull changes. So if you have a bunch of changes in your main branch that are ready for pushing to your shared repo, but you have a named branch full of changes that aren't ready to see the light of day, you can't selectively push the stuff in your main branch without pushing the stuff in your test branch. This is a big problem because it can clutter up your shared repo.

Also, the hgweb and hgwebdir cgi scripts that show you changes to your repository in a easy to understand way simply fail to break changes out by named branch. This was the biggest problem for me because I lost track of what changes I had put in what branch so I had trouble compiling all the changes I wanted to for a release. I really wanted to look at the web interface and see the changelog for a particular branch but the hgweb interface simply shows all changesets in chronological order regardless of what branch you clicked on. It also doesn't show what branch a change was commited to so it's impossible to find out where a particular change was commited without looking at the parent changeset and backtracking to where it was split off from the main branch (this is not reasonably achievable.

Named branches are also not deletable. Meaning once you figure out all of the downsides of using them your repository is already full of these named branches and you can't delete them. This also exasperates the push problem because you might push some changes in a test branch to a shared repo inadvertently but once you realize this the damage is already done because you can't delete the branch from the shared repo without backing out all of the changes you made, nor can you delete them from your local repo and then push, or selectively push only one named branch. Basically you're stuck with them forever.

This is probably why there has been talk on the Mercurial mailing list this month about fixing named branches and recommending that developers not use them until they are.