Git pre-receive hooks for deployment

I host this blog on a git repo that lives on the same box as the webserver. When I push to it, I want to ensure that deploys happen. Previously, it involved SSHing and doing a bit of a dance. Today, I setup a deploy-on-push script through git's pre-receive hooks. It was surprisingly difficult to find a good example of this pattern, so I wanted to publish my result.

When the pre-receive hook is invoked, it's given a line on stdin for each ref that was pushed. If the branch is master, then invoke the make publish command in the repo.

GIT_QUARANTINE_PATH is something I couldn't find tons of information about. It prevents you from modifying any of the refs during pre-receive. In general, this sounds like an awesome idea. In practice, it means that you can't check out the source files, so we have to unset it.

The GIT_WORK_TREE setup allows you to put the files somewhere as you work on them, but keep the repo where it is. This was important because when I tried to git clone, the cloned copy didn't have a reference to the most recent files.

#!/bin/bash -ex
zero_commit='0000000000000000000000000000000000000000'

while read -r oldrev newrev refname; do
    # Branch or tag got deleted, ignore the push
    [ "$newrev" = "$zero_commit" ] && continue

    # Calculate range for new branch/updated branch
    [ "$oldrev" = "$zero_commit" ] && range="$newrev" || range="$oldrev..$newrev"

    if [ "$refname" == "refs/heads/master" ]; then
        echo "Deploying..."
        unset GIT_QUARANTINE_PATH
        CO_DIR=`mktemp -d`
        GIT_WORK_TREE=$CO_DIR git checkout -f $newrev
        GIT_WORK_TREE=$CO_DIR git reset --hard
        GIT_WORK_TREE=$CO_DIR git clean -fdx
        cd $CO_DIR && make publish
    fi
done
© 2012 - 2023 · Home — Theme Simpleness