For those of you not familiar with these technologies, Pelican is a static site generator (meaning you can write your content in a format such as Markdown, and Pelican will automatically generate the HTML files for you), and GitHub Pages is a service provided by GitHub for hosting a website under the <your-username>.github.io URL.
Using Pelican and GitHub Pages is quite easy. There's one annoying little thing though... GitHub Pages assumes
master branch contains the root folder to be served to the world. If you're using the Pelican defaults, the
folder is the folder you want to serve.
output is a subfolder leaving aside other important folders such as the
content folder (containing the posts Markdown files). A natural choice of how to organize the files inside the repository
would be to save the pelican's root folder (the parent of
output) as the root of the repository. But GitHub Pages needs
output to be the root. Bummer...
There are those who solve it using two separate repositories: one for the website "source" files, and one for the output which will be served using GitHub Pages.
I personally don't like breaking my blog into two repositories. I want to keep everything in one place, so I chose to solve the problem using branches and git hooks.
The first step is to create two branches:
sourcewill contain the blog's "source" files, namely - all the files such as the
masterwill contain only the
These branches will obviously live in my GitHub Pages repo
and since the
master branch contains the
output's contents, a user navigating to yoel-zeldes.github.io
will be presented with the goodness of my blog.
Manually maintaining these two branches is cumbersome. Git hooks to the rescue!
Git has a way to fire off custom scripts when certain important actions occur. In my case, whenever I push a commit to the
I'd like the
master branch to get updated with the new
output contents. This can be done using the pre-push hook, which is executed,
you guessed it, just before a push occurs.
Just create a file named
.git/hooks/pre-push with the following content:
#!/bin/sh while read local_ref local_sha remote_ref remote_sha do if [ "$remote_ref" = "refs/heads/source" ] then echo 'pushing output folder (production version) to master...' pelican content -o output -s publishconf.py echo anotherdatum.com > output/CNAME ghp-import output git push --no-verify email@example.com:yoel-zeldes/yoel-zeldes.github.io.git gh-pages:master pelican content -o output fi done exit 0
- The first thing the script does is iterating over the commits that are about to be pushed. Specifically, only commits that are pushed to the
sourcebranch are of interest to us.
- If commits are pushed to
source, we run
publishconf.py(so we make sure
outputwill contain the production version of the blog).
- It then creates a
CNAMEfile (which is needed since I use a custom domain).
- The GitHub Pages Import tool is used for copying the content of
outputto a branch named
gh-pagesis pushed to the remote
--no-verifyskips the pre-push hook so this script won't run again.
pelicanis executed again so the development version of my blog will be available for writing the next post.
Now, whenever I push to
source (and only to
master gets updated with the new contents. Cool!
One last small detail: I added
output to the
.gitignore file. This way, the
source branch won't include this folder
(we don't really want to put it under version control - it would be like putting other types of derivative files such as
.o under version control).