Michael Trojanek (relativkreativ) — Bootstrapper and creator of things

This article was published on July 1st 2014 and takes about 3 minutes to read.

Use it with caution — it is probably still valid, but it has not been updated for over a year.

Keeping your codebase healthy with git hooks

When developing on your own or in a small team, automation and code quality are crucial to stay agile. Git hooks are a cheap way to start optimizing.

Table of contents

  1. How to setup
  2. Technical details

git hooks are your friends. They are a snap to implement, can help you to keep your codebase healthy and may be your first step into Continous Integration.

Here is a hook that runs your entire test suite and prevents further actions if there are failing tests:

#! /bin/bash -l

BRANCH=$(git symbolic-ref HEAD|sed 's,refs/heads/,,')
[[ "${BRANCH}" != "master" ]] && exit 0

cd $( cd $(dirname $0); pwd -P )/../..

git stash -q --keep-index
bundle exec rake test &> /dev/null
RESULT=$?
git stash pop -q

if [[ $RESULT != 0 ]]; then
  echo "There are failing tests. Aborting." 1>&2
  exit 1
fi

Before running your tests, it stashes untracked changes to ensure that only relevant code is considered. The stash is reapplied afterwards.

How to setup

It can be setup in two different ways:

  • As pre-commit hook: Prevents commits when there are failing tests.
  • As pre-push hook: Prevents pushing when there are failing tests.

Git hooks live under /path/to/project/.git/hooks but it is advisable to include custom hooks in your application's root directory and symlink them so other developers on your team can use them too (you may want to include these instructions in your project's README). Note that these scripts must be executable in order for git to run them.

To use the above script as a pre-commit hook (name it /path/to/project/pre-commit):

cd /path/to/project
chmod +x pre-commit
ln -s ./pre-commit .git/hooks/pre-commit

To use it as a pre-push hook (name it /path/to/project/pre-push):

cd /path/to/project
chmod +x pre-push
ln -s ./pre-push .git/hooks/pre-push

Technical details

  • Note that the hook is run inside a new login shell (#! /bin/bash -l). Otherwise the bundle-command would not be available.
  • It acts on a specific branch (master in the example above). If you want to act on another branch just change the condition accordingly or remove line 2 and 3 entirely to make the hook act on all branches.
  • Git blocks until all hooks are run, so you may find it annoying to wait for your tests to run everytime you commit or push (depending on the speed of your test suite and the size of your project).
  • If you must commit changes that will break your tests, you can do so by committing or pushing with the --no-verify-flag - this will bypass these hooks.
  • The pre-push-hook is available not until git version 1.8.2 (run git version to find out which one you are using).
  • As long as the files are executable, you can use any language for writing git hooks.

Get in the loop

Join my email list to get new articles delivered straight to your inbox and discounts on my products.

No spam — guaranteed.

You can unsubscribe at any time.

Got it, thanks a lot!

Please check your emails for the confirmation request I just sent you. Once you clicked the link therein, you will no longer see these signup forms.