How the Mercurial project itself manages branched development
- What not to do
- The default branch
- Release branches
- Applying bugfixes
- See also
There are many possible workflows for handling branched development in Mercurial, with combinations of multiple repositories, named branches, bookmarks, etc. This page describes the scheme the Mercurial community itself uses, which has several advantages. The basic model is:
- development primarily occurs in the default branch
- bugfixes are made in one or more release branches
- release branches are regularly merged 'forward' in time to propagate fixes
2. What not to do
Some common mistakes for people coming from other systems:
2.1. Don't use a name other than default for your main development branch
Mercurial's main branch is called "default" and is analogous to "trunk" in SVN, "HEAD" in CVS, and "master" in Git. If you try to use some other name for your "main" branch, users will get a more or less random branch when they clone and commit things in the wrong place, which is generally undesirable.
2.2. Don't treat branch names as disposable
If you're coming from Git, you may be used to the idea that branch names are disposable. Mercurial's model is more traditional: branch names are a permanent part of each commit and allow identifying on which branch each commit was introduced. Thus you will want to give some thought to your branch names so that you don't pollute the branch namespace.
Also, if you attempt to use a branch per bugfix, you may eventually run into performance issues. Mercurial is designed to work well with hundreds of branches. It still works quite well with ten thousand branches, but some commands might show noticeable overhead which you will only see after your workflow already stabilized.
2.3. Don't use branch names that are the same as your tag names
If you have a branch named "1.0" and a tag named "1.0", you'll get surprising results when you try to check out "1.0". Pick a naming scheme for your branches that distinguishes them, eg "1.x", "1.0-dev", etc.
3. The default branch
This is where development of new features occurs. This is the branch that will be checked out by default when you clone. If you're starting from an empty repository, this is the branch you'll start in.
It is strongly recommended to do your primary development on the so-called 'default' branch, because it is the branch used by default in various commands such as clone.
4. Release branches
There are some minor differences based on how many release branches you intend to maintain.
4.1. One maintenance branch
If you only intend to maintain one major release at a time, you only need one release branch. The Mercurial project uses the name "stable". This branch is reused from release to release. To first create the branch, simply do something like the following between the time you start your release code freeze and the time you tag your release:
$ hg branch stable marked working directory as branch stable $ hg ci -m 'start code freeze for release 1.0'
For future releases, you simply merge the default branch into the existing release branch rather than creating a new one:
$ hg update stable 44 files updated, 0 files merged, 1 files removed, 0 files unresolved $ hg merge default 40 files updated, 0 files merged, 2 files removed, 0 files unresolved (branch merge, don't forget to commit) $ hg ci -m 'start code freeze for release 1.1'
4.2. Multiple maintenance branches
If you intend to maintain multiple major releases in parallel, you will want one branch per major release. Choose a consistent naming scheme like 'release-1.0' that corresponds to releases tagged '1.0', '1.0.1', etc. For each release you should open your new branch when you enter your release code freeze:
$ hg branch release-1.0 marked working directory as branch release-1.0 $ hg ci -m 'start code freeze for release 1.0'
We suggest moving to a release branch when you enter code freeze so that it's always clear what the rules are for committing based on the branch name.
5. Applying bugfixes
5.1. Where to apply fixes
Bug fixes should always be committed first to the earliest maintained release branch they apply to. This will allow you to get maximum advantage out of Mercurial's merge intelligence.
After one or more fixes have been applied to a release branch, you should regularly merge that branch 'forward' in time into either the next more recent release branch or the development branch. This will bring all the changes (ie your fixes) made on the earlier branch since the last merge into the newer branch. Repeat this process until you've merged the latest release into the development branch. This process is known as 'forward porting'.
Example one (single release branch):
- Alice finds a bug in the latest release
- Alice checks out the 'stable' branch
- Alice develops, tests, and commits a fix
- Alice checks out the default branch
- Alice merges with the stable branch, tests again, and commits
Example two (multiple release branches):
- Bob finds a bug in version 1.3.2
- Branches 1.1 through 1.4 are still maintained
- Bob finds the bug is present in 1.2.x but not 1.1.x
- Bob checks out the 'release-1.2' branch
- Bob develops, tests, and commits a fix
- Bob checks out 'release-1.3', merges with 'release-1.2', tests, and commits
- Bob checks out 'release-1.4', merges with 'release-1.3', tests, and commits
- Bob checks out 'default', merges with 'release-1.4', tests, and commits
It is not necessary to merge after every fix, but merging regularly will reduce the number of merge conflicts and keep your branches more current. When forward-porting, most merges should be automatic.
5.3. Backporting fixes
Do not try merging the default branch into a release branch to backport a bugfix as it will also merge in all new features!
Occasionally, fixes are committed on the development branch before issues are discovered on the release branches. In this case, you'll need to first 'backport' your change. To do that use the graft command that will utilize the merge machinery and your normal merge tool in case of conflicts.
A more keep-it-simple and error prone approach is to use patches:
$ hg export 23485 > fix.patch $ hg up release-1.1 44 files updated, 0 files merged, 1 files removed, 0 files unresolved $ hg import fix.patch applying fix.patch
Backporting a patch is generally not as easy as forward-porting, due to the likelihood of new fixes being dependent on new features. Thus, you may need to handle some patch rejects when backporting.
Now you'll have a duplicate fix on your release-1.1 branch and you can forward-port it to your other release branches as before.