I’m a recent convert to the ways of the DVCS and my chosen flavour is Mercurial. There is tons of documentation out there but I couldn’t find a “Quick Start for Half Wits to Branching” that appealed to my simple nature. So I thought I’d have a go at writing one based around my current workflow.
Mercurial has several ways to work with branches but I find named branches best suit my feature branch approach to using SCM. There is an excellent guide to all the types with their advantages and disadvantages, here.
I’m going to assume you’re familiar with basic push, pull, and commits.
Creating and Moving Between Named Branches
To create a new named branch you simply enter:
hg branch "<branch name>"
This will mark the current working revision with the branch name you specified but it will not be part of your repository till you next do a commit. When committing it will create the branch and add all the changes since your last commit. This is quite a big gotcha, if you want to any changes to be committed on the old branch before moving to the new one you must do a commit before branching.
Finding out the name of the branch you are on is be done by entering:
You can list all of the branches that are currently open by using:
This outputs a list of branches with the changeset number that is the head of the branch, for example:
To move between the branches you do an update with the name of the branch in. This will fail if you have any uncommitted changes but you can force it to update and lose any the changes by using –C.
This will just move between branches:
hg up "<branch name>"
This moves between branches losing any changes:
hg up -C "<branch name>"
The following examples ties a few of these together and shows how creating a branch without committing first moves any recent changes into the new branch.
Merging two branches is done by updating to the branch you want to be the target then merge in the changes from the source branch by specifying its name. For example if you wanted to merge the latest edits from default into the feature branch named “Feature X” you would do:
hg up "Feature X" hg merge “default”
It will attempt to merge the changes without any user intervention but if it can’t it will ask the user to do it. On Windows, KDiff3 is installed along with Mercuiral and is used to merge changes. Again none of these changes will be saved until you commit. If you regularly work on a feature branch while others update the default branch, I would strongly urge you regularly merge updates from the default branch to stop you having one almighty nightmare merge at the end.
Merging offers a preview option by passing –p to the merge command. This allows you to see upfront if there will be any conflicts or problems, I find this quite useful when assessing how long a merge will take.
Mercurial by default pushes your whole repository, including all your local branches, to the remote repository. It works exactly the same if the branch (or branches) exists in the remote repository. If they don’t it will fail and you can use the –f option when pushing to force it to create the branches on the remote repository.
But sometimes you want to just push changes on the current branch, leaving the others behind. I’ve recently discovered a great tip for doing this, you can just push the current revision with its associated history and parent by using:
hg push --rev .
The ‘.’ is a shortcut for the most recent changeset on the branch and it will only push changes on that branch. This, of course, means that the branch must exist or be created on the parent.
Mercurial doesn’t support the deleting of branches (at least that I’ve come across) but you can close a branch. Closing a branch is done by selecting the branch and doing a commit with the close flag, for example:
hg up "<branch to close>" hg commit --close-branch
This marks the branch as inactive and stops it appearing when you list the branches using hg branches. It is possible to still see all branches including closed ones using the this command
hg branches -c
One major downside is, closing a branch does not prevent it from being pushed. This means you will still have to create it on the server or just push the current changeset as shown above.