Are pre-commit git hooks a good idea? I don't think so.
Tags: programming, git, commit, cicd
Published: 2023-12-17 16:36:05

Here's a little rant from a technical owner perspective.

I've seen this at various places. A senior developer sets up a repository, everything is well and all right, the main branch is protected and there are CICD pipelines set up. Everything is fine. And then, with a little thought given to it, pre-commit git hooks are set up.

Obviously, I mean the hooks that run on your very machine, before you can actually *commit* stuff.

Is it a good idea? Maybe it's a bad and micro-manager-like way to power flex? Well, let's see.

# The good intentions
I get it. This option looks attractive on the surface. Here are points that look all right at the first glance.

##### Git history looks cleaner
This point is stupid because you will squash pull requests anyway so any weird commits not passing tests are removed.

##### Save time on CI
Fair point, you will save some time, but are you *really* that tight on budget that you can't spare some seconds?

If this is a problem, maybe your pipelines can be configured better. Follow the fail-early method, run linter first, then units, then integration, and so on.

Ultimately, the developer working time is much more expensive, and with pre-commit hooks you lose a bit of this time.

##### Force developers to test before pushing
This point is distrust in your workers, just disguised. If you don't trust your developers, fire them, or fire yourself.

# The bad reality
Usually, pre-commit hooks are a terrible idea. To clarify why, here are some my thoughts on this topic

##### Most likely your tests suite doesn't run in seconds
Tests can be speed up (see my other articles) but usually if you are working on non-trivial code base, the tests will take a considerable amount of time. Maybe it's 5 minutes, maybe 10, who knows, but you really do not want to do it before commit.

You already have CICD that will run exactly the same suite, why bother running it locally? Use the resources you yourself set up.

##### Developers will be either afraid of commiting often or will just skip this stupidity with --no-verify
This is a very important point, maybe even the most. You want your developers to commit often. This allows more experimentation, which can be reverted if they want, at any time. With long hook any commit is a long investment of time, nothing can be done in this time as well.

It will hinder your developers performance because of that. They will make less commits, make big commits, and will not be able to tests various solutions to a problem with easy way to revert them.

##### Are you sure tests can be run locally, or you only pretend?
Sure there can be projects that are set up *correctly* that everything can be run locally. 

But even more often, nowadays, you will encounter absolutely rubbish setups that require, for example, AWS credentials to run tests.

Not only this makes it impossible to work locally, for example in a plane or on a train without internet, but also means that developers that are joining the project will need to wait for accesses to remote systems before even trying to commit anything! Hilarious situation, and complete waste of time.

Most likely one developer will not completely overhaul the whole system, in a way that every single test must be run locally when developing that refactor. Most of the time developer will work on one feature, quickly iterate with tests just for this feature, and once it's ready, will commit and push. Only then on CICD the whole suite will run, and your pipelines are already well configured for this task.

I should probably write a checklist style article about how to set up a project correctly. Follow me, it will happen soon.

##### Scope of testing in very big projects
Sometimes you encounter a monorepo with 10 subprojects inside it. Why the heck would a developer even want to run tests of completely unrelated projects when developing a small change in one of them? Again, waste of time. Anyway, CICD will validate stuff in the end.

Not to mention such monorepos are a stupid idea too, why group unrelated projects inside one single repository? There is no good answer to that.

##### Trust issues
Do you really want to show that you do not trust your developers to do the right thing? You should want them to experiment, push half working stuff to their branches, see the outcomes, who cares whats going on in their experimental branches. 

The end goal is the same, working code, with passed pipeline tests, merged into main/dev/whatever.

By micromanaging your developers by enforcing pre-commit hooks you show that you don't trust them. What's the next step? Watching them code via screen sharing? Believe or not, I've seen that.

# Final words
Just don't. If you already made a mistake and set up this feature already, remove it. Everyone already does --no-verify anyway.