# Braids: Intro to Git workshop This repo contains technical notes from the preparation for the Braids: Intro to git we gave at Het Nieuwe Instituut on Januari 15 2026 on invitation of The Hmm and NNAD as part of the workshop series "How to Archive Better: Preserving Practices". The slides for the workshop live in their own repo at: https://git.hackersanddesigners.nl/hrk/Braid-slides and are viewable at https://braids.hackersanddesigners.nl/slides/ We’ve set up a Forgejo instance (you're probably reading this there) on a Raspberry Pi, accessible over the web via Tinc. During the workshop, user account registration was temporarily open. After a short introduction to the basics of Git, participants were invited to clone the workshop repository, create a personal branch (for example braids/my-name), make a few small edits to the starter HTML page, commit their changes, and push the branch back to Forgejo. A webhook on the same machine published each pushed branch to a shared gallery site, so everyone could immediately view each other’s pages in the browser and iterate with additional commits. The Forgejo repository is configured with a push webhook that calls a small deployment script on the Raspberry Pi. When a branch is pushed, the webhook triggers the script to fetch the latest updates from Forgejo, export the contents of each participant branch, and write them to the web server directory under a per-branch path. It also regenerates the gallery index page so new or updated branches appear immediately. This provides a near real-time “publish on push” loop during the workshop. The main branch was protect to commits in the Forgejo repo settings. This involved: - [Installing Forgejo and configuring Tinc](#installing-forgejo) - [Setting up a webhook](#setting-up-a-webhook) - [Creating a script to deplay the sites](#deploying-the-sites) ## Installing Forgejo Mostly based on https://pimylifeup.com/raspberry-pi-forgejo/ with some modification because we're storing the repos on an external SSD I am going to pretend i did this in the right order. We first setup the SSD, so we can configure the proper paths rightaway. ### Set up the SSD. Create mount directory: `sudo mkdir /media/ssd ` Test mount `sudo mount /dev/sda1 /media/ssd` If it works add it to fstab To get uuid `lsblk -f` Edit /etc/fstab and add: `UUID= /media/ssd ext4 defaults,no-fail 0 2` No-fail so the raspi boot even if the disk unplugged. ### Then install Forgejo Following: https://pimylifeup.com/raspberry-pi-forgejo/ Install docker with: `curl -sSL https://get.docker.com | sh` Create user (in current user group) `sudo usermod -aG docker $USER` Logout `logout` Check if the group exist `groups` test: `docker run hello-world` Docker should now be set up. Create a directory for the installation: ```bash sudo mkdir -p /opt/stacks/forgejo cd /opt/stacks/forgejo nano compose.yaml ``` ```yaml services: server: image: codeberg.org/forgejo/forgejo:7 container_name: forgejo environment: - USER_UID=1000 - USER_GID=1000 - FORGEJO__database__DB_TYPE=postgres - FORGEJO__database__HOST=db:5432 - FORGEJO__database__NAME=forgejo - FORGEJO__database__USER=forgejo - FORGEJO__database__PASSWD= - FORGEJO__WEBHOOK__ALLOWED_HOST_LIST=private,loopback restart: always networks: - forgejo volumes: - /media/ssd/forgejo:/data - /etc/timezone:/etc/timezone:ro - /etc/localtime:/etc/localtime:ro ports: - "3000:3000" - "222:22" depends_on: - db db: image: postgres:14 restart: always environment: - POSTGRES_USER=forgejo - POSTGRES_PASSWORD= - POSTGRES_DB=forgejo networks: - forgejo volumes: - ./postgres:/var/lib/postgresql/data networks: forgejo: external: false ``` `docker compose up -d` It should now be accessible at :3000 Now we have to set up tinc proxying, but in this case it was already setup for another service. So only nginx config on the tinc edge node and creating a certificate. ` sudo certbot --nginx -d git.hackersanddesigners.nl` And configure nginx in /etc/nginx/sites-available/forgejo.conf: Set the newly created domain in the Forgejo config with: ` nano /media/ssd/forgejo/gitea/conf/app.ini` And change the domains: ``` ROOT_URL = https://git.hackersanddesigners.nl DOMAIN = git.hackersanddesigners.nl ``` And restart the service ` docker compose restart` We shoudl now have a running instance of Forgejo ## Setting up a webhook Setting up the webhook took a bit of time because it is somewhat confusing what IP to use to get from the Docker container to the host. But that is probably my inexperience with Docker. Setup web hooks like this: https://www.shawenyao.com/Voice-Controlled-Raspberry-Pi/ ` sudo apt install webhook` configure > sudo nano /etc/webhook.conf ``` [ { "id": "git-pull-site", "execute-command": "/usr/local/bin/deploy-git-site.sh", "command-working-directory": "/var/www/html/", "pass-arguments-to-command": [] } ] ``` Create the shell script ` sudo nano /usr/local/bin/deploy-git-site.sh` ```sh #!/usr/bin/env bash set -euo pipefail cd /var/www/html/testsite git pull --ff-only ``` Make it executable ` sudo chmod +x /usr/local/bin/deploy-braids.py` Edit the web hook: ` sudo systemctl edit webhook` Add: ``` [Service] ExecStart= ExecStart=/usr/bin/webhook -hooks /etc/webhook.conf -ip 0.0.0.0 -port 9010 -verbose ``` ` sudo systemctl daemon-reload` ` sudo systemctl enable --now webhook` ` sudo systemctl restart webhook` Check for errors: ` sudo systemctl status webhook --no-pager` Allow the webhook to connect to localhost, add to compose.yaml ` - FORGEJO__WEBHOOK__ALLOWED_HOST_LIST=private,loopback` We have to call the webhook on the IP of the docker host. Get it with: ` ip -4 addr show docker0` Gave: ``` 5: docker0: mtu 1500 qdisc noqueue state DOWN group default inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0 valid_lft forever preferred_lft forever ``` (if i understand correctly 172.17.0.1 is kinda standard, but i did not know that) Now add the webhook to the repo with that IP: url: http://172.17.0.1:9010/hooks/git-pull-site ## Deploying the sites The script called by the webhook is a python script that was cobbled together from a bunch of resources: - https://stackoverflow.com/questions/31261600/how-to-archive-a-remote-git-repository-programmatically-using-python - https://git-scm.com/docs/git-archive - https://www.funkycloudmedina.com/2018/10/deploy-a-hugo-website-from-github-to-s3-using-github-webhooks-api-gateway-and-lambda/ - https://www.aicodesnippet.com/python/quality-and-best-practices/basic-git-operations-in-python-using-subprocess.html - https://forgejo.org/docs/next/contributor/static-pages/ You can find the script in this repo under /code/deploy-braids.py