Deploying with git hooks

25 Mar 2014

Update: this still works, but you probably want to use this hint instead.

If you have a git repository that you’d like to deploy to a remote server by pushing it, there’s a few things you’ll have to watch out for.

Specifically, if you try to just push the repository and leave it at that, you’ll notice that the files never get updated. This is because the working tree is not updated when commits are pushed to the repository, unless you make special arrangements for that to happen.

To make these arrangements, you need to use hooks to provide instructions for git as to what it should do and when. There’s a massive amount of flexibility here, but for the simple case of updating the working tree after a push, you want the post-receive hook.

The hook scripts live in a hooks directory inside the (hidden) .git directory. They’re simple scripts, so you can write them in any language you want that can be called from the shell. But usually they’re just written in normal shell script: sh, bash, whatever.

But the real twist in this is that you might think you could just do a git reset --hard HEAD in the post-receive hook and your working tree would update and everything would be kittens and daffodils. But you’d be gravely mistaken.

The problem is that when the hook is run, the GIT_DIR and other variables are pointing inside the .git directory itself. This means that if you do the aforementioned git reset, you will pour a copy of your working tree in the wrong place, inside the .git directory. Even worse, if some of your files happen to overlap the names that git uses to track the state of the repository, you now have completely screwed your repo’s state of mind.

So how to avoid this? Well, in short, just use this script:

#!/bin/bash
test "${PWD%/.git}" != "$PWD" && cd ..
unset GIT_DIR GIT_WORK_TREE
exec git reset --hard HEAD

This will do what you want, in the simple case of updating the working tree after a push, which is perfect for updating a website on a remote server. You could add some commands at the end for kicking your webserver or application server if you need to, in order for it to realize something changed.

Enjoy!