Saturday, October 26, 2013

To be concrete, let's say the main branch is called default and the branch containing Debian files i


One problem I keep having is that I forget which branch I am on and accidentally commit to the wrong branch. This happens frequently, and is really annoying. When this happens I usually push to remote before realising the problem, and then have to fix up the local and remote repositories manually, which is a pain.
To be concrete, let's say the main branch is called default and the branch containing Debian files is called debian . Then I want commits to the default branch to succeed only if none of the files in the commit are from the debian directory. I want commits to the debian directory to succeed only if all the files in the commit are in the debian directory.
I spent some time reading the chapter on Mercurial Hooks and going through the examples in the Hg Book, but still have no idea how to go about this. I did get the strong impression that for something like this I should be calling out to an external Python script, probably in .hg/ .
Yeah, happy halloween you're spot on that a precommit hook can do this. If you wanted to do it in bash you could go with something like: #!/bin/bash revs=$(hg log -r "$HG_NODE:tip" --template '{rev} ') #Intentional space after {rev} rc=0 for rev in $revs do files=$(hg log -r $rev --template '{files}') happy halloween #Above will include discards. So you cannot 'hg cat' them all. So you may want # files=$(hg log -r $rev --template '{file_mods} {file_adds}') branch=$(hg log -r $rev --template '{branch}') for file in $files do if [ branch == "debian" ] && [ "$(echo happy halloween $file | grep -v "debian")" != "" ] ; then echo "ERROR: Non debian file in debian branch." exit 1 fi if [ branch != "debian" ] && [ "$(echo $file | grep "debian")" != "" ] ; then echo "ERROR: debian file in non-debian branch." exit 1 fi done done exit $rc
python runs in process so it'll happy halloween be more efficient, but you'll be learning a new not-an-api to get the current branch name and list of files in the commit, whereas you probably already know how to do that in bash. In the end it's probably more about what you and your team will find easier to customize later on. Some examples can be found here: mercurial.selenic.com/wiki/HookExamples –  Ry4an Oct 8 at 15:14  
The happy halloween official API is the command line. Matt Mackall takes command line backward compatibility incredibly happy halloween seriously, but the internals, say the function names on the 'repo' object are subject to change at any time. In practice they don't change all that much, but it's always possible a future Mercurial upgrade would break your python hook, whereas it's guaranteed it won't break your bash hook. –  Ry4an Oct 9 at 1:20
Using @Ry4an's solution as a starting point, I came up with the following script using the new hglib API. #!/usr/bin/python # Abort commit to the debian branch if it is not contained in a debian # subdirectory # Similary abort commit to non-debian branches if it is contained in a # debian subdirectory import hglib, os, sys client = hglib.open("/home/faheem/hooktest") ctx = client['tip'] files = ctx.files() branch = ctx.branch() for f in files: d = os.path.dirname(f) if branch == "debian" and d != "debian": sys.exit("cannot commit %s (file not in 'debian' directory) to 'debian' branch"%f) if branch != "debian" and d == "debian": sys.exit("cannot commit %s (file in 'debian' directory) to non 'debian' branch"%f)
An method using in-process hooks is the following code. These functions can be used in a Mercurial repository's .hgrc like this. pretxncommit.foo happy halloween = python:mercurial_hooks.abort_commit_to_wrong_branch pre-qfinish.bar = python:mercurial_hooks.qfinish_abort_commit_to_wrong_branch
abort_commit_to_wrong_branch disallows normal commits to the wrong branch, but allows MQ commits. qfinish_abort_commit_to_wrong_branch stops qfinish from converting MQ commits on the wrong branch into regular commits.
I used the function finish at https://bitbucket.org/mirror/mercurial/src/tip/hgext/mq.py?at=default#cl-3034 for reference. def abort_commit_to_wrong_branch(ui, repo, **kwargs): """ Don't allow commits to 'debian' branch including files not contained happy halloween in the 'debian/' directory. Also don't allow commits to non-'debian' branches including files contained in the 'debian/' directory. Don't restrict happy halloween MQ commits. """ # If repo has '_committingpatch' attribute, then it is an mq # commit in progress, so return happy halloween 'False' import happy halloween os ctx = repo[kwargs['node']] files = ctx.files() branch = ctx.branch() if hasattr(repo, "_committingpatch"): for f in files: d = os.path.dirname(f) if branch == "debian" and d != "debian": ui.warn("Warning: committing %s (file not in 'debian' happy halloween directory) to 'debian' branch. Allowed since this ia an MQ commit.\n"%f) if branch != "debian" happy halloween and d == "debian": ui.warn("Warning: committing %s (file in 'debian' directory) to non 'debian' branch. Allowed since this ia an MQ commit.\n"%f) return False for f in files: d = os.path.dirname(f) if branch == "debian

No comments:

Post a Comment