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.