Clone wiki

headcount / Home


Headcount is a Mercurial hook for restricting intake of unseen changesets over push. Originally it was designed to prevent push of multiple heads, but now it can restrict based on any revset specification. The head count limit is now simply a use case.

Headcount is configured as a pretxnchangegroup hook, meaning that it executes once after a group of changesets is received into a repository (by push, pull, unbundle, serve), but before the changegroup is accepted permanently. This allows headcount to decide whether a changegroup is permissible.

Headcount refuses changegroups in which the number of changesets matching some revset description exceeds a defined limit. Exceptions can be made for the person pushing the changegroup, or based upon the person who committed the changeset(s) in question. (Watch for security gaps here: anyone can falsify their committer name, so be sure your configuration matches your trust profile.)

The original use case is for preventing the push of multiple heads. Mercurial naturally resists pushes of multiple heads, but this can be overcome with 'hg push --force'. Headcount (in the first example configuration below) allows a repository owner to enforce the restriction.


There are two general approaches to enabling the extension:

    pretxnchangegroup.headcount = python:headcount.headcount.hook


    pretxnchangegroup.headcount = python:/path/to/headcount/

Configuring headcount policies is straightforward:

    # If debug is True and source is 'serve' (i.e. pushing over hgweb),
    # transform debug messages to status messages so that they appear
    # remotely.  (ui.debug and ui.note are eaten over http.)
    debug = False
    # This creates a policy named 'heads' which biases against bundles
    # in which more than 1 changeset is an unclosed head.
    heads.policy = head() and not closed()
    heads.limit = 1
    # If the local username of the user performing the push is in
    # this list, policy violations are allowed.
    # To allow all users to push:
    # push_ok = *
    heads.pushok = user1, user2, user3
    # If the author name of a changeset matches[*] one of these names,
    # then that changeset is exempted from the policy.
    # To allow all committers:
    # commit_ok = *
    heads.commitok = userA, User B,
    # Template for the error message returned to the Mercurial client.
    # (This is the default message.)
    heads.warnmsg = %(matches)d new heads detected. You may not push new heads to this repository.
    # Create a secondary policy preventing pushes to the 'stable' branch,
    # unless the person pushing is identified as 'repoboss'.
    stable.policy = branch(stable)
    stable.limit = 0
    stable.pushok = repoboss
    stable.warnmsg = You may not push to the stable branch.

For pushok identifiers, a match is defined as an exact match of the local username provided by mercurial or hgweb. This may be a local account name or the value of REMOTE_USER, etc.

For commitok identifiers, a match is performed against the changeset's "user" string, and may be any of the following: 1. The exact user string; 2. The user@domain address, if the user string parses by rfc822 rules; 3. The user field of the address, if the user string parses by rfc822 rules.


To install, clone this repository within your Python path (for example, your site-packages directory):

    cd /usr/lib/python2.6/site-packages
    hg clone

Then add to your hgrc file:

    pretxnchangecount.headcount = python:headcount.headcount.hook