Syncing git repositories with syncthing

I have recently been experimenting with decentralizing my personal git repos by syncing them across devices using syncthing.

The idea is to have all devices automatically sync the immutable parts of .git directories, so that they all know about each other’s commits and branches.

I set up syncthing on my home server, laptop, phone, and hetzner vps.

Pushback

Q: If I already have a vps, why not just set up git there and serve?
A: First, with syncthing I’m not actually reliant on the vps. Second, I don’t keep ssh access to my hetzner on my phone. Third, syncing is automatic and almost immediate – I don’t need to initiate git pushes and pulls.

Q: Is this secure?
A: I think so? syncthing seems to be ok.

Q: Does it work smoothly?
A: So far it’s been fine, but I can’t say if it’s because my git usage is limited or naive. I generally only use basic commands: add, commit, rebase, checkout.

The code

First, here’s my .stignore file:

!.git/objects
!.git/refs/heads
!.git/refs/tags
!.git/packed-refs
!.git/hooks/post-checkout
!.stignore
*

We want to ignore anything that’s not immutable. Most importantly, we ignore HEAD – different devices don’t know what branches other devices are on, and changing HEAD on one device should not change HEAD for others.

But we also don’t want to move branches owned by other devices. I solve this by having an environment variable $MYGITNAME that I set in my .zshrc file per device, and my .git/hooks/post-checkout script reverts trying to checkout branches that don’t start with the device’s “git name”:

#!/usr/bin/env bash

branch_checkout=$3

[ "$branch_checkout" = "1" ] || exit 0
[ -n "$MYGITNAME" ] || exit 0
[ -z "$_SYNCGIT_HOOK_RUNNING" ] || exit 0
export _SYNCGIT_HOOK_RUNNING=1

current_branch=$(git symbolic-ref --short HEAD 2>/dev/null) || exit 0

case "$current_branch" in
	"$MYGITNAME"*) exit 0 ;;
esac

echo "ERROR: '$current_branch' is not your branch" >&2
git checkout -q -

On my phone I have MYGITNAME=bfg, and so I use branches like bfg/foo on it. My home server is called nn, and when I want to “pull” code from it, I just rebase bfg/foo over nn/bar. I already have nn/bar synced automatically, I don’t need to fetch.

And that’s it!