One reason for migrating to static site generation is that the site becomes more straightforward to keep in version control systems such as git. And I do like version control; I naturally ran
git init before I ran
In my workflow, once I have made and committed changes locally, I push the changes remotely. But now I need to build and deploy the new version of the site. What if I could get that to happen automatically?
To do this, I set up my web server to accept git commands; this is a topic unto itself which I might write about some time.
I then create a bare repo:
git init --bare blog.git
After setting permissions as appropriate, I can now push my git repo to the web server:
git remote add origin https:[email protected]/git/blog.git git push -u origin master
I then modified an example git-hook I found on the Jekyll website to be more robust and meet my needs. There are a few things to take note of here:
- I switched from using the
git-receivehook as per Jekyll’s recommendation to
post-receive. This is because the level of info
git-receive, ahem, receives seems a bit overkill —
post-updateprovides the names of the modified branches, and that’s all we need.
DEPLOY_REF_REGEXis a regex that matches git-refs, such as branches. The value in my script means that it’ll only deploy the website when changes are pushed to
master. This means you are free to experiment on non-
masterbranches. I haven’t gone so far as to deploy different branches different places!
GIT_REPOis the path to your site’s git repo. Ensure it can be read by the webserver.
PUBLIC_WWWis where the website needs to be deployed to be visible on the web. Ensure it is writable by the webserver.
To use this hook, create a file called
post-update in your remote bare repo’s
hooks directory. Ensure it is executable by your webserver!
#!/bin/bash # Builds and deploys blog when new commits are pushed to the specified branches (default master). # # Despite the Jekyll site recommending to use the post-receive hook, we do not # need the level of information that post-receive gets. post-update receives # each ref that was updated as an argument, and so is sufficient for this # script's needs. # # The script also adds the commit ID of the deployed commit to the site, so you are able # to tell exactly what is live by visiting /deployed_commit. # # Originally taken from: http://jekyllrb.com/docs/deployment-methods/#git-post-receive-hook # DEPLOY_REF_REGEX=refs/heads/master GIT_REPO=/shared/code/git/blog.git PUBLIC_WWW=/var/www/blog DEPLOY= for ref in "$@"; do if [[ $ref =~ $DEPLOY_REF_REGEX ]]; then DEPLOY=true break fi done if [ $DEPLOY ]; then TMP_GIT_CLONE=$(mktemp -d) git clone "$GIT_REPO" "$TMP_GIT_CLONE" echo $(GIT_DIR=.git git -C "$TMP_GIT_CLONE" rev-parse HEAD) > "$TMP_GIT_CLONE/deployed_commit" jekyll build -s "$TMP_GIT_CLONE" -d "$PUBLIC_WWW" rm -Rf "$TMP_GIT_CLONE" else echo "Updated refs did not match; not deploying." fi exit
You’ll get output like the following:
$ git push Counting objects: 4, done. Delta compression using up to 4 threads. Compressing objects: 100% (4/4), done. Writing objects: 100% (4/4), 3.15 KiB | 0 bytes/s, done. Total 4 (delta 2), reused 0 (delta 0) remote: Cloning into '/tmp/tmp.TkcxSnfVnb'... remote: done. remote: Configuration file: /tmp/tmp.TkcxSnfVnb/_config.yml remote: Source: /tmp/tmp.TkcxSnfVnb remote: Destination: /var/www/blog remote: Generating... remote: done. remote: Auto-regeneration: disabled. Use --watch to enable. To https:[email protected]/git/blog.git df05e56..ce42b80 master -> master
If the deploy succeeds, then website should be available on the internet and you are done! If the deploy fails, the push will be cancelled and you’ll need to investigate why that might be. I would first check the permissions on all of the directories mentioned above.
Finally, as a little bonus, the script creates a
deployed_commit file which contains the commit SHA of the commit the build was based on; useful if something goes wrong or you just want to check what you last deployed. You can even check my site’s deployed commit!