Dotfiles are text files that are used to configure applications you run on the command line (in a terminal). They might tell your editor what colours to use, or what environment variables should be defined in your shell.
It can be very handy to be able to easily deploy them across multiple machines, so that the applications you use behave consistently.
Managing your dotfiles, the collection of these configuration files, is then a neat thing to do. There are several websites dedicated to different ways of organising and deploying them. I recently adopted what I think is nice way of doing it, and doesn’t seem to be that common, so I thought I’d share what I’m doing, why, and how you can organise your dotfiles in the same way.
The dotfiles repository
Let’s say you have a machine that you spend most of your time on, but
occasionally you login in to some server somewhere.
On your local machine, you’ve got a collection dotfiles sitting in your home
~/.bashrc, but they’re not on the server. What can you do?
A very common method is to create a git repository, say in a folder called
~/.dotfiles, and then to create symbolic links (or ‘symlinks’) from the
files in the repository to your home directory.
Having the folder be a git repository makes it very easy to synchronise the
files between machines.
Let’s create the git repository and add a dummy dotfile.
$ mkdir ~/.dotfiles $ cd ~/.dotfiles $ git init . $ echo "This is a dotfile." > mydotfile $ git add mydotfile $ git commit -m "Create dotfiles repository"
Now we have a repository and a dotfile within it, we just need to create the symbolic link.
$ cd ~ $ ln -s .dotfiles/mydotfile .mydotfile $ ls -la | grep mydotfile lrwxr-xr-x 1 apearce staff 19 12 Feb 17:05 .mydotfile -> .dotfiles/mydotfile
The last command shows that we have a symbolic link called
pointing to the file in the dotfiles repository. We can inspect and edit the
link as if it were the real file, but if we delete the link the real file
remains as it was.
This is essence of a dotfiles repository. But, as you can imagine, manually linking dotfiles quickly becomes laborious and error-prone. One solution is to create a script that links the files for you, but I think there’s a better way.
GNU stow, or just stow, is a symbolic link manager. To quote their homepage:
GNU Stow is a symlink farm manager which takes distinct packages of software and/or data located in separate directories on the filesystem, and makes them appear to be installed in the same place.
I didn’t understand what this meant when I first read it. I think it’s best explained with an example.
Let’s say we’re inside our
~/.dotfiles folder, but now we’ve added some files
and restructured it a little.
We can use the
tree command to recursively display the contents of the
directory as tree-like structure in plain text. (It’s not installed on OS X by
default, but you easily install it with Homebrew with
brew install tree.) The
-a flag tells
tree to show hidden files.
$ tree -a ~/.dotfiles . ├── bash │ ├── .bashrc │ └── .profile └── vim └── .vimrc
We could symlink these to our home directory in the same way as before, or we could let stow do it for us!
$ cd ~/.dotfiles $ stow vim
Now let’s take a look at what’s in our home directory.
$ ls -la ~ | grep vimrc lrwxr-xr-x 1 apearce staff 20 7 Jan 12:35 .vimrc -> .dotfiles/vim/.vimrc
Stow has created the symlink for us! Magic. So what’s actually going on?
- We ran the command
stow <dir>, where
<dir>was the name of a folder whose entire contents we wanted symbolic links for in our home directory.
- Stow looked in the folder
vim/folder in this case, and found one file:
- Stow created a symbolic link to
vim/.vimrcone folder above where the
stowcommand was run.
The last step is the cool bit. Stow assumes that the contents of the
you specify should live one directory above where the
stow command is run,
so having our
.dotfiles directory at
~/.dotfiles means using stow to
manage our dotfiles just works.
A little deeper
The original purpose of stow was to manage multiple software versions. Let’s
say you have some piece of software called
foo with which sometimes you want
to use version 1.3, and sometimes you want to use version 2.0.
Most shells will include
/usr/local/bin in their
PATH, a variable that
tells the shell where to look for programs. You could just put two programs,
foo2.0 in that folder, but you don’t want to have to remember to
foo2.0. You just want to run
foo, and you don’t want to
have to modify scripts that use
foo, so you do something cool.
$ mkdir /usr/local/stow $ cd /usr/local/stow $ mkdir -p foo1.3/bin $ mkdir -p foo2.0/bin $ mv /usr/local/bin/foo1.3 foo1.3/bin/foo $ mv /usr/local/bin/foo2.0 foo2.0/bin/foo
Now when you want to start using
foo1.3, you just use stow to set up some
$ cd /usr/local/stow $ stow foo1.3 $ ls -la /usr/local/bin | grep foo lrwxr-xr-x 1 apearce staff 20 7 Jan 12:35 foo -> ../stow/foo1.3/bin/foo
Notice that we have a directory structure inside the
foo1.3 folder, and stow
will respect that structure when making the symbolic link.
This is useful when you have an application that uses the XDG configuration
files standard, where configuration files for
foo are kept in
~/.config/foo/somefile, because then your dotfiles repository uses the same
folder structure as in your home directory.
$ tree -a ~/.dotfiles . ├── bash │ ├── .bashrc │ └── .profile ├── foo │ └── .config │ └── foo │ └── somefile └── vim └── .vimrc
stow foo inside the dotfiles folder will then create a symbolic link
~/.config/foo/somefile, creating any intermediate directories that don’t
If you want to delete a set of symbolic links, just run
stow -D <dir>.