I am a programmer and architect (the kind that writes code) with a focus on testing and open source; I maintain the PHPUnit_Selenium project. I believe programming is one of the hardest and most beautiful jobs in the world. Giorgio is a DZone MVB and is not an employee of DZone and has posted 638 posts at DZone. You can read more from them at their website. View Full User Profile

A simple strategy for dotfiles

05.22.2013
| 3469 views |
  • submit to reddit

Simple as in Simple Object Access Protocol. Dotfiles such as .vimrc and .bashrc are at the core of configuring a Unix system. They are usually places in the home folder of a user and, if present, are read by various tools such as the shell and Vim.

After having written (and rewritten) many dotfiles in the last years, I've gathered here a few strategies for storing and porting them between machines.

Versioning

For a while I tried putting my dotfiles into a Dropbox subfolder, symlinking the stored versions to the original place:

ln -s ~/Dropbox/dotfiles/.vimrc ~ 

However, unless you are always online and never use a pc on a train or on a plane, Dropbox cannot scale as it is not capable of solving conflicts. Given the plain text format of these files, we can treat them as source code and version them with the same tools that store Java and PHP code.

mkdir .dotfiles
mv .vimrc .dotfiles
ln -s ~/.dotfiles/.vimrc .
cd .dotfiles
git init
git add .
git commit -m "Added .vimrc"
git remote add origin git@github.com:giorgiosironi/dotfiles.git
git push -u origin master

Hosting dotfiles on GitHub is common (I learned it from @bittastic) and we usually do not have trade secrets embedded in them. It's not really an open source move as it's difficult to reuse uncommented tricks embedded in someone else's dotfiles; still, it relieves you from backups and the setup of private Git repositories.

Git submodules

Once you have jumped into Git, you can use its submodule capabilities to pull in other repositories for simpler updating of external dependencies (such as Vim plugins). Here is my Vim Pathogen installation:

[08:04:10][giorgio@Galen:~/.dotfiles]$ git submodule
c1646e3c28d75bcc834af4836f4c6e12296ba891 .vim/bundle/ctrlp.vim (1.78-67-gc1646e3)
22b4f2073bf16679b31578bb64289ea304573e47 .vim/bundle/snipmate-snippets.git (heads/master)
d209d220358d67d630c6f166d277b88ed9e480c6 .vim/bundle/snipmate.vim (heads/master)
ac67114efa4f436a3580f5cbb3168aaa13011fc8 .vim/bundle/syntastic.vim (2.2.0-513-gac67114)
...

Some of these modules were actually dependencies of one of the plugins. I didn't find a better solution than installing them alongside their dependent module as there is no Composer or npm for .vim bundles. Or is there?

Installation script

Once you're porting the dotfiles from one machine to another, it becomes boring to create all the links by hand. Furthermore, you may also have to perform additional actions such as a git submodule update -i.

So store a simple .sh script at the toplevel of your dotfile repository, which does the following:

git submodule update -i
ln -s ${PWD}/.vimrc ~
ln -s ${PWD}/.bashrc ~
...

Linking one or two files may not seem an hassle, but as their number grow and you start producing virtual machines instead of physical ones, it's the only solution that scales.

Template method

Your files aren't probably going to be perfectly identical on all machines. In some you may need to look for commands in different paths; or defining different AVA_HOME variables.

As an example, consider my need for setting up differently colored prompts on different machines (for example red or green). It's a surefire way to distinguish which machine you're logged in and it's faster than reading the hostname in the prompt: one shell with a red prompt next to other 3 with a green prompt really stand out as that production server where you should be careful in running commands.

The Template Method pattern can be applied with dotfiles too; you do not even need to define an hook method to be called in external files, but often just environmental variables.

In the case of coloring prompts, .bashrc contains:

C_RED="\[\033[0;31m\]"
C_GREEN="\[\033[0;32m\]"
C_LIGHT_GRAY="\[\033[0;37m\]"
C_RESET="\[\033[0m\]"
COLOR=${C_RESET}
source ~/.bash_prompt
PS1=$COLOR

The installation script performs a:

touch ~/.bash_prompt

And after an empty file has been produced you can put a customization in there:

COLOR=$C_RED

If you do not need to override the prompt color on that machines, there is still a default (COLOR=${C_RESET)) so that the setup script always creates a valid combination of dotfiles without further intervention being necessary.

Some .bashrc examples

Don't know what to put into your .bashrc? Here are some examples:

# Aliases for frequently used or long commands
alias agi='sudo apt-get install'
# Adding folders to the path to use some additional binaries
PATH="~/bin:${PATH}"
# Exporting environmental variables which will be available to all scripts
JAVA_HOME=/usr/lib/jvm/java-6-openjdk/
export JAVA_HOME
# Grep default options, that you don't have to type with the command
export GREP_OPTIONS='--color=auto'
GREP_OPTIONS=
for PATTERN in .cvs .git .hg .svn .work; do
  GREP_OPTIONS="$GREP_OPTIONS --exclude-dir=$PATTERN"
done
export GREP_OPTIONS

The .vimrc would take a lot more to explain, and can be an article (or a book) by itself...

Published at DZone with permission of Giorgio Sironi, author and DZone MVB.

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)