Ramblings of an aging IT geek
← Ramblings of an aging IT geek
tooling

my dotfiles, finally in a state i'm not ashamed of

After years of a tangled dotfiles repo, I rebuilt it around a bare git repository tracking my home directory, with a clean install script and per-host overrides.

A mechanical keyboard lit beside a terminal

I have had a dotfiles repo for years. It has also, for years, been a mess: a pile of symlinks created by a script I no longer trusted, files that drifted out of sync the moment I touched a config on one machine and not another, and a bootstrap.sh that I was frankly afraid to run on a clean box. Over the holiday lull I finally sat down and fixed it, and the fix was simpler than every clever framework I had been avoiding.

The trick is the bare git repository pointed at your home directory. No symlinks, no stow, no special-purpose tool. You make a git repo whose work tree is $HOME and whose git directory lives somewhere out of the way, then you only ever track the handful of files you actually care about.

git init --bare $HOME/.dotfiles
alias dot='git --git-dir=$HOME/.dotfiles --work-tree=$HOME'
dot config status.showUntrackedFiles no

That showUntrackedFiles no line is the bit that makes it bearable. Without it, dot status drowns you in every file in your home directory. With it, the repo only sees what you have explicitly added. From there it is just git: dot add ~/.zshrc, dot commit, dot push. On a new machine you clone the bare repo, check it out over your home directory, and you are done. No install script translating intentions into symlinks, because the files are already exactly where they belong.

A code editor showing a shell config file

The other thing I sorted out was per-host differences, which is where my old setup always fell apart. The pattern that works: keep the shared config tracked, and have it source a local, untracked file at the end.

# end of ~/.zshrc
[ -f ~/.zshrc.local ] && source ~/.zshrc.local

My work laptop's proxy settings, the home server's slightly different paths, the desktop's GPU nonsense: all of that lives in .zshrc.local, which is never committed. The shared file stays clean and identical everywhere. Differences are additive and local rather than a thicket of if hostname branches in the tracked config.

It is not a clever system. That is the entire point. The old version was clever and I spent more time maintaining the machinery than the actual configs. This version is just git and a sourced local file, and after a fortnight of using it across three machines I have not once had to think about it. Which, for dotfiles, is the highest praise I have to give.