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
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/. 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.
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.