+++
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](https://www.gnu.org/software/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](https://www.gnu.org/software/stow/manual/stow.html) 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](https://www.gnu.org/software/stow/manual/stow.html#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](https://git.venberg.xyz/Gabe/dotfiles) 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 [here](http://ftp.gnu.org/gnu/stow/), 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](https://git.venberg.xyz/Gabe/dotfiles) or the repo of anyone else using stow for dotfile management. 
