Mercurial Branches

June 25, 2010

I was looking for a way of storing different streams of development when working with Mercurial. We have developers that want to start work on something, then branch off and fix a bug before returning to what they were doing before. We used to use CVS, and so people are used to just committing the files they've changed and ignoring their new development - this doesn't work well with the mercurial pull/merge/commit process for getting other's work from a remote repository as that needs a clean repository with everything mercurial knows about committed.

I've settled on using named branches, but you have to be careful when pushing that you only push the correct branch to the remote repository. Each mercurial repository puts everything in a branch called default, but you can create further branches as required.

Theory

To create a new branch use:

hg branch new

where new is the new branch's name. This marks the working directory as being for the new branch. If you list existing branches at this point, using hg branches you won't see the new branch as you haven't committed it yet. However, hg branch will show that you are working in a branch called new.

You can switch back to different branches using

hg update branch_name

where branch_name is the branch you want to switch to, or default for the default branch. You will need to commit any local changes before doing this.

Pushing

When it comes time to pull updates from the central repository and push your changes back, you need to make sure you don't push your local branches too. If you attempt to do a plain hg push you will get an error:

abort: push creates new remote branch 'new'!

To push only a particular branch, simply pass the branch name to the push command as a revision:

hg push -r default /other/repos

This command will push the latest changes on the default branch. Our central repository only has one branch, the default, so if we want to push changes we have to merge them into your local default branch first.

This suggests that it is sensible to do speculative development on named branches and keep the default branch for quick bug fixes. When you are happy with the speculative development, merge it into the default branch and then push from there.

hg update -C default
hg merge new
hg commit

Day To Day Working

Lets say you have never used branching before, and you have done lots of speculative changes to the code base in your local repository. Then an urgent bug comes in that you need to look at. What's an easy way to deal with this?

$ hg status
? testing.tst
? thisisanewfile.txt

This shows I have two new files in my repository. These are my speculative development. I want to keep this, but they're not ready to be pushed back to the main repository yet.

What we need is a new branch with the speculative development in, so lets create it:

$ hg branch testing
marked working directory as branch testing
$ hg addremove
adding testing.tst  
adding thisisanewfile.txt
$ hg commit
$ hg branch
testing

We're still in the testing branch here, we now need to switch back to the default

$ hg update -r default
0 files updated, 0 files merged, 2 files removed, 0 files unresolved

You are now free to work on your local changes without your speculative development getting in the way. When you have done, commit and push your important bugfix. You can now switch back to the branch to carry on working:

hg update -r testing

When your speculative work is done, merge the branch back into the default:

$ hg update -r default
0 files updated, 0 files merged, 2 files removed, 0 files unresolved
$ hg merge testing
2 files updated, 0 files merged, 0 files removed, 0 files unresolved
$ hg commit

Future

Mercurial 1.5.2 has a -b flag, which limits the push, pull, clone, incoming and outgoing commands to just the current branch. You need to specify the branch name following the -b, but a full stop is shortcut for the current branch:

hg push -b .

References

Tags: mercurial hg merge