Idiomdrottning’s homepage

Hardlinks from a Git repo

For good reason, git breaks hardlinks. (It’d be dangerous AF if you checked out an old and crusty branch and then suddenly all files hardlinked from that repo also got old & crusty!)

For, uh, let’s call it a mix of good reasons and dumb reasons, nginx and Jekyll don’t follow softlinks.

So, and this is gonna be a hacky AF solution but it does the job hopefully, here is a shell script named gln.

#!/bin/sh
remp () {
	echo "$*" | sed 's!.*/!!'
}
dest="$2";
if test -d "$2";then dest="$2/$(remp "$1")"; fi
canonize="$(echo "$(realpath "$1")"|sed 's![^/]*$!canonize.sh!')"
echo "$(realpath "$1")"
echo "$(realpath "$dest")"
rm -v "$(realpath "$dest")"; # don't exit
cp -lv "$(realpath "$1")" "$(realpath "$dest")" ||exit 1
echo "rm -v \"$(realpath "$dest")\"; cp -lv \"$(realpath "$1")\" \"$(realpath "$dest")\" ||exit 1" >> "$canonize"||exit 1
tempf=$(mktemp)||exit 1
sort -u "$canonize" > "$tempf" # don't exit
mv "$tempf" "$canonize"||exit 1


Usage:

gln [CANONFILE] [SHADOWFILE]

For example, let’s say you have the file “foo” in the repo and you want “/tmp/bar” to be a copy of that. gln foo /tmp/bar.

The link goes both ways; edits to bar show up in foo and vice versa (it’s a normal hard link). But when git checks out old stuff, it breaks the hard links, leaving bar intact.

The file canonize.sh is created in foo’s folder. Run sh canonize.sh when you want to redo the link between foo and bar. The mental model is “OK, now foo is good, foo is fixed, I like foo, I just need to push it out to all of its various hardlinks all over the place” and that’s when you sh canonize.sh. For example, you can call it from a another publishing script.

Feel free to edit canonize.sh if you’ve made mistakes and it’s getting borked.

PS: Also put canonize.sh in your global gitignore.

PPS: for a jallon, git clone https://idiomdrottning.org/gln