Full-service Internet Marketing & Web Development
Recent Posts

Sponsors
![]() |
Mercurial Hook: Forbid 2 headsMike Peters, 12-05-2009 |
The Mercurial version control system offers a powerful mechanism to let you perform automated actions in response to events that occur in a repository. In some cases, you can even control Mercurial's response to those events. No comments
The name Mercurial uses for one of these actions is a hook (aka trigger).
One of the most popular hooks is the ability to reject multiple heads.
What are multiple heads?
Multiple heads are a case where the code repository contains changes from two (or more) developers, that haven't been merged. These changes may potentially overlap and break the application flow.
Having multiple heads occurs in two cases:
* As part of a merge (generally temporary)
* Bugfix versions (generally permanent)
At any time, you can view the head(s) of a repository with the command: hg heads
Pitfalls to watch-for with Multiple Heads
Consider the following scenario:
* It's Monday morning. Bob and Linda each pull a copy of the repository to their local Mercurial HG.
* Bob makes a few changes to index.php and pushes them to the server Monday afternoon.
* Linda makes a few additional changes to index.php and pushes them to the server on Tuesday morning.
Since Linda doesn't have the most recent copy of index.php (with Bob's changes), her copy of index.php will create a second "head" to the project.
There are now two development branches - the one with Bob's changes and the one with Linda's changes, neither one having all changes in place.
While TortoiseHG will often block Linda's push with a warning that it will create multiple heads, it is possible to push with -f (force). Some Mercurial plugins automatically push with -f, creating the second head on the live server repository.
Yes you can run 'hg merge' on the live server to merge Bob and Linda's changes (the two heads) locally, but you never ever want to run hg merge on a live server.
Running 'hg merge', adds "<<<<< local >>>>> other" comments into the source files, as part of its file-diff process. This temporarily breaks the syntax of your source files for the duration of the merge.
If this is a live server, your scripts will all STOP WORKING until the merge is complete and the "<<<<< local >>>>> other" notations are removed from the source files.
Rejecting Multiple heads - Do the merge offline
Instead of allowing multiple heads on the live server, a much better approach is to reject multiple heads, forcing the engineers to merge changes locally, before pushing any change that will create a second head.
In the example above, when Linda attempts to push the changes on Tuesday, her push will be rejected with an error message of "Trying to push more than one head, try run hg merge before it."
Linda then has to pull the recent changes, retrieving Bob's additions, merge the changes locally and then push a version that incorporates both her changes and Bob's into the server.
The benefits of this approach are:
#1. Server scripts are never rendered inactive by a local 'hg merge' run
#2. Engineers always need to retrieve (and test) the latest version, prior to being able to upload changes that may conflict with others.
#3. The live server always has a single development graph, containing the most recent changes.
Installing NetBeans Forbid2Heads Mercurial hook
Step 1: Locate your HG extensions folder
The folder name is 'hgext' and it is typically installed under Mercurial's home folder. For example:
/usr/home/mercurial/work/mercurial-1.3.1/hgext
Step 2: Install forbid_2heads Python script
Create a new folder named 'forbid_2head' under 'hgext' and save this file under /hgext/forbid_2head/forbid_2head.py:
# win32text.py - LF <-> CRLF translation utilities for Windows users
#
# This software may be used and distributed according to the terms
# of the GNU General Public License, incorporated herein by reference.
#
# To forbid pushes which creates two or more headss
#
# [hooks]
# pretxnchangegroup.forbid_2heads = python:forbid2_head.forbid_2heads
from mercurial import ui
from mercurial.i18n import gettext as _
def forbid_2heads(ui, repo, hooktype, node, **kwargs):
if len(repo.heads()) > 1:
ui.warn(_('Trying to push more than one head, try run "hg merge" before it.n'))
return True
Step 3: Add hook to Mercurial config file
Update your Mercurial hgweb.config, adding the new hook under the 'hooks' section, like this:
[hooks]
pretxnchangegroup.forbid_2heads = python:forbid_2head.forbid_2heads
--
Attempting to push changes to the repository that will create multiple heads is now blocked.
Users will be presented with an error message and the transaction rolled back, until the user merges changes locally, so that no multiple heads are created:
--
The live server repository will always have a single development branch. Engineers will be forced to merge changes locally, before new changes can be pushed:

The name Mercurial uses for one of these actions is a hook (aka trigger).
One of the most popular hooks is the ability to reject multiple heads.
What are multiple heads?
Multiple heads are a case where the code repository contains changes from two (or more) developers, that haven't been merged. These changes may potentially overlap and break the application flow.
Having multiple heads occurs in two cases:
* As part of a merge (generally temporary)
* Bugfix versions (generally permanent)
At any time, you can view the head(s) of a repository with the command: hg heads
Pitfalls to watch-for with Multiple Heads
Consider the following scenario:
* It's Monday morning. Bob and Linda each pull a copy of the repository to their local Mercurial HG.
* Bob makes a few changes to index.php and pushes them to the server Monday afternoon.
* Linda makes a few additional changes to index.php and pushes them to the server on Tuesday morning.
Since Linda doesn't have the most recent copy of index.php (with Bob's changes), her copy of index.php will create a second "head" to the project.
There are now two development branches - the one with Bob's changes and the one with Linda's changes, neither one having all changes in place.
While TortoiseHG will often block Linda's push with a warning that it will create multiple heads, it is possible to push with -f (force). Some Mercurial plugins automatically push with -f, creating the second head on the live server repository.
Yes you can run 'hg merge' on the live server to merge Bob and Linda's changes (the two heads) locally, but you never ever want to run hg merge on a live server.
Running 'hg merge', adds "<<<<< local >>>>> other" comments into the source files, as part of its file-diff process. This temporarily breaks the syntax of your source files for the duration of the merge.
If this is a live server, your scripts will all STOP WORKING until the merge is complete and the "<<<<< local >>>>> other" notations are removed from the source files.
Rejecting Multiple heads - Do the merge offline
Instead of allowing multiple heads on the live server, a much better approach is to reject multiple heads, forcing the engineers to merge changes locally, before pushing any change that will create a second head.
In the example above, when Linda attempts to push the changes on Tuesday, her push will be rejected with an error message of "Trying to push more than one head, try run hg merge before it."
Linda then has to pull the recent changes, retrieving Bob's additions, merge the changes locally and then push a version that incorporates both her changes and Bob's into the server.
The benefits of this approach are:
#1. Server scripts are never rendered inactive by a local 'hg merge' run
#2. Engineers always need to retrieve (and test) the latest version, prior to being able to upload changes that may conflict with others.
#3. The live server always has a single development graph, containing the most recent changes.
Installing NetBeans Forbid2Heads Mercurial hook
Step 1: Locate your HG extensions folder
The folder name is 'hgext' and it is typically installed under Mercurial's home folder. For example:
/usr/home/mercurial/work/mercurial-1.3.1/hgext
Step 2: Install forbid_2heads Python script
Create a new folder named 'forbid_2head' under 'hgext' and save this file under /hgext/forbid_2head/forbid_2head.py:
# win32text.py - LF <-> CRLF translation utilities for Windows users
#
# This software may be used and distributed according to the terms
# of the GNU General Public License, incorporated herein by reference.
#
# To forbid pushes which creates two or more headss
#
# [hooks]
# pretxnchangegroup.forbid_2heads = python:forbid2_head.forbid_2heads
from mercurial import ui
from mercurial.i18n import gettext as _
def forbid_2heads(ui, repo, hooktype, node, **kwargs):
if len(repo.heads()) > 1:
ui.warn(_('Trying to push more than one head, try run "hg merge" before it.n'))
return True
Step 3: Add hook to Mercurial config file
Update your Mercurial hgweb.config, adding the new hook under the 'hooks' section, like this:
[hooks]
pretxnchangegroup.forbid_2heads = python:forbid_2head.forbid_2heads
--
Attempting to push changes to the repository that will create multiple heads is now blocked.
Users will be presented with an error message and the transaction rolled back, until the user merges changes locally, so that no multiple heads are created:
Quote:
|
pushing to http://mydomain.com/ searching for changes 4 changesets found adding changesets adding manifests adding file changes added 4 changesets with 2 changes to 7 files (+1 heads) Trying to push more than one head, try run "hg merge" before it. transaction abort! rollback completed abort: pretxnchangegroup.forbid_2heads hook failed [command returned code 1] |
--
The live server repository will always have a single development branch. Engineers will be forced to merge changes locally, before new changes can be pushed:

![]() |
Mike Peters, 02-18-2010 |
If you're struggling with making forbid_2head.py work, here's another alternative - using a bash file:
Step 1: Save this forbid_2head.sh anywhere
Step 2: Update your Mercurial config file with:
Step 1: Save this forbid_2head.sh anywhere
#!/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
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
Step 2: Update your Mercurial config file with:
[hooks]
pretxnchangegroup.forbid_2heads = /path_you_saved_under/forbid_2head.sh
pretxnchangegroup.forbid_2heads = /path_you_saved_under/forbid_2head.sh
|
|
Subscribe Now to receive new posts via Email as soon as they come out.
Comments
Post your comments

