Managing my dotfiles with Stow


For years I have, apparently, not been managing my dotfiles. I thought I had but when I went to check, the folder containing them was not a git repository. Dotfiles are one of those sorts of cart-and-horse problems where, on a fresh install, you need your dotfiles in order to be able to get access to your dotfiles. So I likely downloaded a zip of my repo, and promptly forgot about them when they were working. That's classic me, if ever I heard it.

If you didn't know, dotfiles is a colloqial programmer term for the little hidden files in your home directory that configure a bunch of things. If you've ever opened your terminal and installed something from Github, you likely have ~/.ssh, ~/.config, ~/.gitconfig but when you work in your terminal all day, you amass quite a few of those things and it makes a noticeable difference when you reinstall your OS and they're not there. And so, dotfiles tend to be one of those invisible reliances that has apparently become a bit of a science.

The way I was running it was to have a repo, then use a little Ruby script to create all the symlinks that matched the repo. I basically reinvented Stow but worse (and, I suppose, by "worse" I mean "only fit for my immediate purposes"). I saw a YouTube video the other day, introducing Stow (it's really crazy how much some people can drag these things out to a ten minute video) - in a nutshell, what it does is take a directory argument and create symlinks to files one directory up, with some useful (and sometimes annoying) nuances.

The reason these nuances can be useful is your SSH directory. You do not want to store ~/.ssh in a git repository that will live anywhere public (and yes, private github repos are public in this context. An encrypted USB flash drive in your wallet, however, is not). Usefully, Stow will not symlink directories that already exist - so if you have ~/.ssh and ~/dotfiles/.ssh/config, then you will end up with a symlink in ~/.ssh/config rather than ~/.ssh, like this:

├── config -> ../dotfiles/.ssh/config

Which is very useful for shimming your SSH config into your ~/.ssh directory.

However, if you use tmuxinator, you will also have ~/.tmuxinator which holds all your project configs. You don't want to have to run stow every time you create a new project config, so you don't want Stow to fold here (folding, as far as I can tell, is the process of shimming your symlinks into a directory structure at the leaf, rather than the directory. Stow doesn't have the concept of a .stow-no-fold file or something which would allow you to selectively fold certain directories whilst leaving others alone.

Lots of people have come up with lots of different, crazy solutions to this, but I favour simplicity (not technically true - I favour something that will do what I want without me having to become an absolute specialist for an afternoon), so I've gone with a simpler alias in my fish config that runs Stow once without folding, removes the directories that I want to fold, then runs it again with folding enabled. Stow will ignore everything that already exists, but create everything else (i.e. just the removed directory) and I can get on with my day. That looks like this:

alias stowme="stow --no-folding -d ~/dotfiles -t ~ .; and rm -Rf ~/.tmuxinator; and stow -d ~/dotfiles -t ~ ."

The -t ~ . bit is a bit strange - in Stow, you pass a target directory, and then specify a package within that directory. In my case, those two are the same directory, so ~ points it at my home directory, and . tells it to use that directory again. Bit redundant but I can see why it's available as an option.

And that's all. It's pretty nice to work this way, but it unfortunately did shine a light on how disorganised I was being here. I had so many SSH keys in my home directory, which have now been ported to 1Password and updated where they needed updating. That was an evening well-spent.

If anyone reading this has a better way of doing any of this I would love to hear it. Optimising this kind of housekeeping is something I find very satisfying. Probably because it feels like work, but isn't really. Got to love a bit of procrastination!

Some recent pictures I'm getting so sick of reading about how the EU is messing with Apple and iOS. I'm no Apple...