Managing dotfiles can be tedious process, considering that configuration files for everything from
zsh are located in many different places in the home directory.
Recently, I discovered GNU Stow which is an intelligent symbolic linker (written in Perl). From Stow’s manpage, it’s official description is “a symlink farm manager which takes distinct sets of software and/or data located in separate directories on the filesystem, and makes them appear to be installed in a single directory tree”.
While Stow’s intended purpose was not to manage dotfiles, it’s features naturally lended it to being a superior choice in this regard compared to other labor-intensive methods.
Installing GNU Stow
You can download releases for GNU Stow from http://ftp.gnu.org/gnu/stow and for this guide I’ll be using the latest version which is 2.3.1 at the time of writing. The first step is to download and extract stow:
wget http://ftp.gnu.org/gnu/stow/stow-latest.tar.gz && tar -xvzf stow-latest.tar.gz
The binary for Stow has to be compiled and does require Perl, but Perl comes pre-packaged on all major distributions these days. The commands to do this are:
cd stow-2.3.1 sudo sh configure && make
If an error message about missing
Test::Output module is displayed, this must be installed using CPAN, otherwise the Stow binary won’t work. Use the following commands to achieve this:
cd # go back to $HOME sudo cpan # you may be prompted for default settings, choose [yes] install Test::Output exit
After installing the
Test::Output module, delete the
stow-2.3.1 folder and extract the archive again and rerun the build commands:
rm -rf stow-2.3.1 tar -xvzf stow-latest.tar.gz cd stow-2.3.1 sudo sh configure && make
If all goes well you’ll have a binary called
stow in the
bin directory. You’ll need to copy this binary to your PATH:
Copy binary to
sudo cp bin/stow /usr/bin
If you don’t know where to copy the binary, you can list folders that correspond to the PATH variable using the command
echo "$PATH" — the listed directories will be separated by a colon.
Once you’ve copied the binary, verify that Stow works:
That command should output the version number of Stow. If an error message is returned that resemlbes the following:
Can't locate Stow.pm in @INC (you may need to install the Stow module) (@INC contains: /etc/perl /usr/local/lib/x86_64-linux-gnu/perl/5.30.0 /usr/local/share/perl/5.30.0 /usr/lib/x86_64-linux-gnu/perl5/5.30 /usr/share/perl5 /usr/lib/x86_64-linux-gnu/perl/5.30 /usr/share/perl/5.30 /usr/local/lib/site_perl /usr/lib/x86_64-linux-gnu/perl-base) at /usr/bin/stow line 463. BEGIN failed--compilation aborted at /usr/bin/stow line 463.
Then you’ll have to install the Stow Perl module in order to fix this:
sudo cpan install Stow # and now Stow should execute without dependency errors stow --version
You can read the Stow manpages for more information, but in a nutshell Stow uses “package” folders whose directory structure correspond to the parent directory that the
stow command is run from.
Basically, the workflow involves the following steps:
- Create a directory where
stowwill store (stow) all the symlinks, e.g.
- Create subdirectories known as “packages” where
stowwill symlink data, e.g.
- Understand that whenever Stow is invoked in a directory it will target the parent directory when creating symlinks within packages, e.g. if you run
~/.zshrcwill be symlinked to
To illustrate the above workflow concepts, I’ll show you a basic example of how I use Stow to keep a few configuration files stored in one place. These are some of the files that I’ll want to manage centrally:
~/.config/audacious/config ~/.gitconfig ~/.config/extensions-sync.json ~/.zshrc
I’m going to keep all of them in a directory called
stow in my home folder. Within this directory, I’ll create subdirectories that are known as Stow “packages” and can be given any name, as they exist for organizational purposes only. Below are the “package” folders that I created:
mkdir ~/stow cd ~/stow mkdir audacious mkdir gnome mkdir git mkdir zsh
Next, I’ll move (not copy) the files from their original directories into the central location.
Apart from moving and not copying, the most important step is to match the structure of the parent directory transparently.
To illustrate this, below are the commands that I used:
cd ~/stow mkdir audacious/.config/audacious mkdir gnome/.config mv ~/.config/audacious/config ~/stow/audacious/.config/audacious mv ~/.config/extensions-sync.json ~/stow/gnome/.config/extensions-sync.json mv ~/.gitconfig ~/stow/git/.gitconfig mv ~/.zshrc ~/stow/zsh/.zshrc
And, the final locations of the files that were moved:
~/stow/audacious/.config/audacious/config ~/stow/gnome/.config/extensions-sync.json ~/stow/git/.gitconfig ~/stow/zsh/.zshrc
As you can see, the directories and files in each “package” directory are mapped as if they were children of the home (
~/) parent directory.
Now that the files and directories are in place, the next step is to invoke the
stow command from within the
~/stow directory, specifying each “package” directory by name in order to create the symbolic links:
cd ~/stow stow audacious stow gnome stow git stow zsh
After those commands are run, the old locations of the files that were copied now become symbolic links to their mapped location in the
~/stow directory, within their respective “package” subdirectories.
If I run an
l command in my home directory for example, the
.zshrc file will be shown with the syntax
.zshrc -> stow/zsh/.zshrc.
Version Control with Git
Now that my files are in a central location, it’s trivial to schedule a backup job to archive and upload Stow’s directory for safekeeping. It’s also a straightforward option to use Git to keep track of changes, for example:
cd ~/stow git init git remote add origin https://gitlab.com/oedmarap/stow.git git add --all git commit -m "GNU Stow is awesome!" git push -u origin master
- GNU Stow - http://gnu.org/software/stow
- GNU Stow Manual Pages - https://www.gnu.org/software/stow/manual/stow.html
- GitLab - https://gitlab.com