Rethinking Git Pre-Commit Hooks
December 2025
I've worked on many projects where, as part of the development setup, tools like Husky are used to automatically inject git pre-commit hooks. Once installed, these hooks run locally on the developer's machine and force every commit to pass whatever checks the team has enabled. If a commit doesn't pass, git will reject it, preventing you from saving your work. Common checks include enforcing code formatting, checking for untracked files, or even running unit tests.
Here's why git pre-commit hooks don't work for me, and what I prefer instead.
First, why is enforcing checks on every commit a bad thing? Because some developers, like me, make lots of draft commits that are never meant to be shared. I use commits as checkpoints. I might be experimenting with something risky and want an easy rollback point, or it might be the end of the day and I want to save my work. None of these commits will be reviewed by others. They only exist for me.
So the last thing I want when I'm trying to save my work is a tool deciding whether I'm allowed to do so. Just let me commit. Yes, I know I can skip the hooks with --no-verify, manually remove them (though they will be automatically reinstalled the next time you run npm install, for example), or set HUSKY=0 for Husky, but having to do this every time is annoying. Why create the problem in the first place? I don't want to bypass checks. I want to decide when to run them, when I know my code is ready, not every time I create a checkpoint.
A better alternative is this. Instead of enforcing checks in pre-commit hooks, expose those same checks as explicit commands. For example: make test, make test.types, make test.unit, etc. Developers are then free to run these commands when it makes sense for them, and they can still wire them into pre-commit hooks if they want.
An added bonus is that these same commands can be reused in CI/CD pipelines to enforce checks before merging a pull request.
Like this article? Get notified of new ones: