Sooner or later, every linux-user has to deal with keeping track of configurations (configs). These can be configs for specific software, for processes and services, or for individual environments and contexts. Keeping track of your configuration allows you to re-use a well written config, to go back to a working configuration when things go awry, and to move safely and methodically between systems.
git
A natural approach to managing your config is to employ some sort of a version-control system like git
. A rather elegant and nifty method first (as far as I can tell) documented by Nicola Paolucci in this article, is to use bare git repositories. And this is exactly how I started, many many moons ago. While the system worked well, it was cumbersome, and involved remembering a lot of intermediate steps any time I wanted to edit a config file. Searching for an alternative, I realised that there are, in fact, a number of actively developed, open-source tools for configuration management.
chezmoi
In Linux, configurations are usually stored as dotfiles - i.e., files with names starting with a dot (e.g., .zshrc
or .profile
). Thus, most configuration management tools often have names like dotbot and dotdrop. One of the most successful and comprehensive dotfile management tools in use today is chezmoi - and after browsing through articles written by serious programmers with needs far beyond my own, this is what I moved to next. After about 6 months of use, I realised that chezmoi
was exactly what it says on the tin - a no nonsense, highly specialised tool for complete and total config control. While I found chezmoi
to offer more options than I will ever need, I found its interface to be demanding. It is a serious tool, and it required me to make a 24/7 commitment to config tractability - something that I am starting to believe myself incapable of. I obviously like to maintain a well documented and tractable system configuration, but the pressures of day-to-day life often end up pushing it very low down my priority list.
stow
Enter GNU stow. I have been using stow
for almost 3 years now, and, combined with git
, it is easily the most straightforward way to deal with configuration management I have experimented with. stow
is an old, old (at least older than 2001) utility used to manage “symlink farms”, i.e., it specialises in keeping track of large symbolically linked directory structures. While stow
obviously has a number of important use-cases (it was not developed to manage dotfiles), its ability to seamlessly mount and unmount entire symlink hierarchies makes it an excellent tool for config management. There are many articles which describe how to use stow
for this purpose, and here, I will only give a very quick and cursory overview of how I personally employ it.
stow
stow
stores configurations in units, and each unit is stored in a separate directory. The file-structure within each unit can then be symlinked to a different base-directory in the filesystem. This is best illustrated using an example. I will use a typical scenario: configuring zsh
. A simple and mostly sufficient approach is to use a ~/.zshrc
file with all the aliases, environment variables and all sorts of voodoo you’d want in your terminal prompt. To stow
your zsh
configuration (a unit), you create a directory for it (say, ~/config/zsh
) and move all your configuration (in this example, the file ~/.zshrc
) inside this directory - taking care to preserve the relative directory-tree. Note that you might want to make a backup if you’re following along.
$ mkdir -p ~/config/zsh
$ cp ~/.zshrc ~/.zshrc.backup
$ mv ~/.zshrc ~/config/zsh
stow
We have now created our stow
for zsh
in ~/config/zsh
! However, if you try to open a zsh
terminal, your configuration will obviously be missing. To activate (i.e., symlink) the config, the stow
needs to be deployed. To deploy a stow
we need to know where it is located (option -d
or --dir
), and which target base-directory you’d like the symlink-tree to be built on (option -t
or --target
). In our example, the directory where the stow
is located would be ~/config
, and the target directory would be ~
. We can now deploy the stow
we have created for zsh
using:
$ stow -d ~/config -t ~ zsh
This creates a symlinked file ~/.zshrc
. Invoking a zsh
terminal now works as expected. What is more, since most modern editors can follow symlinks, visiting ~/.zshrc
will allow you to edit your configuration stow
-ed in ~/config/zsh/.zshrc
.
To extend this illustration, let us suppose that you have too many aliases in your zsh
config, and you store them separately in ~/.zsh/aliases
(typically this would be sourced by your .zshrc
). How do you stow
your zsh
config in this case? Remember, the idea is to simply re-create the intended relative directory-tree in your stow
. So, in this case, in addition to ~/config/zsh/.zshrc
, your stow
would also contain the file ~/config/zsh/.zsh/aliases
. The stow
can be deployed as before, using
$ stow -d ~/config -t ~ zsh
It will symlink the local file-structure in ~/config/zsh
atop the target directory ~
- creating two symlinked files: ~/.zshrc
and ~/.zsh/aliases
.
stow
s and version-controlAs a final extrapolation of the example, now imagine you also want to store a configuration for direnv
and perhaps another one for firefox
. Following the previously outlined steps, you create the stow
s at ~/config/direnv
and ~/config/firefox
. While you don’t have to use the same base-directory (i.e., ~/config
), I would recommend you do so, as it makes version-control easier. In our example, you could version-control by simply initialising a git
repository in ~/config
, i.e.,
$ cd ~/config && git init
You can now version-control all your stow
s (i.e., zsh
at ~/config/zsh
, direnv
at ~/config/direnv
, and firefox
at ~/config/firefox
) at once! Finally, the new stow
s can be deployed simultaneously using:
$ stow -d ~/config -t ~ firefox direnv
Voilà, you now know the basics of dotfile management using GNU stow
!
NOTE: If you do end up using stow
, you might also want to look at other options like --verbose
, --simulate
, --delete
and --restow
. And remember kids, RTFM, always.