Automatically publish a site using Git
I've just rebuild this site using my own static generator. It would be easy to just rely on github pages to automatically publish my site but I don't want to use too much cloud services. Therefore I want to use the same technology tricks github uses but then on my own system.
I'm using Git to host the sources
of my site; some markdown files, pictures, stylesheet and html templates.
I've created a bare repository in repos/mysite.git
of my home directory
on my server.
# this is run on the server!!!
git init --bare
I've added this repo as a remote in my site's git repo and forced pushed all data.
# this is run on the system with the site's git repo
git remote add origin arnaud@myserver.sphaero.org:repos/mysite.git
git push --force origin master
You can now push changes like you do to a github hosted repo! Now for the juicy stuff
Run a script on push using Git hooks?
We can run a script on the server when we push to the repo. Inside
the repo's directory you'll find the hooks directory containing example
scripts. This is how github triggers all kinds of actions when you do
things on a repository. We need to run the script post-receive
.
In this script we need to:
- checkout the repository
- prepare the appie.py generator
- run the appie.py generator
Ok should be easy. I leave that as an excercise because, holy shit, what am I doing. If I continue this path I'm going to waste lots of resources. Didn't I say I'm into Permacomputing nowadays? If I'm not going to rely on wasteful cloud services such as Github for this simple site why stop there? I don't need to mimick what Github is doing? If I would I would be hosting 3 copies of the same repo and waste precious cpu cycles of my home server (router) as it would be regenerating the complete site from scratch including reparsing and converting all images for nothing. If you don't get what I'm saying, the site is only updated. So only new stuff needs to be added. I don't need to create all its previous files from scratch again. I could write a smarter script that only updates what was changed but I think it can be easier still. It would be better if my workstation would be doing all that because it probably already did so while creating the update for the site.
Long story short. We just need to copy new and updated generated files from the machine I'm working on to the server! A simple rsync would be sufficient!
Running rsync on push
When I push to a remote it usually means I'm done with the change. This would be the perfect moment to push the update to the live site.
In the repository where I'm working in you can find the .git/hooks
directory. In there we create the following pre-push
script.
#!/bin/bash
remote="$1"
url="$2"
rsync -irpt ~/src/my-generated-site/ myserver.sphaero.org:/var/www/mysite/
Make sure it is executable. And run a test. It shouldn't give any errors and should have copied all files.
Now push changes in the repo. It should run the script as well.
[:~/src/sphaero.org] [venv] master(+0/-0)* ± git add site_src/blog/20250101_automatic_site_publishing_with_git.md
[:~/src/sphaero.org] [venv] master(+0/-0)* ± git commit -a -m "blog about git hooks"
[master 28fee8a] blog about git hooks
1 file changed, 92 insertions(+)
create mode 100644 site_src/blog/20250101_automatic_site_publishing_with_git.md
[:~/src/sphaero.org] [venv] master* ± git push origin master
arnaud@myserver.sphaero.org's password:
arnaud@myserver.sphaero.org's password:
<f.st...... index.html
<f+++++++++ blog/20250101_automatic_site_publishing_with_git.html
<f.st...... blog/index.html
<f+++++++++ tags/git.html
Enumerating objects: 8, done.
Counting objects: 100% (8/8), done.
Delta compression using up to 16 threads
Compressing objects: 100% (5/5), done.
Writing objects: 100% (5/5), 2.03 KiB | 2.03 MiB/s, done.
Total 5 (delta 2), reused 0 (delta 0), pack-reused 0 (from 0)
To myserver.sphaero.org:repos/sphaero.org.git
b5cd0ac..28fee8a master -> master
As you can see I do have to enter the password twice. Once for the git push and once for the rsync! You can overcome this by using key authentication