Managing Dotfiles with GNU Stow

Sep 7, 2019 20:25 · 391 words · 2 minutes read

GNU Stow is an amazing application that streamlines the management of unix config files aka dotfiles. Last week, I converted my original rsync based dotfiles script to GNU Stow and could not be happier with the results.

TLDR: My dotfiles on GitHub

banner unsplash-logoPhoto by Fabian Grohs

Dotfiles

Modern DevOps is all about automation and reproducibility. This philosophy is the foundation of cloud infrastructure and should also be part of your daily workflow. The dotfiles page on github said it perfectly:

Backup, restore, and sync the prefs and settings for your toolbox. Your dotfiles might be the most important files on your machine.

GNU Stow

GNU Stow introduced many upgrades over traditional bash script based dotfiles scripts.

  • symlink based installation which means you can modify config in home directory
  • config files are split into separated package per application
  • useful features including verbose mode and dry run
  • high quality software maintained by GNU foundation

For each application you want to stow, simply create a folder containing the config files like this

.dotfiles/
    vim/
        .vimrc
    zsh/
        .zshrc

After installing GNU Stow with your favorite package manager, you can simply run this to symlink your dotfiles.

stow vim zsh

stow

No Folding

By default, GNU Stow will symlink top level folders into home directory. That’s ok for most applications, but it does cause some trouble when the application tries to write into the config folders. For example, when VIM writes temporary files to the ~/.vim folder, they will contaminate our git repository. The solution to this is using the no-folding option. No-folding will create all directory with mkdir and only symlink the config files. This is the stow command I use to to map configs.

for PKG in ${PACKAGES[@]}; do
	stow --no-folding --verbose $PKG
done

Conflict Resolution

GNU Stow did not provide a built-in way to resolve conflicts. This is usually not a problem after configs are installed, but it is tricky for first time users. Here is a simple conflict resolution script modified from mafrosis’s repo

PACKAGES=(
	conda
	tmux
	vim
	zsh
    # ...
)

for PKG in ${PACKAGES[@]}; do
	CONFLICTS=$(stow --no --verbose $PKG 2>&1 | awk '/\* existing target is/ {print $NF}')
	for filename in ${CONFLICTS[@]}; do
		if [[ -f $HOME/$filename || -L $HOME/$filename ]]; then
			echo "DELETE: $filename"
			rm -f "$HOME/$filename"
		fi
	done
done

You can find my personal dotfiles setup on github here