This post is a continuation from my previous post about Hugo Setup and Deployment. In this post, we’ll look into GitHub Actions.
First thing first, let’s sum up what we did previously:
- We created a site and generated the site’s HTML files (under
/public
folder) using Hugo. - We uploaded these HTML files to a GitHub repository called
my-blog
, and then we hosted the site by enabling GitHub Pages on that repo. - Lastly, we wrote a deployment script written in bash which can automatically generate and push the static HTML files to the GitHub repository.
Using that way, we generate the site’s static HTML files and then we push these newly generated files to the repository. So, there will be a bunch of HTML files generated on our machine over time, and we’re going to upload them all each time we wish to update the site. That’s why this is a waste.
So to avoid that, we’ll employ GitHub Actions! Well, it basically does the same thing as we did, but, instead of using our own machine, we’ll let GitHub VM/Docker instances do it for us.
I know that there are a lot of similar tutorials out there, but let me finish what I’ve started!
Goals
The only goal of this post is:
- Automate Site Deployment using GitHub Actions (I’ll try my best to explain about it!)
Prerequisites
Prerequisites are still the same, they are:
- A GitHub account
- Familiarity with CLI
- Familiarity with Git.
A Little Clean Up
Let’s start by reviewing the previous site structure, here’s where we (I) left it:
$ tree -a -L 2 -I "\.git"
.
├── .gitmodules
├── archetypes
│ └── default.md
├── config.yml
├── content
│ └── post
├── data
├── deploy.sh
├── layouts
├── public # <-- All files under this folder are hosted using GitHub Pages,
│ ├── 404.html
│ ├── assets
│ ├── categories
│ ├── en
│ ├── fa
│ ├── fr
│ ├── index.html
│ ├── index.json
│ ├── index.xml
│ ├── page
│ ├── post
│ ├── robots.txt
│ ├── series
│ ├── sitemap.xml
│ └── tags
├── resources
│ └── _gen
├── static
└── themes
└── PaperMod
20 directories, 10 files
We’ll now ignore the public folder and remove all of its content including the git repository inside it, because this will be handled by GitHub Actions later.
$ rm ./public/* -r f
$ rm ./public/.git -rf
If you happen to use the public
folder as a submodule, remove the following lines from .git/config
and .gitmodules
[submodule "public"]
url = https://github.com/your-username/my-blog.git
active = true
Clean any cached content from the public
folder.
$ git rm --cached ./public -f
Then go create another GitHub repository with the format your-username.github.io
because we’re going to use this repo as the remote repository of our blog.
$ git remote add origin https://github.com/your-username/your-username.github.io.git
For the config.yaml
, changed the baseURL value with:
baseURL: "https://your-username.github.io/"
Add the Theme as Submodule
If you happen to not using theme as submodule previously, this time we will.
Run the following command to add the PaperMod theme we cloned previously as a submodule of our site.
$ git submodule add https://github.com/adityatelange/hugo-PaperMod.git themes/PaperMod
If you don’t use the same theme, simply replace the url and directory parts to match yours.
Add GitHub Actions
On the previous post, we automated several things: site build, commit, and push our site to GitHub using a bash script. We can call the execution of this script as a workflow that runs a single job, it is to deploy our site. Each command executed within the deployment script (build, commit, push) can be referred as a step.
GitHub Actions are basically the advanced version of the deployment script we created. It’s event-driven, which means we can set a specific event to trigger the workflow. In this case, we’ll create an event that will trigger the site deployment each time we push a new commit to the main branch.
A workflow file for GitHub Actions must be written in YAML syntax, and it’s placed under a special directory called .github/workflows/[here].yml
, so let’s create the folder first inside our site repository.
$ mkdir -p ./.github/workflows
We’ll save the following code under the workflow directory with a name gh-pages.yml
(./.github/workflows/gh-pages.yml
).
name: github pages
on:
push:
branches:
- main # Set a branch to deploy
jobs:
deploy:
runs-on: ubuntu-18.04
steps:
- uses: actions/checkout@v2
with:
submodules: true # Fetch Hugo themes (true OR recursive)
fetch-depth: 0 # Fetch all history for .GitInfo and .Lastmod
- name: Setup Hugo
uses: peaceiris/actions-hugo@v2
with:
hugo-version: 'latest'
extended: true
- name: Build
run: hugo --minify --cleanDestinationDir
- name: Deploy
uses: peaceiris/actions-gh-pages@v3
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: ./public
You can study the code yourself, because I’m not the one who created it 😅. But, to make sure that the public folder always get cleaned first before build, I added --cleanDestinationDir
option.
Let’s commit this workflow and push it to GitHub.
$ git add ./.github/workflows/gh-pages.yml
$ git commit -m "Add gh-pages.yml"
$ git push -u origin main
Trigger the Workflow!
We can create a new post, then add some text to it.
$ hugo new post/test-gh-actions.md
$ echo 'Test GH Action' >> content/post/test-gh-actions.md
Finally, commit the change and push it to your repository to trigger the workflow
$ git commit -m "Trigger build"
$ git push -u origin main
To observe the deployment process/workflow, just navigate to your site repository and click on the action menu (https://github.com/your-username/your-username.github.io/actions
).
That’s it!
My Current Deployment
A bit off topic, but I’ll show you my current deployment process, not in detail, but it should give you an idea of how it was like.
My deployment process a little bit different, because I’ve separated my blog into two: blog-core, and the full static HTML site (it’s this site). The blog-core is a private repo, and the full static HTML is a public repository. The blog-core repo contains my draft, notes, and other (a lot of them), which is only available for me locally because of .gitignore
.
When a new commit is pushed on the blog-core, GitHub Actions will be triggered to generate the static HTML files. The newly generated HTML files are then pushed to the static site repo. I had to include my secret token in the blog-core so that GitHub Actions could use the token to authenticate itself.

Note: these are not the actual commands.
I’ll separate this section in a dedicated post later! nevermind lol
I found the blog post that explains about this
And here’s the Github Actions that I used