Mercurial_ The Definitive Guide - Bryan O'Sullivan [73]
$ cd hook-test
$ echo '[hooks]' >> .hg/hgrc
$ echo 'commit = echo committed $HG_NODE' >> .hg/hgrc
$ cat .hg/hgrc
[hooks]
commit = echo committed $HG_NODE
$ echo a > a
$ hg add a
$ hg commit -m 'testing commit hook'
committed ffec6cdc3a79c21f42d9e0c8fa460ea72c1748e5
You add an entry to the hooks section of your ~/.hgrc. On the left is the name of the event to trigger on; on the right is the action to take. As you can see, you can run an arbitrary shell command in a hook. Mercurial passes extra information to the hook using environment variables (look for HG_NODE in the example).
Performing Multiple Actions Per Event
Quite often, you will want to define more than one hook for a particular kind of event, as shown below.
$ echo 'commit.when = echo -n "date of commit: "; date' >> .hg/hgrc
$ echo a >> a
$ hg commit -m 'i have two hooks'
committed e2b474b33334b9c332deeaa7a211f36b03266ac9
date of commit: Tue May 5 06:44:39 GMT 2009
Mercurial lets you do this by adding an extension to the end of a hook’s name. You extend a hook’s name by giving the name of the hook, followed by a full stop (the . character), followed by some more text of your choosing. For example, Mercurial will run both commit.foo and commit.bar when the commit event occurs.
To give a well-defined order of execution when there are multiple hooks defined for an event, Mercurial sorts hooks by extension, and executes the hook commands in this sorted order. In the above example, it will execute commit.bar before commit.foo, and commit before both.
It is a good idea to use a somewhat descriptive extension when you define a new hook. This will help you to remember what the hook was for. If the hook fails, you’ll get an error message that contains the hook name and extension, so using a descriptive extension could give you an immediate hint as to why the hook failed (see Controlling Whether an Activity Can Proceed for an example).
Controlling Whether an Activity Can Proceed
In our earlier examples, we used the commit hook, which is run after a commit has completed. This is one of several Mercurial hooks that run after an activity finishes. Such hooks have no way of influencing the activity itself.
Mercurial defines a number of events that occur before an activity starts, or after it starts but before it finishes. Hooks that trigger on these events have the added ability to choose whether the activity can continue, or will abort.
The pretxncommit hook runs after a commit has all but completed. In other words, the metadata representing the changeset has been written out to disk, but the transaction has not yet been allowed to complete. The pretxncommit hook has the ability to decide whether the transaction can complete, or must be rolled back.
If the pretxncommit hook exits with a status code of zero, the transaction is allowed to complete, the commit finishes, and the commit hook is run. If the pretxncommit hook exits with a non-zero status code, the transaction is rolled back, the metadata representing the changeset is erased, and the commit hook is not run.
$ cat check_bug_id
#!/bin/sh
# check that a commit comment mentions a numeric bug id
hg log -r $1 --template {desc} | grep -q "\ $ echo a >> a $ hg commit -m 'i am not mentioning a bug id' transaction abort! rollback completed abort: pretxncommit.bug_id_required hook exited with status 1 $ hg commit -m 'i refer you to bug 666' committed 8e23f09593369ce73361346d89e875e152432402 date of commit: Tue May 5 06:44:39 GMT 2009 The hook in the example above checks that a commit comment contains a bug ID. If it does, the commit can complete. If not, the commit is rolled back. Writing Your Own Hooks When you are writing a hook, you might find it useful to run Mercurial either with the -v option, or the verbose config item set to “true.” When you do so, Mercurial will print a message before it calls each hook. Choosing How Your Hook Should Run You