Article summary
If you’ve done much work with command line tools, you’ve undoubtedly wrestled with dotfiles, those pesky configuration files in your home directory that are hidden from view by having a dot at the beginning of their name. Bash uses a .bashrc
configuration file. Vim uses a .vimrc
file and a .vim
directory for additional scripts. Tmux uses a .tmux.conf
file. Git uses a global .gitconfig
. Untold other tools follow the pattern.
Dotfiles are indispensable for configuring your system, so it’s helpful to have them in a single, version-controlled directory. Since Vim, Bash, Tmux, and friends don’t know to look in your dotfiles directory, you’ll need to symlink from your home directory to each file’s actual location. Managing those symlinks for all your dotfiles can be a pain, and there are several tools designed especially for helping manage your dotfiles. The best tool I’ve found so far is GNU Stow1.
Basics
Stow allows you to collect dotfiles into various packages that can be symlinked as a group. If you’re in a ~/dotfiles
directory with a git
subdirectory, you can run stow git
and Stow will symlink all the files in ~/dotfiles/git
into the home directory.
In general, Stow symlinks files from packages into the their grandparent directory. If you’d like to symlink them elsewhere, use the -t
option, which allows you to specify a target directory for creating symlinks.
Managing Project Dotfiles
Stow’s -t
option is incredibly useful for me, because not only do I rely on dotfiles in my home directory, but in many project directories as well. I put project-specific Vim scripts alongside the source code in a .vimlocal
file. I create a project workspace in Tmux by running a .tmuxrc
file. I have scripts related to my workflow in a directory called (for some reason) .rj
.
All these project-specific dotfiles are scattered across my source code directories. Since they have to do with my preferences and not the team’s, I don’t check them into the source code, which means if I delete the project directory for any reason, I won’t have my scripts when I re-clone the repository.
Thanks to Stow, I can move all these project dotfiles into one version-controlled directory and delete my complex system of scripts for backing up my precious configuration files. Here’s how.
I’ve created a directory called project-dotfiles
and within it a directory for each project with dotfiles I want to preserve. Then I moved the dotfiles from my various project directories to the corresponding subdirectory in project-dotfiles
. For each project, I ran Stow with the project directory as the target and the project dotfiles directory as the package. For instance,
stow -t ~/code/awesome-project awesome-project
Stow symlinked the files in project-dotfiles/awesome-project
to ~/code/awesome-project
.
Next Steps
You can also create files that are shared between projects. Suppose you want to include a Vim script useful for Ruby on Rails projects. You can create a ruby-on-rails
subdirectory in project-dotfiles
, then run
stow -t ~/code/ruby-on-rails-project ruby-on-rails stow -t ~/code/some-other-project ruby-on-rails
and Stow will symlink the files in your ruby-on-rails
package into two different project directories.
One of the best side-effects of using Stow and symlinked dotfiles is that you can edit dotfiles the same way you do now, and the changes show up in your centralized directory, ready to be committed to version control.
Stow has not only cleaned up how my home directory dotfiles are organized, but my project dotfiles as well, and it’s allowed me to delete several scripts I was using to manage all those dotfiles. Everything is a lot more well-organized when it’s properly Stowed.
1 Thanks to Brandon Invergo for bringing it to my attention.
Hey thanks for this.
Your post inspired me to spend some time creating a dotfiles repo (powered by stow) and documenting how i setup a system.
Future me also thanks you :)
I really do love the simplicity of stow for managing dotfiles, however, I’ve run into a potentially deal breaking situation.
In the case where stow is trying to symlink a file that already exists, it gives this error:
WARNING! stowing ssh would cause conflicts:
* existing target is neither a link nor a directory: .ssh/config
All operations aborted.
Any suitable workaround that doesn’t involve manually deleting the files before running stow?
I have a script that first moves files into a package directory, then calls stow to set up symlinks. Consider stow a tool rather than a toolchain.