Git Hooks (Part I) - The Basics

What are hooks?

Hooks are scripts that help you enforce policies on your repository by triggering scripts at certain events that enforce policies such as 'The commit message must be longer than 20 characters' or 'The test suite must be run before a commit and if it fails, reject the commit'.

Hooks are available in every VCS I have used before. They are also available in Visual Sourcesafe which is not a VCS.

Git Hooks

In Git the hook scripts can be implemented using any language but Shell, Ruby, Perl and Python scripts are the most common as far as I know.

The language of the script is determined by the shebang notation as it is usually in Linux based software. Note that this also applies to Windows because Git for Windows runs under MSYS.

If you supply the --no-verify argument to the git command then the command will still be executed even if one (or more) of the hooks failed (i.e. returned a non-zero status code). Please do this only if you know what you are doing.

These hooks reside under the .git/hooks/ directory of your repository.

The Git-SCM book already covered the various hooks available. It also provided an example of how those hooks can be written in Ruby.

For a quick reference you can open your favorite shell and type:

git hooks --help

Why should you be using hooks?

Because this is the last time we let Tim commit ASCII porn in the comments!

Controlling commit contents

Seriously now, no one wants to be the guy/girl who has to bring coffee & doughnuts at his/her expense for tomorrow’s standup meeting because he broke the build so we want to make sure our codebase does exactly what it should. If it happens to you too many times you might end up being broke :)

We want the test suite to run automatically every time we change something. It's one of the reasons we have a test suite, so we know we're on the right path and things aren't broken.

We also want to make sure that our test coverage is high enough, because untested code won't break the build but it will surely break your production environment.

These are good example of common hooks that you should implement in order to decrease build breakage and long, frustrating and lonely nights spent screaming “WORK GODDAMIT WORK!” at your development machine.

Allow me to paraphrase a line from the movie “Training Day” (It’s a great movie by the way)

I wanna go home :)

I don’t know about you guys but I wanna’ go home. I implement these hooks for every project I work on.

Apart from testing, we want to make sure that our codebase fits our style guidelines so we need to run a lint tool.

We also want to make sure that the docs can be generated and that every public module, class & method is documented.

Controlling commit messages contents

Remember that time where you spent a day figuring out what changed in a specific commit that caused major downtime because the commit message was “Fixed this bug” for a commit that added new 20 files and modified 90 other files? If you don’t want to repeat that experience than we have to make sure that we know exactly what changed in each commit.

First of all, thank Linus, empty commit messages are not allowed in Git. If you do not provide a commit message your favorite editor will be opened for you. If you still haven’t typed anything in your favorite editor, the commit will be aborted.

But it’s not enough. We have to make sure the commit messages are meaningful.

It is recommended to reject very short commit messages. Commit messages that contain below 10 characters are usually useless.

All commit messages must be in English only because your team may speak another language but you never know when you’ll have to subcontract or hire a team member from abroad.

Since each commit that contains a new feature/bugfix will have its own tests you might want to append a diff of the test results & code coverage from the last commit. This will allow you to understand exactly what was added, removed or changed in each commit.

If you are willing to write a somewhat complex hook, a hook that verifies that every class & method that was added, modified or removed in the commit is mentioned in the commit message might be useful.

This list can grow very long and I just wrote the hooks I usually implement and some ideas I have. You are most welcome to share your own ideas in the comments.

Next Time

Next time I’m going to show you how hooks should be implemented in a much more structured way than what was suggested in the Git-SCM book.

The examples will be in Python but the theory is relevant for every scripting language.