Managing Dotfiles with GNU Stow
Sep 7, 2019 20:25 · 390 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
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
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