Manage and Share Your Dotfiles with rcm

The Weekly Iteration

This video is only a short sample, but you can access the full version and all our other great content by subscribing.

Video

Notes

Background

All of the dotfiles are in /Users/gabe/.dotfiles rather than in /Users/gabe. Thus, none of the programs on the system can find the files (like zshrc) yet. rcm will symlink those files from /Users/gabe/.dotfiles into /Users/gabe.

You can find rcm installation instructions in the rcm README. If you're on OS X and you have Homebrew installed, you can do this:

$ brew install thoughtbot/formulae/rcm

rcm relies on a few commands to work its magic. The first one is lsrc.

lsrc

lsrc is just like ls, but for your dotfiles (or "rc files"). It doesn't link anything, so it's safe to run as many times as you want -- there are no side effects. lsrc prints out a huge amount of output by default, so let's see how to read each line. Each line is split by a colon and has this format:

/Users/gabe/.curlrc:/Users/gabe/.dotfiles/ctags

That line means "rcm would symlink /Users/gabe/.curlrc to /Users/gabe/.dotfiles/ctags". (Remember, it's not actually symlinking anything yet.)

In the output, there are a lot of vim backup files that shouldn't be symlinked. Let's use lsrc's -x flag to ignore them:

lsrc -x backups

There's still a lot of output. Let's ignore some more things:

lsrc -x backups -x bundle -x undodir

By ignoring these directories that have thousands of files inside them, lsrc finishes a lot faster. Now it's totally ignoring the backups, bundle, and undodir directories too, though. I don't want to symlink the files inside those directories, but I actually do want to symlink the directories themselves. That way everything can find the backups by following ~/.vim/backups, but the backup files will live in ~/.dotfiles/vim/backups, and rcm won't have to symlink thousands of files. I can do that with -S to symlink the directories but nothing inside them:

lsrc -S backups -S bundle -S undodir

They were totally ignored before, but rcm will now symlink the directories and none of the files inside them. It's one symlink instead of thousands.

rcup

Now that we know exactly what's going to be symlinked, we can do the actual symlinking with rcup. rcup conveniently takes the same flags as lsrc. I also use the -v ("verbose") flag so that rcup prints exactly what it's doing:

$ rcup -v -S backups -S bundle -S undodir
...
'/Users/gabe/.dotfiles/zsh/colors.zsh' -> '/Users/gabe/.zsh/colors.zsh'
'/Users/gabe/.dotfiles/zshenv' -> '/Users/gabe/.zshenv'
...

Note that the zshenv file in the .dotfiles directory has no leading dot, but rcup adds the leading dot for us to .zshenv in the symlink. This makes it so that the files you edit in .dotfiles are regular non-hidden files, but the symlinked files are still detected by Zsh, Vim, etc as dotfiles.

rcup will detect files that are already symlinked and identical and do nothing. If the file is already there (for example, if you already have a .zshenv file), rcup will ask you if you want to overwrite it. This is great because it means that rcup by default is safe: you can run it and it won't destroy any files that you may have forgotten to manage with rcm. It also saves a little bit of time.

rcdn

If, after running rcup, you want to remove all of your files, or start over, you can run rcup's counterpart command rcdn ("rc down").

$ rcdn -v
removed '/Users/gabe/.agignore'
not a symlink, skipping: /Users/gabe/.zsh/rails.zsh
...

Just like rcup, rcdn is safe by default: if something isn't a symlink, it won't remove it. When first starting with rcm, you may run rcup then rcdn quite a bit until you figure out exactly what what you need.

Structuring your dotfiles

rcm allows you to use a tag system to split up your configuration using any system you'd like. I use it to store e.g. all of the tmux-related configuration (for Zsh and Vim) in one place instead of split up across my zsh and vim directories. It's very handy for pointing new tmux users at one place and letting them copy it over to their system. It also makes the dotfiles directory much more organized.

Each file in (e.g.) tag-ruby will be symlinked as if tag-ruby were in the root. So /Users/gabe/.dotfiles/tag-ruby/gemrc will be symlinked as /Users/gabe/.gemrc, not/Users/gabe/tag-ruby/.gemrc. This also means that for example, the files in tag-ruby/vim will be copied into /Users/gabe/.vim, just like the files in the top-level vim/ directory. This allows me to split up my vim configuration across multiple tags.

Installing tagged files

rcm ignores tags by default unless we explicitly tell it to install files from that tag. We can use the -t flag to indicate which tags to symlink:

$ lsrc -t ruby

And we can use rcup to symlink the files:

$ rcup -v -S backups -S bundle -S undodir -t ruby

Configuring rcm

If your dotfiles are public, you might want to put the specific rcup commands you run in a shell script so people don't have to guess at which flags they should use. An even better idea is to use rcm's built-in configuration file, named rcrc.

Here's an rcrc that behaves exactly the same way as
rcup -S backups -S bundle -S undodir -t ruby:

SYMLINK_DIRS="backups bundle undodir"
TAGS="ruby"

You can use EXCLUDES to mimic the -x flag:

EXCLUDES="README.md install.sh"

I use these to avoid copying files that don't make sense as dotfiles, like the README for the repository, or the install script.

Before you run rcup, the rcrc isn't symlinked yet and so rcup doesn't pick up on it. In order to use it the first time, you can run rcup like this:

RCRC=rcrc rcup

This tells rcup to look for the rcrc file in the current directory and fixes the chicken-and-egg problem.

Further reading

You can see Gabe's dotfiles at gabebw/dotfiles.

Plus, check out our Weekly Iteration on dotfiles.

×

15 Full Courses, 100+ Screencasts & New Content Weekly