pre-commit
My team and I ran into a problem where Code Style violations were being caught too late: in CI or at Code Review. A shared .editorconfig clearly wasn’t enough on its own, since editorconfig can’t fully describe every nuance of formatting.
The obvious, well-known solution is to check code before it lands in source control. Everyone knows about git hooks,
but over the past few years I haven’t run into teams that actually use them seriously.
In my view, there are two main problems with git hooks:
- There’s no transparent way to install them when checking out a working copy.
- A scripted response to a specific action (e.g.
pre-commit) is driven by a single file in.git/hooks— that makes it hard for the team to keep hooks current.
To make pre-commit-hook setup easier, we used the well-known pre-commit tool. It’s written in python and uses a yaml configuration.
What are the advantages of this tool? Let’s list them:
- A declarative description of the scenarios that need to run before changes hit history, kept in a single
.pre-commit-config.yamlconfiguration file. - Strict pinning of the scenario versions — the key to reproducibility across every contributor and every machine.
- The ability to run the whole set of checks independently of
gitviapre-commit run. - Simple installation of the scripts into your working copy with a single
pre-commit install.
Installation
I recommend installing pre-commit with pipx. This approach has an undeniable advantage: each tool installed via
pipx gets its own virtualenv, so the python packages it depends on won’t collide with each other in the system
site-packages.
pipx install pre-commit
If that’s not a big deal for you, follow the installation instructions in the official documentation instead.
Example
Here’s what the .pre-commit-config.yaml for this blog looks like:
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v3.2.0
hooks:
- id: trailing-whitespace
- id: end-of-file-fixer
- id: check-yaml
- id: check-toml
- repo: https://github.com/igorshubovych/markdownlint-cli
rev: v0.34.0
hooks:
- id: markdownlint-docker
args:
- --disable
- MD034
I deliberately disabled the check that bans “bare” links in markdown — I consider that acceptable.
And here’s how you’d enable checking and formatting of import directives in Go using goimports:
repos:
- repo: https://github.com/tekwizely/pre-commit-golang
rev: 645165368711be670d1945c15060e746f5ed15c6
hooks:
- id: go-imports
args:
- -local
- git.your-company.tld
- -w
Once you’ve described .pre-commit-config.yaml at the root of your repository, run:
pre-commit install
That will wire the hooks into your working copy.
If you want to check your changes before running git commit, run pre-commit run:
pre-commit run
The output will show the issues, if there are any.
Hopefully pre-commit makes it easier for you to start using git hooks — if you actually need them, of course. Good
luck!