hgban /

Full commit
#!/usr/bin/env python

'''exclude-changesets is a Mercurial extension which sets up a pretxncommit hook.
Any changesets to be pushed / pulled / bundled into the repository will have their
changeset hashes compared against a list of excluded hashes in repo/.excludedchangesets.
If any new hash is already in this file of excluded hashes then the entire
changegroup will be rejected.

Enable the exclude-changesets just like any other Mercurial extension by adding the
following to your hgrc

exclude-changesets = /path/to/exclude-changesets

import os.path, re
from mercurial import hg

#print "Checking For Excluded Changesets!"

def getSetOfExcludedChangesets(repo):
        excludedChangesetsPath = os.path.join(repo.root,'.excludedchangesets')
        f = open(excludedChangesetsPath, 'r')
        excluded = set()
        changesetPat = re.compile(r"(^[0-9a-fA-F]+).*")
        for line in f:
            m = re.match(changesetPat, line)
            if m:
        return excluded
        return {}

def changesetIsExcluded(node, excludedChangesets):
    for p in excludedChangesets:
        if, node):
            return True
    return False

def colateChildren(ctx, colation = set()):
    children = ctx.children()
    for childCtx in children:
        if not childCtx.hex() in colation:
            colateChildren(childCtx, colation)
    return colation

def checkForExcludedChangesets(ui, repo, **kwargs):
    node = kwargs.get('node')
    rejectedChangesets = set()
    if node:
        excludedChangesets = getSetOfExcludedChangesets(repo)
        ctx = repo[node]
        allChildren = colateChildren(ctx)
        for childChangeset in allChildren:
            if changesetIsExcluded(childChangeset, excludedChangesets):
        if len(rejectedChangesets) > 0:
            repoName = os.path.basename(repo.root)
            if len(rejectedChangesets) == 1:
                ui.warn('The following changeset was rejected by the repository \'%s\'\n' % repoName)
                ui.warn('The following %d changesets were rejected by the repository \'%s\'\n' % (len(rejectedChangesets), repoName))
            for changeset in rejectedChangesets:
                ui.warn('    %s\n' % changeset)
            if (len(rejectedChangesets) < len(allChildren)):
                if len(rejectedChangesets) == 1:
                    ui.warn('Rebase, transplant, or otherwise transfer any changesets you have which are derived from this rejected changeset.\n')
                    ui.warn('Rebase, transplant, or otherwise transfer any changesets you have which are derived from these rejected changesets.\n')
            return True # We found an excluded changeset, return True (exit code 1) which causes the changegroup addition to be aborted.
    return False # No excluded changesets were found. The changegroup addition can go ahead.

def reposetup(ui, repo):
    ui.setconfig("hooks", "pretxnchangegroup.exclude-changesets", checkForExcludedChangesets)