Should you use git hooks to boost dev productivity?

What are best practices for using git hooks for developer productivity?

Jordan Baczuk, one of my connections on LinkedIn, asked me:

Hey! I’d love to know your opinions maybe a post :) on best practices for git hooks and developer productivity. I’m stuck wondering whether they are worth the time hit if I already do the same checks on the CI server.

What are git hooks?

For any readers not familiar with the concept of git hooks, they’re basically scripts that can be run at certain important times. Broadly speaking, git hooks come in two flavors: client-side hooks and [server-side hooks]((https://git-scm.com/book/en/v2/Customizing-Git-Git-Hooks#_server_side_hooks). Since Jordan says he already has a CI server doing some checks, I’m going to assume he’s interested in client-side hooks, and only discuss that today.

For the purpose of sanity checks on code, the pre-commit hook is going to be the most interesting, because it

is run first, before you even type in a commit message. It’s used to inspect the snapshot that’s about to be committed to see if you’ve forgotten something, to make sure tests run, or to examine whatever you need to inspect in the code.

So here you could add a make test (or your project’s equivalent) to ensure that all tests pass before your code is committed. Or maybe you’d run a code formatter or static analysis tool/linter. You can go as crazy as you want, of course.

When should we use git hooks?

So with that preliminary information out of the way, let’s address Jordan’s question.

On principle, we want to get feedback as quickly as possible about our code. Back in the old days, you’d write come code with a pencil, pass it along to someone with a teletype machine who would encode it on cards, then send those cards over to the data processing center where, hopefully, there’d be 30 minutes of spare computing time available in the next day or two, for the computer operator to feed your cards into the machine, then spit out some result on linefeed paper. They’d then send that linefeed paper and your original stack of cards back to you via courier, probably in another building. The next morning, you’d pour over the results, and see if they matched expectations. If not, you’d repeat the process.

The feedback loop was often measured in hours or days.

Fortunately, our computers are a wee bit faster now. Ironically, the worst case scenario hasn’t improved much: Write code, push it up to git, then wait for a deploy in 3 months to see if the users liked it.

However, the best case scenario is immensely better: Write some code then hit the save butto… oh wait. My IDE already told me I have a typo in my function name. Let me correct that.

Of course not all coding errors can be caught by your IDE’s relatively trivial checks. So you’re writing some unit tests, too, right? If you run those unit tests for every commit or pull request you send to git, then you’ll know within minutes (one hopes) if you’ve accidentally introduced a regression. That’s pretty good. But can we do better?

What if you ran all your unit tests in a git hook? Then you’d know before your code ever landed on the centralized Git server. Faster feedback FTW!

If that’s your only option, (and your local dev machine can be reasonably configured to run most or all of your tests) I would suggest using git hooks for this purpose.

However, most modern languages have some pretty tight integration to your editor/IDE, so that as soon as you hit the save button, it can run your style linter and unit tests automatically. As a Go developer, that usually takes well under a second. Not all programs (or languages) compile and execute as quickly. But still, you should be able to get pretty good feedback at a unit-test level within two or three seconds in most cases.

So this leads to my concrete suggestions:

  1. Set up CI to run your tests, code formatting, and static analysis.
  2. Configure your editor or IDE to run as much of that on save (or even earlier!) as possible.
  3. If either of those is not possible for you for some reason (you’re using an unusual language, or you simply prefer coding in pico for some reason), then set up a pre-commit git hook as well.

In principle, there might be one other reason to use a git hook, although I’m scratching my head to think of a practical example. And that would be if you ever have code that you want to use during testing, but that should never be sent to the server. Maybe a personal API key or something, for example, could be detected and rejected by a git hook. But honestly, I think this is better handled with .gitignore.

Now that CI/CD servers are more or less ubiquitous, the only times I’ve really advocated strongly for git hooks is in the case where your team does not use CI/CD, and can’t be convinced to. Then using git hooks is better than nothing. Especially if you can convince the rest of your team to run the hooks locally as well. But then, one would hope you could convince them to install a CI server… 🤷

Share this