Give yor dotfiles a home with GNU Stow
Getting started.
Make sure you have already set up a dotfiles directory like I’ve described in the video called How to create dotfiles folder
In this video I’m going to assume that your dotfiles directory is located right inside your home, and it’s called ~/.dotfiles
.
You’ll also need to install GNU Stow, you can find it in the package managers of most GNU/Linux distributions with the name stow
.
If you’re on macOS, you can install it with Homebrew via the command brew install stow
On Windows, you can install Stow via the MSYS2
command shell using pacman -S stow
, but make sure you run the shell as Administrator and have the MSYS
environment variables set to winsymlinks:nativestrict
so that it creates symbolic links correctly, otherwise stow
just copies the files!
About GNU Stow
GNU Stow describe itself as a “symlink farm manager”, but in practical terms it’s just a program that can mirror the structure of one directory into another by creating symbolic links back to the original files.
This is extremely useful when you have a directory full of configuration files that is managed by Git and you want to send all of those configuration files to where they belong in your home directory.
Basic usage
Let’s say we’ve got our configuration files stored in a directory under home directory called .dotfiles
. We can easily create symbolic links to the files in this directory to the equivalent locations in the home directory using the following command:
1
stow .
Before we run that, let’s take a look at what’s already in the .dotfiles
directory and the home directory:
1
2
ls -al ~
ls -al ~/.dotfiles
Now let’s run thestow
command that I mentioned before:
1
2
3
cd ~/.dotfiles
stow .
ls -al ~
We can now see that all of the configuration files under ~/.dotfiles
, even those in child directories, have had symbolic links created!
It’s possible that you will receive an error saying that the target file or link already exists so you might need to remove existing files before this command will succeed.
How it’s works
GNU Stow walks the file and directory hierarchy of the directory passed as the first parameter to the stow command and creates symbolic links to those files in the equivalent locations in the target directory.
The important things to be aware of here is that our dotfiles directory must have the same layout
as where the files would be placed under the home directory structure in your dotfiles folder so that all symbolic links get created in the right place.
One thing you may have noticed: we didn’t specify what the target directory is! By default, stow
assumes that the target directory is the parent directory of the one that you specify.
This means that stow .
is equivalent to:
1
2
3
4
5
stow --dir=~/.dotfiles --targe=~/
# OR
stow -d ~/.dotfiles -t ~/
This means that you have full control over the source and target directories that Stow uses!
TIP: If you keep your dotfiles directory somewhere other than home folder, I’d recommend creating a simple Bash script for invoking stow with the right parameters since you’ll probably have to run it occasionally.
Ignoring files and directories
By default, GNU Stow does a good job of ignoring common files and directories you might not want to be linked back to your home directory like README
and LICENSE
files, source control folders.
Let’s say you have other files in your dotfiles folder that you don’t want to have linked to your home directory. For example, our dotfiles folder has a Notes.org
file. That really doesn’t need to be in our home folder.
To skip files like this, we can create a file in our dotfiles folder called .stow-local-ignore
. Each line of this file should be a string or regular expression representing any file or directory you don’t want to link to your home folder.
Here’s an example:
1
2
3
4
\.git
misc
#LICENSE
^/.*\.org
This will avoid linking the .git
folder (important!), a folder called mis
, the LICENSE
file, and any files ending in .org
, the latter being useful for you if you use Emacs and Org Mode to keep literate configuration files!
An important detail here is that specifying your own ignore file will override. Stow’s default ignore list! We now need to add LICENSE
to this list to ensure it doesn’t get linked.
GNU Stow Manual: Type and Syntax of Ignore lists
Cleaning up symbolic links
If for some reason you’d like to get rid of all the symbolic links that GNU Stow created in your home folder, you can do that with one extra parameter to the command we’ve been running so far:
1
stoe -D .
All of the previously-created symbolic links in the home directory will now be gone!
Don’t forget to stow
every time you sync!
One last tip I’ll mention: if you use Git to commit your configuration files to a repo that is shared between multiple machines, don’t forget to run stow
each time you sync to ensure that any new configuration files get linked into the proper location.
To make sure you never forget to do this, you can use this script I created sync-dotfiles
to automate the whole process. This script will stash current changes to your dotfiles folder, pull any new changes from the remote repo, pop the stashed changes, and then run stow .
You might consider keeping this in a bin
subfolder of your ~/.dotfiles
directory and add it to PATH!
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#!/bin/sh
# Sync dotfiles repo and ensure that dotfiles are tangled correctly afterward
GREEN='\033[1;32m'
BLUE='\033[1;34m'
RED='\033[1;30m'
NC='\033[0m'
# Navigate to the directory of this script (generally ~/.dotfiles/.bin)
cd $(dirname $(readlink -f $0))
cd ..
echo -e "${BLUE}Stashing existing changes...${NC}"
stash_result=$(git stash push -m "sync-dotfiles: Before syncing dotfiles")
needs_pop=1
if [ "$stash_result" = "No local changes to save" ]; then
needs_pop=0
fi
echo -e "${BLUE}Pulling updates from dotfiles repo...${NC}"
echo
git pull origin master
echo
if [[ $needs_pop -eq 1 ]]; then
echo -e "${BLUE}Popping stashed changes...${NC}"
echo
git stash pop
fi
unmerged_files=$(git diff --name-only --diff-filter=U)
if [[ ! -z $unmerged_files ]]; then
echo -e "${RED}The following files have merge conflicts after popping the stash:${NC}"
echo
printf %"s\n" $unmerged_files # Ensure newlines are printed
else
# Run stow to ensure all new dotfiles are linked
stow .
fi
NOTE: You might need to change the name of the
master
branch tomain
if your repository uses that instead!
Resources
- GNU Stow: GNU Stow
- GNU Stow Doc: GNU Stow Doc
Leave a Comment
Your email address will not be published. Required fields are marked *