I want to restrict certain users from pushing changesets to the default branch of a repository. If it is possible, how would you do it?
-
Please, provide more information regarding your server setup. – C2H5OH Apr 11 '12 at 19:51
-
We store our repositories on a machine with windows server 2008 installed. The version of mercurial on that machine is 1.7.5. All of our repositories are set to go to the c:\repository folder. Each user has their own local clone on their machines. Users only commit to the server when their work is complete. From there they have to login with their username and password before they can actually commit to re repository. I looked into using [acl.deny.branches] but haven't had any luck in actually restricting users. – themaniac27 Apr 12 '12 at 16:40
2 Answers
The ACL extension should work for you. However, you need to take into account the following considerations:
The extension must be enabled in the server repositories. That is, the
hgrc
file of each served repository should have ACL settings defined:[extensions] acl = [hooks] pretxnchangegroup.acl = python:hgext.acl.hook [acl] sources = serve [acl.deny.branches] default = user1, user2, user3
These users that have push denied are system users. That is, the username is taken from the credentials provided by the web server in your case. It has nothing to do with the
Author:
field in the commit metadata.- You can only allow or deny complete chagegroups. If one of your denied users pushes a group of commits containing a single commit to the default branch, the whole push will be denied (even if the other commits are allowed). This is not so strange if your users tend to merge with the default branch very often.
You could also write your own pretxnchangegroup
hook but you will not be much more capable than the ACL extension.

- 388
- 3
- 8

- 5,452
- 2
- 27
- 39
The current answer will check at the moment when you push (and the check is server side, as what I make up from the acl code). What you want is a check on commit to your local repository. For that you should make a 'pretxncommit'-hook (note there are multiple kinds of hooks that act on different events).
Do the following:
According to A successful Git branching model, there should be no direct commits on master, only merges. To impose this we can add a callback hook to mercurial to check commits and disallow them if they are directly on master. To do that add the following line of code in your project's .hg/hgrc:
[hooks]
pretxncommit.nocommittomasterhook = python:%USERPROFILE%\hgnocommittomaster.py:nocommittomaster
The in your Windows homedirectory create the file 'hgnocommittomaster.py
' with contents (original example):
from mercurial.node import bin, nullid
from mercurial import util
# Documentation is here: https://www.mercurial-scm.org/wiki/MercurialApi
# Script based on: https://www.mercurial-scm.org/wiki/HookExamples
def nocommittomaster(ui, repo, node, **kwargs):
n = bin(node)
start = repo.changelog.rev(n)
end = len(repo.changelog)
failed = False
for rev in xrange(start, end):
n = repo.changelog.node(rev)
ctx = repo[n]
p = ctx.parents()
if ctx.branch() == 'master' and len(p) == 1:
if p[0].branch() != 'master':
# commit that creates the branch, allowed
continue
if len(ctx.files()) == 0 and len(ctx.tags()) == 1: # will not hit?, '.hgtags' always changed?
continue # Only a tag is added; allowed.
elif len(ctx.files()) == 1 and len(ctx.tags()) == 1:
if ctx.files()[0] == '.hgtags':
continue # Only a tag is added; allowed.
ui.warn(' - changeset rev=%d (%s) on stable branch and is not a merge !\n' % (rev,ctx))
failed = True
if failed:
ui.warn('* Please strip the offending changeset(s)\n'
'* and re-do them, if needed, on another branch!\n')
return True
This post was inspired by: Mercurial pre commit hook and Mercurial Pre-Commit Hook: How to hook to python program in current directory?

- 724
- 6
- 12