Test driving pre-commit
The git
tool offers many hooks - you can ls -al .git/hooks
in any repo to see:
$ ls -al .git/hooks
total 104
drwxr-xr-x 14 gavin staff 448 25 Oct 2021 .
drwxr-xr-x 15 gavin staff 480 13 Aug 19:15 ..
-rwxr-xr-x 1 gavin staff 478 25 Oct 2021 applypatch-msg.sample
-rwxr-xr-x 1 gavin staff 896 25 Oct 2021 commit-msg.sample
-rwxr-xr-x 1 gavin staff 3327 25 Oct 2021 fsmonitor-watchman.sample
-rwxr-xr-x 1 gavin staff 189 25 Oct 2021 post-update.sample
-rwxr-xr-x 1 gavin staff 424 25 Oct 2021 pre-applypatch.sample
-rwxr-xr-x 1 gavin staff 1638 25 Oct 2021 pre-commit.sample
-rwxr-xr-x 1 gavin staff 416 25 Oct 2021 pre-merge-commit.sample
-rwxr-xr-x 1 gavin staff 1348 25 Oct 2021 pre-push.sample
-rwxr-xr-x 1 gavin staff 4898 25 Oct 2021 pre-rebase.sample
-rwxr-xr-x 1 gavin staff 544 25 Oct 2021 pre-receive.sample
-rwxr-xr-x 1 gavin staff 1492 25 Oct 2021 prepare-commit-msg.sample
-rwxr-xr-x 1 gavin staff 3610 25 Oct 2021 update.sample
In the above example, I don’t have any hooks set up; there’s just a bunch of samples. I’ve often used pre-push
to stop myself pushing outright garbage.
But let’s say I want to prevent myself from committing some dump stuff. I mean, sure, we have CI and all that, but for small, light checks, we can run before even making the commit in the first place…
Better still, we can apply our autoformatting code style at point of commit, without ever having to explicitly run the tool.
AUTOMATION. ROBOTS! A better class of problem!
So, we could write our own hooks, for example a pre commit hook as described above… But do we really have to write it all ourselves? Wouldn’t it be nice to pull some off the shelf, like we do for everything else these days?
Enter pre-commit
pre-commit is “a framework for managing and maintaining multi-language pre-commit hooks”. The rationale for its existence is that it’s painful to manage hooks across projects. After all, it’s a generic problem - everyone needs linters, for example!
I won’t duplicate their documentation, this article is more about figuring out where
pre-commit
could be situated in a developer’s tool chain
I installed it on the repo for this website and added just one hook to trim trailing whitespace.
I hacked a PHP file, added some whitespace at the end, and committed it, and hey presto, it was auto-trimmed!
$ git commit -amx
Trim Trailing Whitespace.................................................Failed
- hook id: trailing-whitespace
- exit code: 1
- files were modified by this hook
Fixing README.md
Fixing remove-dead-tag.php
Clearly, in IRL, I would never use
x
as a commit message! :p Man was just fiddlin’!
Any gotchas?
Not really gotchas, more something worth knowing… The pre-commit hook will only operate on staged files, i.e. files in the set you git add
. So, when you add a new plugin, it won’t run on all the files in the repo unless you pre-commit run --all-files
.
You can skip pre-commit
by supplying the --no-verify
flag to git, should you need to, although it may be neater to use the SKIP
flag (see their docs.
Writing your own plugins
One of the most powerful features is that you can write your own hooks, and use them cross-repo simply by specifying them by repo in the Yaml. Tops!
Loadsa languages are supported, but unfortunately my goto language PHP is not included. Boo! However, Node and Python are, so man’s happy with that.
In the current role I’m working in, I am considering developing a few pre-commit hooks to help keep our Terraform consistent, doesn’t look too hard to wire in.
Worth a bash?
Yeah, for sure. It’s complementary to CI, .editorconfig
, pull request reviews… It’s another tool in that space to help you write more consistent code, and to raise your game in terms of the quality of mistakes you’re making.
And if you are getting to grips with Git, see my free eBook, Git Workflow Discipline :-)