Missing git hooks documentation

One part of git’s documentation that is particularly lacking is that on the subject of hooks.  In particular, that page doesn’t explain:

  • What the current working directory is when the hooks run.
  • Which helpful environment variables are set in the environment when the hooks are run.

These omissions are particularly irritating since the current directory is not consistent across the different hooks, and the setting of the GIT_DIR environment variable can cause some very surprising results in some situations.

So, I did some quick tests to find what the behaviour of git 1.7.1 is for each of these hooks, for both bare and non-bare repositories where appropriate.  (If I were more confident about the details of these, I would try to contribute a documentation patch, but that’s probably best done by someone who knows the code well.)

applypatch-msg
post-applypatch
pre-applypatch

(Tested with “git am” in a working tree – it cannot be used with a bare repository for obvious reasons.)

The current directory is the top level of the working tree.  The following environment variables are set:

  • GIT_AUTHOR_DATE, e.g. set to ‘Sat, 9 Apr 2011 10:13:24 +0200′
  • GIT_AUTHOR_NAME, e.g. set to ‘Ada Lovelace’
  • GIT_AUTHOR_EMAIL, e.g. set to ‘whoever@whereever’
  • GIT_REFLOG_ACTION is set to ‘am’

Note that GIT_DIR is not set.

pre-commit
prepare-commit-msg
commit-msgt
post-commit

(Tested with “git commit” in a working tree – it cannot be used with a bare repository.)

The current directory is the top level of the working tree.  The following environment variables are set:

  • GIT_DIR is set to ‘.git’
  • GIT_INDEX_FILE is set to ‘.git/index’

post-checkout

(Tested with “git commit” in a working tree – it cannot be used with a bare repository.)

The current directory is the top level of the working tree.  The following environment variables are set:

  • GIT_DIR is set to ‘.git’

pre-receive
update
post-receive
post-update

These hooks can be run either in a bare or a non-bare repository.  In both cases, the current working directory will be the git directory.  So, if this is a bare repository called “/src/git/test.git/”, that will be the current working directory – if this is a non-bare repository and the top level of the working tree is “/home/mark/test/” then the current working directory will be “/home/mark/test/.git/”.

In both cases, the following environment variable is set:

  • GIT_DIR is set to ‘.’

With a working tree, this is unexpectedly awkward, as described in Chris Johnsen’s answer that I linked to earlier.  If only GIT_DIR is set then this comment from the git man page applies:

Note: If –git-dir or GIT_DIR are specified but none of –work-tree, GIT_WORK_TREE and core.worktree is specified, the current working directory is regarded as the top directory of your working tree.

In other words, your working tree will also be the current directory (the “.git” directory), which almost certainly isn’t what you want.

pre-auto-gc

(Not tested yet.)

Summary

I think the (quite obvious) lesson from this is just:

  • Always test your hooks carefully, probably starting with a script that just echos the current working directory and GIT_DIR.

A related tip is that since the rules about GIT_DIR / –git-dir and GIT_WORK_TREE / –work-tree / core.worktree are so complex, I follow the rule of thumb that if you need to set either one, set both, and make sure you set them to an absolute path.

In case you’re interested, the test hook I used for this was just:

#!/bin/bash
echo Running $BASH_SOURCE
set | egrep GIT
echo PWD is $PWD

6 thoughts on “Missing git hooks documentation”

  1. (And thx for being so thorough yet concise with your investigation + docs. Really appreciated. Hope git community integrates above notes into their native docs.)

  2. git rev-parse –git-dir

    “trust, but verify”

    root_dir=$(git rev-parse –git-dir)
    root_dir=$(cd $root_dir >/dev/null && cd .. >/dev/null && pwd -P)

  3. Thanks for the helpful article. I couldn’t find a comprehensive list of variables beeing set elsewhere but your small script has lead me to find an interesting variable beeing set by post-merge :

    GITHEAD_b6668177bc4906dbf05dac37eb30108a24cf3939=master

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>