Mercurial branching, main and stable, a possible workflow

Published on 2009-10-14.

Software projects, whether small or big, often needs to go trough periodic official releases. Often you need to release a stable branch of a project while at the same time development continues on the main branch. This small tutorial is about how this can be done using the Mercurial revision control system.

Creating a main and a stable branch

The stable branch of the project would only receive bug fixes, but not any new features, as new features needs some testing before they can be termed as stable. Once a release cycle has reached a new point, a new stable branch is made from the main branch, and again the stable branch would only receive bug fixes while new features are developed on the main branch. You might even consider supporting the old stable branch with bug fixes or security fixes for a specific time period.

Mercurial is great at managing several different branches from the same project. Each branch can live in its own directory (but doesn't have too), and you can merge bug fixing code from one project unto the other.

Since branches are separated and live in their own directories (at least in this work flow example), changes in one will never effect the other unless you merge changes from one branch to the other. This can be a great way to keep things separated.

This is an example of how this might work.

$ mkdir my_project
$ cd my_project
$ hg init main
$ cd main
$ hg branch main
$ touch first_file.txt
$ hg add
$ hg commit -m "We have reached a release cycle!"
$ hg tag v1.0

Please notice that I have chosen to name the branch 'main', using the hg branch main command, this is not needed (more on this in the end).

It's now time to create a stable branch from the main branch.

$ cd .. (back to my_project)
$ hg clone main stable
$ cd stable
$ hg log

changeset:1:f92379326e0f
tag:tip
user:Foo Bar <foo@bar.com>
date:Wed Oct 14 00:37:45 2009 +0200
summary:Added tag v1.0 for changeset 5e4dfb526284
changeset:0:5e4dfb526284
tag:v1.0
user:Foo Bar <foo@bar.com>
date:Wed Oct 14 00:37:42 2009 +0200
summary:We have reached a release cycle

$ hg branch stable
$ hg commit -m "Stable branch has been created."
$ hg log

changeset:2:f16514dfb2a5
branch:stable
tag:tip
user:Foo Bar <foo@bar.com>
date:Wed Oct 14 00:46:29 2009 +0200
summary:Stable branch has been created.
changeset:1:f92379326e0f
tag:tip
user:Foo Bar <foo@bar.com>
date:Wed Oct 14 00:37:45 2009 +0200
summary:Added tag v1.0 for changeset 5e4dfb526284
changeset:0:5e4dfb526284
tag:v1.0
user:Foo Bar <foo@bar.com>
date:Wed Oct 14 00:37:42 2009 +0200
summary:We have reached a release cycle

As soon as we reached version 1.0 we cloned the main branch into a stable one, but we could have continued development on the main branch for a while longer, because as long as we remembered to tag our main branch, we can clone from that particular moment at any time.

If we imagine that development continued for a while before we actually branched the stable branch, we could clone the stable branch like this:

$ cd /home/foo/my_project
$ hg clone -rv1.0 main stable

Now, let's imagine that for the next six months we continue to release bug fixes and security fixes into the stable branch. We could do that by working directly inside our stable directory, but we could also do that by cloning our stable branch into a stable-fixing branch, make our changes, commit the changes, and then push the changes back into the stable branch.

$ hg clone stable stable-fixes
$ cd stable-fixes
$ echo "I am now fixing a bug." >> first_file.txt
$ hg commit -m "Bug fix."
$ hg push

pushing to /home/foo/my_project/stable
searching for changes
adding changeset
adding manifest
adding file changes
added 1 changesets with 1 changes to 1 files

If we want the changes to be reflected in the working copies of the files in the stable branch, we need to remember to update the repository that we just pushed to, otherwise the change will not be reflected in the working copies of the files. Mercurial will not update the files for us automatically, even though it is possible to achieve this using a hook.

In this particular case we are not going to work inside the stable branch, so I am not going to update it. Mercurial doesn't do anything by itself and until we push the changes back into the stable branch, nothing will happen with the stable branch. Naturally we want all our bug fixes and security fixes to show up in the main branch as well. We do not want to rewrite a bug fix in the main branch. Since the stable branch only contains bug fixes and security fixes, we can safely pull the changes made to the stable branch into the main branch, like this:

$ cd /home/foo/my_project/main
$ hg pull /home/foo/my_project/stable

pulling from /home/foo/my_project/stable
searching for changes
adding changeset
adding manifest
adding file changes
added 2 changes with 1 changes to 1 files
(run 'hg update' to get a working copy)

Since there is no requirement for two named branches to be merged, we need to explicitly tell Mercurial that we want those two branches to be merged.

If we had left the branches with the 'default' branch name, and not changed them into 'main' and 'stable' (which you also might decide to do - more on this in the end), Mercurial would have posted a merge message (if the files needed a merge). Because we haven't used the 'default' branch name, Mercurial doesn't post any merge message.

So inside the main branch we merge the changes that we pulled from the stable branch.

$ hg merge stable
(branch merge, don't forget to commit)
$ hg commit -m "Pulled in bug fixes from the stable branch."

A question may arise here: What if we discovered a bug in the main branch during development that we know also exist in the stable branch, is it possible to somehow isolate that bug fix and pull that into the stable branch from main?

The answer to the question would ordinarily be "no". The main branch would contain much more development than simple bug fixes, thus the code would have advanced with many changes since the release of the stable branch. It would not be possible to pull only a specific bug change into stable unless the code from which you are pulling, are identical to the one receiving except for the bug fix. The main branch will contain all the current changes and new features added to the code, and it would also contain all the bug fixes from the stable branch. Changes from the stable branch are going into the main branch, but not the other way around unless you do it manually by rewriting a bug fix from main into stable.

Naming branches

From the Mercurial documentation:

Mercurial branch names may be used for whatever reasons users want. However, a good rule of thumb is to use branch names sparingly and for rather longer lived concepts like "release branches" (rel-1, rel-2, etc) and rather not for short lived work of single developers. Some Mercurial users do not use branch names at all. And there is indeed no need to assign branch names in Mercurial. Some users find them helpful, some not. Establish and apply your local consensus.

In this tutorial I have used the branch names 'main' and 'stable' in order to show how branch naming might be used, but I personally prefer not to use branch names at all, and just focus on the names of the directories.