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 .