Git hooks are a great way to execute something whenever a specified event happen in a Git repository. No wonder this website also uses Git hooks, mostly abusing post-receive. This post is not meant to introduce you to Git hooks, numerous tutorials have already done it better.

In my previous static blog's case, whenever a push happens i.e. the code has changed, the server generates working copy of the project, collects static files, and restarts the Gunicorn server.

Following post-receive hook shows how this happens:

#!/usr/bin/env python

import sys
import subprocess
import os

BASE_DIR = '/home/aatish/aatish.com.np'

def run_and_print(command):
    output = subprocess.check_output(command, stderr=subprocess.STDOUT, shell=True)
    print output

for line in sys.stdin:
    # Iterate over lines as multiple branches may be pushed.
    branch = line.split()[2]
    if branch == 'refs/heads/master':
    # Make sure we do this only if pushed to master
        print "Generating working copy"
        GIT_WORK_TREE = os.path.join(BASE_DIR, 'code')
        command = 'GIT_WORK_TREE=%s git checkout -f refs/heads/master' %(GIT_WORK_TREE,)
        run_and_print(command)


        print "Restarting Gunicorn"
        GUNICORN_PID_FILE = os.path.join(BASE_DIR, 'gunicorn.pid')
        command = 'kill -HUP `cat %s`' %(GUNICORN_PID_FILE,)
        run_and_print(command)

Put your hook inside your bare Git repo under hooks/ as post-receive and Git will send every line of output of this script to the client after commit has been successfully received. So, you can be sure that either the deployment succeeded or some error occurred.

You can debug this script as:

echo "hello there refs/heads/master" | ./hooks/post-receive

or you can just push an empty commit as:

git commit --allow-empty -m "Execute post-receive hook"
git push origin master

Check out the following links to better understand Git hooks: