Pre-commit Hooks in Git
Remembering to run your tests before you commit is hard:
* 84f7e2e 2016-02-06 | Another typo. And test[David Wickes] * ef215f8 2016-02-06 | OMFG semicolons WAAAAAT [David Wickes] * c20b65d 2016-02-06 | Typo [David Wickes] * fca4aa8 2016-02-06 | Another fix for the same test[David Wickes] * f0206a9 2016-02-06 | Fixes failing test [David Wickes] * 657cc48 2016-02-06 | Amazing new feature [David Wickes]
Yes, I suck. It’s even worse when you’ve just pushed that teensy-tiny, insignificant change to the CI pipeline and it throws a strop because the JS linter is super fussy about semi-colons.
Don’t get angry. Get even.
Wait, wut? Don’t get even. Automate all the things!
Inside the unexamined recesses of the
.git directory of every repo
is a folder called
hooks. You should look inside it.
applypatch-msg.sample commit-msg.sample post-update.sample pre-applypatch.sample pre-commit.sample # <--- This one here! pre-push.sample pre-rebase.sample prepare-commit-msg.sample update.sample
You’ll see some pretty self-explanatory instructions on what it does, but the tl;dr is:
- It is a shell script that runs before you commit
- You activate it by removing the
So say we have a Node project we’re working on. A cool pre-commit hook would look like:
#!/bin/sh npm test
Pop that in a file called
pre-commit inside that
hooks directory - make sure
it’s executable like the sample ones - and see what you get.
So as long as you’ve set up you
package.json file sensibly to run tests when
npm test you’re golden. Same idea holds for
whatever you’re using as a task runner.
But you’d hate to do that for every project, right? Automate that too.
$ git config --global init.templatedir '~/.git-templates' $ mkdir -p ~/.git-templates/hooks
Inside the equally unexamined
.gitsettings in your home directory you should
[init] templatedir = ~/.git-templates
(you could’ve just written that in there by hand… but here we are)
What this’ll do is copy the contents of
.git-templates to the
directories of new projects you clone or initialize.
We now need to make our hook more generic. Let’s save the below off in
#!/bin/sh if [ -f package.json ]; then echo "detected package.json... running npm test" npm test else echo "no testable project detected... so no tests before commit" fi
[ -f package.json ] asks if there’s a file called
package.json, and if there
is we run
npm test. The rest of the script is just a little logging so we can
see what’s happening. Just remember to make it executable1 before you start to
There we have it - the bare bones of a “generic” pre-commit hook. You can easily
embelish this with more tests and other exciting/useful/amusing things to
execute (is there a
Rakefile present? Do any of the files I’m commiting still
console.log or a
As I said, this template will get added to everything that gets
initialized by Git from now on. For those projects that have already been
started, just run
git init again to pull in the template.
And there we are - have fun exploring the other sample templates, read the docs, and experiment with other useful scripts. Then tell me about them on Twitter so I can use them.
chmod a+x pre-commit- you didn’t need telling, but just in case.