Using git hooks

Contents

  1. Commit Hooks
    1. Types of commit hooks
      1. pre-commit
      2. prepare-commit-msg
      3. commit-msg
    2. Testing commit hooks
  2. E-mail Hooks
  3. Other Hooks
    1. post-merge
  4. Server-Side Hooks
    1. update
    2. pre-receive
    3. post-receive
  5. Links

Git hooks

Git is already satisfactorily documented. If you've landed here then you are likely doing yourself a disservice and should instead use the official documentation by searchin git-scm.com

From here on out is ideally simple notes (mostly just an opinion piece) for either those that forget or those who are overwhelmed by the real documentation.

I believe most hooks should have at least these three things:

  1. Output that always occurs to ensure you know the hook is running or has run.
  2. A default-to-fail style (start by setting the output to always exit as a failure/reject, then allow the code to test and override this to a success.
  3. A clear pass/fail. With failure: a reason for the rejection. Ideally with a hint or tip to resolving it.

Commit Hooks

As these are managed by the .git/ directory with a non-bare repository they must be enabled by the user - as the .git/hooks/ directory itself is not managed by git.

Types

pre-commit

Aptly named, this hook runs before a commit is completed. This is regularly where validations occur for an end-user on their own workstation. Usually these are paired with pre-receive hooks.

prepare-commit-msg

Run before a commit editor is started, but after the default message is created. Usually for automated commits.

commit-msg

Ensure commit messages are correctly patterned

Testing

To test a commit hook is very simple. You modify the hook in your .git/hooks/ directory, and then attempt to perform a commit action. With appropriately verbose output it should be easy to see if your hook is allowing or denying the intended action.

The same below procedure is used for testing commit-msg, prepare-commit-msg, & pre-commit hooks.

cd ~/git/mytestrepo/
cp hooks/pre-commit ~/git/mytestrepo/.git/hooks/pre-commit
touch testfile
git add testfile
git commit
          

If your hook is not running - then you likely have a problem with permissions (ownership and mode) of the hook file. Most other troubles you will encounter will be within your hook itself.

E-mail Hooks

applypatch-msg, pre-applypatch, & post-applypatch: For information about these, visit the Official documentation.

Other Client Hooks

pre-rebase, post-rewrite, post-merge, pre-push: For information about these, visit the Official documentation.

Server-Side Hooks

Hooks managed on the server-side (regularly a "storage" directory used to host repositories where the repository is often bare.

Types

update

pre-receive

post-receive

Testing

To test a server-side hook is only slightly more complex than that of a commit hook. I generally create a bare-repository of the repository I wish to test against to act as the "server-side", create a remote from my repository to this "server-side", then enable the hooks and try pushing branches.

The same below procedure is used for testing update, pre-receive, & post-receive hooks.

mkdir ~/gitd/mytestrepo.git # I use ~/gitd & .git to differentiate for bare-repositories vs ~/git/
cd ~/gitd/mytestrepo.git
git init --bare # initialize the empty repository
cd ~/git/mytestrepo/ # go back to the existing repository
git remote add hooktest file:///$HOME/gitd/mytestrepo.git # Add the bare repository as a remote named "hooktest"
cp hooks/pre-receive ~/gitd/mytestrepo.git/hooks/pre-receive # Set your hook into the bare-repository's hooks/ directory.
git checkout -b 'hookfail' # branch to a named-branch where you can go hog-wild with testing bad commits/branches/etc.
touch badfile
git add badfile
git commit -m 'This should fail my pre-receive hook if I did things right.'
git push hooktest hookfail
          

At this point, if your hook properly does what you want - you should see output that it is running and then an exit that it rejected your change (since this is the badfile/hookfail test). Now repeat for a known-good case to ensure it is allowed:

git checkout master # or whatever your base branch is
git checkout -b 'hookpass'
touch goodfile
git add goodfile
git commit -m 'This should pass because I made a good change.'
git push hooktest hookpass
          

If you made your "hookfail" and "hookpass" branches correctly and avidly - you can always leave them as-is and re-use them in the future to ensure any other changes to your pre-receive hook still pass/fail appropriately. I recommend occasionally pulling your master branch into them (e.g., just:

git checkout hookfail && git merge master
).

If you are able to push up your "hookfail" branch -- delete it via:

git push hooktest :hookfail
and then fix your hook - re-copy the hook in place, and try again. Same goes for the hookpass branch.

If your hook is not running - then you likely have a problem with permissions (ownership and mode) of the hook file. Most other troubles you will encounter will be within your hook itself.

Links

Last Modified: 2019/12/03
URL: https://www.dayid.org/comp/githooks.html
Valid HTML 4.01 Strict Written in the vi editor