All blog posts that explain how to publish your site sources to github.io from a Hakyll build suggest to use the _site
directory as a git submodule. After a few experiments, I came to the conclusion that doing this can lead to some trouble. I explain in this post why, and detail the workaround I use instead.
Most of the times, you build your site sources with:
cabal run build
and all is perfect. The directory _site
is updated and, in case you declared _site
as a submodule, everything is fine and the contents of the submodule are correctly updated. The only precaution to take is to be sure that _site
is not on a ‘detached HEAD’ state.
Imagine now that you run instead:
cabal run rebuild
In this case, you can notice that hakyll first wipes out the directories _cache
and _site
. What happens then? git-submodule is now wrecked out, and, because _site/.git
has been deleted, the directory _site
is considered as a standard subdirectory in your source tree instead of a submodule! Indeed, if you go in the directory _site
and for example run git remote -v
, you will see that origin
points to the location of you Hakyll source tree, not to the location of your github.io
repository where you push the source site files!
Why did this happen? Because the rebuild
process first involves the deletion of the _site
directory. Hence the .git
subdirectory.
Hopefully you can recover from this situation. Go to the Hakyll source tree and run:
git submodule udpate --remote
To avoid this problem, it is necessary to use two separate directories for the build directory used by Hakyll, and the git submodule used to push the files of your website to github. Hakyll uses _site
as a build directory, and I created a submodule in site
.
To summarise, the build/update process involves these steps:
- hakyll build
- set your build submodule (e.g.
site
) to the default branch (e.g.master
) - sync
_site
to your build submodule (e.g.site
). Do not delete the.git
subdirectory! - git push to github
I pushed all of this in a minimalist Makefile
(my submodule lies in site
):
.PHONY: build rebuild watch
build:
cabal run $@
rebuild:
cabal run $@
watch:
cabal run $@
push: rebuild
git submodule update --remote --merge
rsync -avr --delete --exclude='.git' _site/ site/
cd site \
&& git checkout master \
&& git add . \
&& git commit -m 'site update' \
&& git push origin master
git add site
git commit -m 'site update'
git push origin master