techWebsite/content/posts/dotfile-management.md

5.8 KiB

+++ title = "Dotfile Management with GNU Stow" date = 2023-07-29T16:37:34-05:00 draft = false +++

So I've been using git to managing my dotfiles since [checks git log]... 2018. At first, I was going to write some inevitably brittle shell script to handle symlinking from the dotfile repo to where each file should be, but before I got about to implementing it, I discovered stow. Now, after using stow for dotfile management for over 5 years, I figure I should really document exactly how I go about managing my dotfiles, with an aim to help other people who want to have an easy to manage dotfiles repo that can be quickly deployed on new machines.

What Stow does

stow is a 'symlink farm manager', but I almost prefer to think of it a simplistic package manager that makes it incredibly easy to create packages from scratch. Like most of the gnu project utility, the documentation covers a lot, but is a bit intimidating if you don't already know the software.

At its core, if you are in directory ~/foo, containing a directory bar, which itself contains some files and folders like so:

~
└── foo
    └── bar
        └── .config
            └── bar
                └── bar.cfg

cd ing into foo and running stow bar will symlink the contents of bar into ~, resulting in a file structure looking like:

.
├── foo
│   └── bar
│       └── .config
│           └── bar
│               └── bar.cfg
└── .config -> ~/foo/bar/.config

now, stow does a neat thing called tree folding, so if you make another 'package' in foo, so the file tree looks like:

.
├── foo
│   ├── bar
│   │   └── .config
│   │       └── bar
│   │           └── bar.cfg
│   └── baz
│       └── .config
│           └── baz
│               └── baz.config
└── .config -> ~/foo/bar/.config

then running stow on baz, (stow baz) will result in:

.
├── foo
│   ├── bar
│   │   └── .config
│   │       └── bar
│   │           └── bar.cfg
│   └── baz
│       └── .config
│           └── baz
│               └── baz.config
└── .config
    ├── bar -> ~/foo/bar/.config/bar
    └── baz -> ~/foo/bar/.config/baz

stow realized that both bar and baz had .config in common, and turned it into a real directory, and remade the symlinks one level lower. Stow calls this tree folding. It can do the reverse, as well, running stow -d bar will result in:

.
├── foo
│   ├── bar
│   │   └── .config
│   │       └── bar
│   │           └── bar.cfg
│   └── baz
│       └── .config
│           └── baz
│               └── baz.config
└── .config -> ~/foo/baz/.config/baz

It detected that .config was no longer shared, and unfolded the tree, making .config a direct symlink again. Note that if .config contained files that stow doesn't 'own', it would leave it alone, only deleting the 'bar' symlink when stow --delete bar was run.

In short, you can think of stow taking a folder, and symlinking the contents of that folder exactly 2 levels up the directory tree, symlinking ~/foo/bar/contents directly to ~/contents.

Ok, how do I use this to manage my dotfiles?

So now you know how to stow operates, you can make a 'package' for every program you have dotfiles for. Id encourage you to take a look at the directory structure of my dotfiles repo if you want more examples of the directory structure you should aim for.

Once you have the file structure down, all you need to install on a new machine is git and stow, git clone your dotfile repo, cd into it, and stow the folders for the software you want to install configs for.

Non-stow considerations

Stow helps you manage your configs, but nothing else. A lot of your more complex configs probably require other software beyond the program that reads that config. For example, my terminal emulator config needs a specific font installed, my i3 config requires specific programs installed for which keybinds are defined, my neovim config needs things like wget, gzip, python, cargo, xsel, fzf, and others for things from treesitter to clipboard support.

Id encourage your repos readme to have a section on each config package that has external dependencies, explaining what dependencies are needed, and if the dependency is only needed for a single functionality, what functionality they add and what part of the config to comment out if the functionality is not needed.

Id also recommend you create a directory called scripts or something similar that is not a stow package, but is put on your $PATH by your .zshrc / .bashrc / .fishrc / the dotfile for whatever shell you use. This is for you to put any scripts you develop that may be called by/aliased by your configurations.

Bootstrapping

Stow can be found on pretty much every Linux distributions package manager. If for some reason it is not, building from source is... surprisingly easy.

You can find the source http://ftp.gnu.org/gnu/stow/[here], download stow-latest.tar.gz, and decompress it with tar xvf stow-latest.tar.gz. cd into the uncompressed folder, and simply run autoreconf -iv, ./configure, and make. The binary will be in ./bin/stow free for you to move it into your $PATH.

Conclusion, or something

So, that more or less explains how I manage every bit of text-based configuration on my machine. Again, Id highly recommend you check out my repo or the repo of anyone else using stow for dotfile management.