How I use GNU Stow to organize my dotfiles
4 mins read
Introduction
Over the past year, I’ve gone through multiple solutions for managing my dotfiles. From using bare repositories to tools like yadm. However, none felt efficient enough for my needs. Knowing how symlinks work, I remembered reading about using them to manage dotfiles and decided to explore this idea further. That’s how I discovered GNU stow.
Dotfiles
As an average Arch Linux enjoyer, I do have some configs laying around in my home directory, you can find my dotfiles repository on GitHub. Here’s how the repository is organized:
$ tree ~/.dotfiles/home/ouassim/.dotfiles├── alacritty├── flameshot├── git├── i3├── lazygit├── nvim├── picom├── polybar├── ranger├── rofi├── tmux├── wal├── zed└── zshEach directory groups related configurations, but the structure doesn’t directly affect the output.
About GNU Stow
GNU Stow might not immediately seem like a natural fit for managing dotfiles, but it’s surprisingly effective. According to its official description:
GNU Stow is a symlink farm manager which takes distinct packages of software and/or data located in separate directories on the filesystem, and makes them appear to be installed in the same place.
In simpler terms, Stow mirrors the structure of one directory into another by creating symbolic links, making it perfect for managing a version-controlled directory of dotfiles and linking them to their appropriate locations.
How GNU Stow Works
To use Stow effectively, it’s helpful to understand these concepts:
- Package: A set of files or directories to be “installed.” For dotfiles, this is a folder containing related configuration files.
- Stow directory: The parent directory holding one or more packages.
- Target directory: The location where symlinks will be created.
When you “stow” a package, it creates symlinks in the target directory that point into the package.
Let’s say I have my dotfiles repository located in ~/.dotfiles. Within this repository, I have a zsh package, containing the .zshrc dotfile:
$ pwd/home/ouassim/.dotfiles # <- repository
$ find zshzsh # <- packagezsh/.zshrc # <- dotfileThe target directory is my home directory, as this is where the symlinks need to be created. I can now stow the zsh package into the target directory like so:
stow --target=/home/ouassim zshStow will now create appropriate symlinks of the package into the target directory:
$ ls -l ~/.zshrclrwxrwxrwx 1 ... /home/ouassim/.zshrc -> .dotfiles/zsh/.zshrcNote that you can stow packages that contain several files or even a complex directory structure. Let’s look at the configuration for neovim which lives below ~/.config/nvim:
$ pwd/home/ouassim/.dotfiles
$ find nvimnvimnvim/.confignvim/.config/nvimnvim/.config/nvim/init.lua...To stow the neovim package:
stow nvimVerify the symlink:
$ ls -l ~/.config/nvimlrwxrwxrwx 1 ... nvim -> ../.dotfiles/nvim/.config/nvimRemoving Symlinks
To remove a package’s symlinks (unstow), use the -D or --delete option:
# unstow zsh packagestow -D zshThis removes the symlink:
$ ls -l ~/.zshrcls: cannot access '/home/ouassim/.zshrc': No such file or directoryIgnoring files and directories
Stow, by default, ignores certain files and directories, as defined in its built-in ignore list. You can customize this behavior by adding a .stow-local-ignore file in your stow directory.
The default ignore file includes:
# Comments and blank lines are allowed.
RCS.+,v
CVS\.\#.+ # CVS conflict files / emacs lock files\.cvsignore
\.svn_darcs\.hg
\.git\.gitignore\.gitmodules
.+~ # emacs backup files\#.*\# # emacs autosave files
^/README.*^/LICENSE.*^/COPYINGAutomating with a Makefile
To simplify the process, I use a Makefile in my dotfiles repository:
all: stow --verbose --target=$$HOME --restow */
delete: stow --verbose --target=$$HOME --delete */The --restow flag ensures outdated symlinks are removed before creating new ones. Updating or cleaning up my dotfiles has become as simple as:
make # Update symlinksmake delete # Remove all symlinksVersion Controlling Your Dotfiles
Using Git to track your dotfiles helps keep changes organized and enables easy synchronization across machines:
git initgit add .git commit -m "storing initial dotfiles"Add a .gitignore to exclude unwanted files and a README.md to document your setup.
Conclusion
I hope this has helped you understand better how to manage your dotfiles. While this method may not be for everyone, it’s my preferred approach.
You can check out my dotfiles repository here. It’s a work in progress, but it might give you some inspiration.
Thanks for reading, PEACE ✌️.