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

Posted

in

by

Tags:

Comments

12 responses to “Missing git hooks documentation”

  1. Hydrostarr Avatar
    Hydrostarr

    Good grief this is helpful. And like you say, so missing from the git docs. Helpful to sort out things like http://goo.gl/yN9UH .

  2. Hydrostarr Avatar
    Hydrostarr

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

  3. Bruce Avatar
    Bruce

    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)

  4. Daniel Convissor Avatar

    Nice work, it’s very helpful. I found your page while looking for a cheat sheet summarizing when each hook is run and the parameters it takes. I didn’t see one around so made one:
    http://www.analysisandsolutions.com/code/git-hooks-summary-cheat-sheet.htm

  5. Angelo Borsotti Avatar
    Angelo Borsotti

    Did you submit a bug report?

  6. Sunny Avatar

    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

  7. Andrey Avatar
    Andrey

    typo in “commit-msgt” – supposed to be “commit-msg”

  8. Marissa Avatar

    I think your challenge there is that you are tinyrg to implement something that is developed for client side (tracking an event using GA’s javascript) into something that is server side (a php action wpmem_post_register_data is an action hook, not a filter hook). You would probably need to focus on adding an event tracking javascript to the registration form itself, such as adding the onClick action to the form submission process. You could do that with the wpmem_register_form filter hook.

  9. Ohad Schneider Avatar

    As of 2.9.0 the docs (https://git-scm.com/docs/githooks/2.9.0) address this:

    Before Git invokes a hook, it changes its working directory to either the root of the working tree in a non-bare repository, or to the $GIT_DIR in a bare repository.

    For more information: http://stackoverflow.com/questions/7065224/in-a-git-hook-is-the-current-working-directory-guaranteed-to-be-within-the-git-r/37927943#37927943

  10. Jonas Avatar
    Jonas

    Author, E-Mail and Date are also available in the pre-commit hook. That was made available after this article was published. For more info see:

    https://github.com/git/git/commit/7dfe8ad6006c105989e4e8cfb196aa4ecda3c21d#diff-8bdf812e0d5d9983d4c8fab34e829994

Leave a Reply to Sunny Cancel reply

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

This site uses Akismet to reduce spam. Learn how your comment data is processed.