Git Yer Hooks In

Git Yer Hooks In

Git, like all good source control systems, allows you to customise the behaviour of the SCM when certain actions occur. For lots of people in lots of projects it’s not vital to use these hooks, but from time-to-time you find yourself repeating the same commands time-and-again. In these scenarios, it is worth looking into setting up a hook for your SCM to run on your behalf.

Because I’m one of the cool new generation of software monkeys, I use Git as my chosen SCM. One of the great things about Git is that it has a very simple hooks system which is both easy to understand and to use. Allow me to demonstrate.

My Example, Because It’s All About Me

To demonstrate the usage of Git hooks, I will walk through an example of a Git hook I created for my own use. This will be a Git commit hook: that is to say, an action that runs whenever I commit into a specific repository.

The repository I’ll be using today is the one in which this website is stored. This website is hosted on Heroku, which means I push and update the website using Git. For this reason, I have a vested interest in minimising the quantity of commands I run on a given update.

My particular issue was pointed out by a shall-remain-anonymous member of the PC Gamer Steam chat room, who noted that the CSS for this blog is served from S3 in an unminified format. This is less than ideal, as it increases both the time it takes to download the four CSS files and the bandwidth costs I pay to supply it to users from S3.

Of course, I want to keep the unminified files in source control, because no-one wants to have to edit minified CSS files. That means I need to balance the need to keep hold of the unminified files while supplying the minified ones. This is exactly the kind of situation where a Git hook comes in handy.

Prepare For Git Hook

So let’s consider what we need to do. I already have yuicompressor installed on my machine, so my hook will definitely use that. The way it ought to behave is that, on a commit, Git should minify the full-size CSS files, move them to the static/ directory, and then run python manage.py collectstatic to upload them to S3.

This requires that I do a few things. Firstly, I need to copy the current static files out of the static/ directory and into a new one, where there will be no name conflict. I called this directory _static/ (yeah, not an inventive name, but never mind). I then cp -r‘ed the contents of static/ into _static/. Finally, I added this new folder to the repository and committed the change.

Next, I write the script I want to run when I commit to the repository. This can actually be any executable file, but because I want to run a series of shell commands I’ve decided to just write a simple Bash script:

This script should be put in the .git/hooks directory of your git repository. Call it post-commit, and run chmod +x .git/hooks/post-commit.

This script will then run every time you make a commit into the repository. It will use yuicompressor to minify the CSS files, place them in the static files directory and then upload them to S3.

Finishing Up

Of course, this is a very simple look at Git hooks. Git allows you to place hooks on many other parts of the Git use process; in fact, I would be willing to put significant sums of money on the notion that it is Git server hooks that allow Heroku to function the way it does.

These hooks turn Git from a simple content versioning system into one that can alleviate the most repetitive tasks associated with your work flow, ensuring that boring commands get run every time you need them to be.

Happily, other good SCMs allow you to do this too: certainly, Mercurial does. This means that, regardless of what you use, you should be able to make your development life a bit easier with Git hooks. Even if all you do is save yourself and your visitors a tiny bit of bandwidth.