This post describes how to implement Git hooks using Python. If you have some commit hooks in Python or any other languages please do share them in the comments as Gists or repositories.

General Information

The Templates Directories

We have two directories that interest us:

The '/usr/share/git-core/templates/' directory on Linux and 'C:/Program Files (x86)/Git/share/git-core/templates/' directory on Windows (Note that on 32bit machines msysGit is installed by default on 'C:/Program Files/…') in which the default hooks are being copied from. If you installed Git using another configuration the installation might reside in a different folder. Adjust the path accordingly.

The '.git/hooks/' directory is the directory in which the hooks templates are being copied to.

The hooked are being copied from the '[...]/share/git-core/templates/' directory. There are other types of templates but they are out of scope for this post.

Note: If you change the templates directory the hooks directory must be a subdirectory of the templates directory. Do not set the templates directory to the desired hooks directory instead.

Changing the global templates directory

If you'd like to change the global templates directory open the terminal and type:

The global templates
directory is exclusively for hook templates. Just as we
usually don’t like to use site-packages for Python and therefore we
set up a virtualenv for containment of each project/deployment/test suite we
don’t want global business logic for our hooks, just framework code.

The .git/hooks/
directory should contain the business logic of the hooks.

Changing the repository's templates directory

You can change the
template directory when you git init or git clone using
the --template option to the desired templates directory specifically for the newly created repository.

For new repositories open the terminal and type:

For cloned repositories open the terminal and type:

Order of precedence

The hooks templates folder will be chosen by the following precedence:

The argument given with the --template option.

The value of the $GIT_TEMPLATE_DIR.

The init.templatedir configuration variable.

The default templates directory.

Starting Fresh

The default templates directory contains some examples. Each example script ends with the *.example extension. If you remove the extension they become executable git hooks.

Since we are developing using Python lets create a new templates folder. Copy the templates into the python-templates folder.

Erase the contents of the hooks folder, download this gist and extract it into the empty hooks folder.

Architecture

Hooks are simple CLI programs. That's how git works. Every git command or sub system is a CLI program.

Parsing Arguments

The Python standard library provides us with two libraries for parsing command line arguments:

Optparse - Simple but deprecated.

Argparse - Has support for everything we need including accepting STDIN as an argument which is used by git's server side hooks.

You can also use the wonderful docopt , a library that automagically parses your docstrings and generates a CLI for you. It has ports to different languages so if you are not using python, you can still use it.

Communicating with Git

Sometimes you need to access your git repository to fetch information or even modify it. Python has a library that do just that. It's called Dulwitch, A pure Python implementation of Git.

Testing Your Hooks

Testing your hooks is not hard but here are a few guidelines that might help you in doing so:

Unit Testing

Since we know git works we should mock out the dependencies that git hooks use. For example commit hooks provide the name of the file that contains the commit message as an argument.