Deploy static Websites with Git

2016/10/17

With the following I will describe how the deployment of a Hugo website is automated with git hooks. If you are interested in further details to git hooks I can recommend this tutorial from Justin Ellingwood.

Automation with Git hooks

To keep track of my website I have a local git repository and a remote one on the webserver. For deployment there is the branch public. Whenever there is a commit to that branch the site is rebuilt with Hugo. If the branch public is pushed to the webserver the content of the folder public within the git repository is copied to the directory of the webserver. This is all done with git hooks.

Build the Site with the pre-commit Hook

The Git hooks are located in the folder .git/hooks/ of the repository. As we want to build the site before the commit, we use the hook .git/hooks/pre-commit. If it doesn't exist create it and make it executable (chmod +x pre-commit).

#!/bin/bash
echo "*** Executing pre-commit hook"

BRANCH=$(git rev-parse --abbrev-ref HEAD)

if [ "$BRANCH" != "public" ]; then
   echo "Not on branch public."
   exit 0
fi

echo "Cleaning public directory.."
rm -r public/*
echo "Rebuild site.."
hugo
if [ $? -ne 0 ]; then
   echo "Website build failed!"
   echo "Aborting commit."
   exit 1
fi
git add public/.
echo "Site built and added to commit."
exit 0

If there is a commit to the branch public this script cleans the public directory (as Hugo won't delete possibly removed files there) and rebuild the site with Hugo. If the rebuild fails the commit is aborted.

Deploy the Site with the post-receive Hook

To deploy the site the hook my_repo.git/hooks/post-receive (from the remote repository at the webserver) is used. If it doesn't exist create it and make it executable like above.

#!/bin/bash

#
# git post-reveive hook for (Hugo) website deployment
#

WORKDIR='/var/www/my_site'
PUBLICDIR="$WORKDIR/html"
BACKUPDIR="$WORKDIR/bak"
WEBUSER='my-user'
WEBGROUP='www-data'

while read oldrev newrev branch
do
    if [[ $branch =~ .*/public ]];then
       echo "Branch public updated. Deploying website.."
        git --work-tree=$WORKDIR checkout -f public -- public
        if [ $? -eq 0 ];then
            if [ -d "$BACKUPDIR" ]; then
                rm -rf "$BACKUPDIR"
            fi
            chown $WEBUSER:$WEBGROUP $WORKDIR/public
            mv $PUBLICDIR $BACKUPDIR
            mv $WORKDIR/public $PUBLICDIR
            echo "Done."
        else
           echo "Checkout failed. Website not deployed."
           exit 1
        fi
    fi
done

If there is a push to the public branch of the remote repository this script

  1. Checks out the public folder of the Hugo site from the repository to the working directory (WORKDIR).
  2. Changes its user (WEBUSER) and group (WEBGROUP) to ensure it can be read by the webserver.
  3. Deletes the old backup (BACKUPDIR) if it exists.
  4. Moves the folder with the current website (PUBLICDIR) to the backup location.
  5. Moves the public directory to the website folder.

If the checkout fails the deployment is aborted.

tl;dr

With these two scripts a Hugo website can be built automatically with a git commit and deployed with a git push.