Anyone using a unix-like operating system probably accumulates many text configuration files as they keep using the system and installing new programs. Maybe you are like me, and use different computers that each have their own configuration and get annoyed by the fact that your config starts to drift as you use your systems. I finally got the motivation to put my configs under version control and automate installing them into my system, resulting in a neat and quick way to have the same config on all of my systems.
GNU Stow to the rescue
As is often the case, for every problem that you might encounter on unix-like systems, there probably was someone that struggled with your issue too and already solved it. Exactly that is the case with the problem of managing your dotfiles across systems. GNU Stow is a symlink farm manager, meaning that it takes files that are spread across other directories and makes it appear like they are all located in another directory. Meaning you can store your configuration and dotfiles in a central directory, put that under version control and then symlink them all into your home directory. Because they are symlinks, you can easily edit them and your changes get reflected into your repository, meaning you can commit them and sync them across your devices.
My Setup
In my case, I created a git repository where I store my files, each directory contains the files for one tool that I use. Note that in order for stow to work as intended, the directory structure in each folder needs to match the one that should be created when symlinking it. In case of starship, the shell prompt I am currently using, the structure looks like this:
starship
└── .config
└── starship
└── starship.toml
With this structure, stow can symlink it so that it ends up in the correct place to get picked up by my prompt:
stow -t ~ starship
This links the starship.toml
that contains my settings into the correct
place. Stow also allows to remove links created by it, simply add the -D
flag
to the command:
stow -t ~ -D starship
Automating stow
One thing that bothered me was the fact that I needed to call stow for every directory containing configuration in my repository. Since that would not scale as I put more and more config under version control, I decided that I need to automate it. I whipped up a quick script that does exactly that:
#!/bin/zsh
MODE="stow"
if [[ ($@ == "--help") || $@ == "-h" ]]; then
echo "Installs all Directories found into ~ with GNU stow"
echo ""
echo "Usage: $0 [--stow|--unstow]"
echo " --stow Stow (create symlinks into ~) [default]"
echo " --unstow Unstow (remove symlinks from ~)"
exit 0
fi
if [[ "$1" == "--unstow" ]]; then
MODE="unstow"
elif [[ "$1" == "--stow" ]]; then
MODE="stow"
elif [[ -n "$1" ]]; then
echo "Unknown option: $1"
echo "Use --help for usage."
exit 1
fi
if [[ "$MODE" == "unstow" ]]; then
STOW_CMD="-D"
else
STOW_CMD=""
fi
find . -mindepth 1 -maxdepth 1 -type d -not -name ".git" | while read dir; do
stow $STOW_CMD -t ~ "$(basename "$dir")"
done
Note that I am very bad at writing shell scripts, but it gets the job done. The script runs stow for every directory found and allows to control if it should create the symlinks or remove them. Surely, one could improve the script, but it works for me. I currently manage my NeoVim configuration and my shell prompt with this approach, with more soon following. Learning about stow greatly increased my comfort in syncing dotfiles across all of my devices, which makes me a happy panda.