Forbidding multiple heads in a shared mercurial repository

; Date: Fri Oct 10 2008

Tags: Mercurial

One of the issues with correctly configuring a shared mercurial repository is to prevent there being multiple heads in the shared repository. Multiple heads? Does that sound like Zaphod Beeblebrox? Maybe, maybe not. In Mercurial (www.selenic.com) history can be a convoluted thing, just like in real life. The series of changes a team has in hand may end up at a place where there are multiple lines of history. A head revision is one which does not have any children, that is a head revision is one from which no further revisions have been made. There is always at least one head revision, that's the tip. But there may be multiple heads.

For many reasons it is bad practice for a shared repository to have multiple heads. Doing a push from a repository that contains multiple heads also makes the repository into which the push lands also have multiple heads.

The (www.selenic.com) merge command gets rid of multiple heads. And you can prune dead branches by pretending to be a virtual arborist. But for the shared repository it's better to avoid them in the first place.

One method is the following hgrc configuration

[hooks]
pretxnchangegroup.forbid_2heads = /path/to/forbid_2head.sh

The hook calls this shell script

% cat /path/to/forbid_2head.sh
#!/bin/bash
COUNT=`hg heads | grep "^changeset:" | wc -l` 
if [  "$COUNT" -ne "1" ] ; then
   echo "=========================================================="
   echo "Trying to push more than one head, try run "hg merge" before it"
   echo "=========================================================="
   exit 1
fi
exit 0

Earlier I recieved a comment saying the above script no longer works:

This script isn't working with recent Mercurial release (> 3.0). I prefer the following which also takes more cases in account:

#!/bin/bash
#--------------------------------------------------------------------------
# To forbid pushing multiple heads even by using hg push --new-branch
# You must put those lines into the hgrc of the repo desired
# [hooks]
# pretxnchangegroup.forbid_2heads = /path/to/forbid_2heads.sh
------------------------------------------------------------------------

NB_HEADS=`hg heads -t | grep "^changeset:" | wc -l`
IS_DEFAULT_BRANCH=`hg heads -t | grep "^branch:" | wc -l`
if [ "$NB_HEADS" -ne "1" ] || [ "$IS_DEFAULT_BRANCH" -ne "0" ]; then
echo "===================================================================="
echo "Trying to push more than one head, try run "hg merge" before pushing"
echo "===================================================================="
exit 1
fi
exit 0

About the Author(s)

(davidherron.com) David Herron : David Herron is a writer and software engineer focusing on the wise use of technology. He is especially interested in clean energy technologies like solar power, wind power, and electric cars. David worked for nearly 30 years in Silicon Valley on software ranging from electronic mail systems, to video streaming, to the Java programming language, and has published several books on Node.js programming and electric vehicles.