Managing dotfiles with GNU Stow (2024)

Managing dotfiles with GNU Stow

Many developers manage their user-specific application configuration – alsoknown as dotfiles – in a version control system such as git. This allowsfor keeping track of changes and synchronizing the dotfiles across differentmachines. Searching on github, you’ll find thousands of dotfilerepositories.

As your dotfiles are sprinkled all over your home directory, managing them ina single repository is not trivial, i.e. how do you make sure that your.bashrc, .tmux.conf, etc. that life in your dotfile repository appear inthe proper places in your home directory? The most common solution is to usesymlinks so that the .tmux.conf in your home directory is just a symlinkpointing to the appropriate file in your dotfile repository:

$ ls -l ~/.tmux.conflrwxrwxrwx 1 venthur venthur 34 18. Dez 22:53 /home/venthur/.tmux.conf -> git/dotfiles/tmux/.tmux.conf

This leads immediately to another problem: how do you manage the symlinks? Forthe longest time I just manually maintained the symlinks on the variousmachines, but this approach does not scale well with the number of dotfilesand machines you’re using this repository on. Often, people write their ownshell scripts that help them with the maintenance of the symlinks, but atleast the solutions I’ve seen so far did not convince me.

Last year I stumbled upon GNU Stow, an unpretentious little tool thatdoes not reveal at first sight how useful it would be for the job. Thedescription on the website says:

GNU Stow is a symlink farm manager which takes distinct packages of softwareand/or data located in separate directories on the filesystem, and makesthem appear to be installed in the same place.

Right.

How does it work?

In stow’s terminology, a package is a set of files and directories thatneed to be “installed” in a particular directory structure. The targetdirectory is the root of the tree in which the package appear to beinstalled.

When you “stow” a package, stow creates symlinks in the target directorythat point into the package.

Let’s say I have my dotfiles repository in ~/git/dotfiles/. Within thisrepository, I have a tmux package, containing the .tmux.conf dotfile:

$ pwd/home/venthur/git/dotfiles$ find tmuxtmux # the packagetmux/.tmux.conf # the dotfile

The target directory is my home directory, as this is where the symlinksneed to be created. I can now stow the tmux package into the targetdirectory like so:

$ stow --target=/home/venthur tmux

and stow will create the appropriate symlinks to the contents of the packageinto the target directory:

$ ls -l ~/.tmux.conflrwxrwxrwx 1 venthur venthur 34 2. Jun 2021 /home/venthur/.tmux.conf -> git/dotfiles/tmux/.tmux.conf

Note that the name of the package (i.e. the name of the directory) does notmatter as stow points the symlinks into the package, so you can chooseit freely. I usually use the name of the program that the configurationbelongs to as the package name.

Your package can also contain several files or even a complex directorystructure. Let’s look at the configuration for neovim, which lives below~/.config/nvim/:

$ pwd/home/venthur/git/dotfiles$ find neovimneovimneovim/.configneovim/.config/nvimneovim/.config/nvim/init.vim$ stow --target=/home/venthur neovim$ ls -l ~/.config/nvimlrwxrwxrwx 1 venthur venthur 41 2. Jun 2021 /home/venthur/.config/nvim -> ../git/dotfiles/neovim/.config/nvim

At this point we should mention that the target directory for my dotfiles willalways be my home directory, so the contents of the packages are either theconfiguration files or the directory structure as they live in my homedirectory.

Deleting a package from the parent directory

You can also remove (unstow) a package from the target directory again, usingthe --delete parameter:

$ ls -l ~/.tmux.conflrwxrwxrwx 1 venthur venthur 34 18. Dez 22:53 /home/venthur/.tmux.conf -> git/dotfiles/tmux/.tmux.conf$ stow --target=/home/venthur --delete tmux/$ ls -l ~/.tmux.confls: cannot access '/home/venthur/.tmux.conf': No such file or directory

Stowing several packages at once

Since your dotfile repository will likely contain more than one package, itmakes sense to combine the individual stow commands into one, so instead ofstowing everything individually,

$ stow --target=/home/venthur tmux$ stow --target=/home/venthur vim$ stow --target=/home/venthur neovim

you can stow everything at once:

$ stow --target=/home/venthur */

Note that I use */ instead of * to match all directories (i.e. packages),since my dotfiles repository also contains a README.md and a makefile.

Putting it all together

My dotfiles repository contains a makefile that allows me tocreate/update or delete all symlinks at once:

all: stow --verbose --target=$$HOME --restow */delete: stow --verbose --target=$$HOME --delete */

The --restow parameter tells stow to unstow the packages first beforestowing them again, which is useful for pruning obsolete symlinks from thetarget directory.

Et voilà! Whenever I make a change in my dotfiles repository that involvescreating or deleting a dotfile (or a package), I simply call:

$ make

and everything is updated. To delete all dotfile-related symlinks from thismachine, I simply run:

$ make delete
Managing dotfiles with GNU Stow (2024)

References

Top Articles
Latest Posts
Article information

Author: Terrell Hackett

Last Updated:

Views: 5653

Rating: 4.1 / 5 (52 voted)

Reviews: 83% of readers found this page helpful

Author information

Name: Terrell Hackett

Birthday: 1992-03-17

Address: Suite 453 459 Gibson Squares, East Adriane, AK 71925-5692

Phone: +21811810803470

Job: Chief Representative

Hobby: Board games, Rock climbing, Ghost hunting, Origami, Kabaddi, Mushroom hunting, Gaming

Introduction: My name is Terrell Hackett, I am a gleaming, brainy, courageous, helpful, healthy, cooperative, graceful person who loves writing and wants to share my knowledge and understanding with you.