Achievement unlocked: Autodeployment with git hooks

2017-05-02

Git is what I use for version control for this site. I started using it just because enough people suggested that I learn this tool, but it has become a major part of my workflow. Thanks to how easy it is to set up my server with remote git repositories over ssh, I also use git to coordinate my work across my various machines. Because I use it already, why not use it to automate deployment to my website?

Git provides "hooks", which are scripts that it calls when specific conditions are triggered. You can write any script for these that you like; they just need to be executable and have the name corresponding to the hook. This tutorial on Digital Ocean is the best source I found for my purposes. To automate deployment to my website, I wrote a post-receive hook in the remote repo on my server. Here's the bash that makes it work:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
#!/bin/bash
while read oldrev newrev ref
do
    if [[ $ref =~ .*/master$ ]]; 
    then
        echo "Master ref received. Deploying . . ."
        thisdir=`pwd`
        sitedir="/path/to/nathanmorrison.net" 
        git --git-dir=$thisdir --work-tree=$sitedir checkout -f
        cd $thisdir
    else
        echo "Ref $ref received. No deployment."
    fi
done

This checks whether the branch being pushed to the server repository is a master branch, and pushes the changes to the host directory if it isul. The only other thing that was needed was giving the user hosting the git server write access to the site's directory. This has already saved me minutes of time compared to logging in and manually pulling in the new files every time.

Trying to be clever and failing

The way my hook works is basically taken verbatim from the tutorial. I initially tried to do things differently by using a different command than the git checkout -f. You see, that folder has its own copy of the repository, and the forced checkout does not update that at all. I had hoped to not mess that up by doing something more similar to

cd $sitedir
git pull origin master

As it turns out, attempting this was more complicated than it was worth. As that tutorial mentioned, the environment the hooks run in is not what you would expect. Changing into the project's directory is not enough to make it recognize its .git/ directory; you have to specify it explicitly. Then I ran into the problem of calling the remotes from a different user than had initially set them up, and I decided to call it quits.

To be honest, having it set up such that the site folder need not be a git repository is probably better anyway. It's cleaner and a bit more elegant this way in addition to being convenient, so I plan to stick with it.