Hugo Blog Deployment

Hugo does a great job of separating out configuration, content, themes, and local overrides. Each getting their own file or directory. But it provides no deployment scripts.

For comparison, Octopress/Jekyll leaves it as an exercise for the developer to separate configuration, content, themes, and local overrides, but it provides a deployment script.

Using GitHub pages and a little bit of git wizardry and the deployment process is pretty easy.


Before you start you run hugo new site -f yaml command to create all the files and directories Hugo uses. I prefer YAML to TOML or JSON, but Hugo supports all three.

I used the following as my basic configuration.

# config.yaml
# Configure the basic behavior of URLs
baseurl: ""
canonifyurls: true

# Name the site
title: "Random Software Inklings"

# Whenever new files are written, use this format
metaDataFormat: "yaml"

# The format shown here is the same one Jekyll/Octopress uses by default.
    post: "/blog/:year/:month/:day/:title/"


Hugo has a lot of themes to choose from in the Showcase. But it is easy enough to build your own theme if you want; I went with the Icarus theme.

If you want to try a couple different themes, just download them to the ./themes diretory and use hugo -t theme-name to generate the site with that theme.

When it came time to pick my final theme, I decided to use git submodule so that I could upgrade the theme in the future without having to deal with merge conflicts.

git submodule works by marking a sub-directory as separate git repository. There are some gotchas so read the entire explanation on the git-scm site.

# Make sure you repo is clean first!!!!
$ git submodule add themes/hugo-icarus-theme
$ git add .
$ git commit -m "Adding theme"

If you need to download a new version of the blog just be sure to init the submodule.

$ git submodule update --init --recursive

Theme Overrides

If there is anything about a theme that you do not like it can be overridden. For example, I wanted Gravatar to used as my profile pick. I did this by copying ./themes/hugo-icarus-theme/layouts/partials/profile.html into ./layouts/partials/profile.html I then changed the image link to use gravatar.

<aside id="profile">
  <div class="inner profile-inner">
    <div class="base-info profile-block">
      {{ with .Site.Params.gravatarHash }}<img id="avatar" src="{{.}}?s=200">{{ end }}
      <!-- <img id="avatar" src="{{ .Site.BaseURL }}css/images/avatar.png"> -->
      ... Rest is unchanged ...

You will notice that I pull gravatarHash from Site.Params. This needs to be added to the config.yaml file.

    gravatarHash: "md5 checksum of your email address"


The hugo site has a very good tutorial on using github pages here. I used a modified version with my blog.

The blog will reside at This means the repo MUST be named, and the static site MUST be on the master branch. If you are using Hugo for project documentation then the setup is a bit different and you should read the tutorial linked above.

Knowing that Hugo generates the static site in ./public the easiest thing to do is use git subtree to track a directory as a ref. git subtree is similar to git submodule in that they both aim to make a directory of one repository a ref to another repository. The difference is that git subtree does this as a merge strategy, while git submodule does it by maintaining two separate full repos.

In my case I will be developing the blog on the draft branch, and publishing it on the master branch. For this reason git submodule is not a good fit, but git subtree is ideal.

Here is the setup.

$ git checkout --orphan master
$ git ls-files | xargs git rm --cached -f
$ ls | xargs rm -rf # remove all but the hidden .git directory
$ git checkout drafts
$ git add
$ git commit -m "Initial Commit"
$ git push origin master
$ git checkout drafts
$ rm -rf public
$ git subtree add --prefix=public origin master --squash
$ git push origin drafts
$ git subtree push --prefix=public origin master

It seems more complicated then it is. Basically, I just create an orphan branch (one not associated with the commit history of the current branch), and then I load that branch in the ./public directory of the branch I will be maintaining. That way using a single git commit will take care of both repos at the same time, and GitHub will be happy because master will have the static site.

Deployment becomes:

  1. Add and commit changes
  2. Regen site
  3. Push drafts branch
  4. Push master subtree (./public)

The following script does that taking a commit message or supplying a default.


echo -e "\033[0;32mDeploying updates to GitHub...\033[0m"

# Build the project.

# Add changes to git.
git add -A

# Commit changes.
msg="rebuilding site `date`"
if [ $# -eq 1 ]
  then msg="$1"
git commit -m "$msg"

# Push source and build repos.
git push origin drafts
git subtree push --prefix=public origin master

comments powered by Disqus