Tracking your dotfiles

/media/images/adayinbattlesmllr.jpg

Are your dofiles in order? Mine weren't.

On linux your dotfiles refer to the simple text configuration files used by most applications. They're called dotfiles because they start with a dot '.'. On unix systems this is used to specify hidden files and most filemanagers will hide these files by default.

/media/images/jesus_in_tub.jpg

Storing the dotfiles in the home directory means every user on the same system can have their own configuration. This also makes setting up a new system trivial - you can often configure every application you use with a single copy command. This is a huge improvement over windows where I would often have to spend several days tweaking things after a new install.

At current count I've got more than 50 configuration files and I've spent countless hours carefully updating and tweaking the contents. It's not a surprise I would want to keep a backup of these file and keep track of changes made over time in a version control system (VCS).

A search for keeping track of your dotfiles in git returns a huge number of articles written on the subject and a large variety of ways of doing this. Apparently there isn't one superior way of tracking your dotfiles in a VCS. I spent several hours researching methods before deciding on a solution that would work for me.

Some of the methods of tracking your dotfiles:

  • Make your entire $HOME directory a git repository. This requires setting a .gitignore file to ignore everything and then manually adding the files you want to track. It's a bit messy but it works for some people.
  • Make a dotfiles directory in your home directory. Move all your dotfiles here and then make symbolic links back to the home directory. This method requires a bash script to create the symbolic links when the directory is dropped onto a new machine. Using symbolic links makes me nervous.
/media/images/medical-inspection.jpg
  • Use hardlinks between a dotfiles directory and your home directory. This isn't recommended because some programs can break hardlinks when they update their configuration.
  • Use a git porcelain like git-home or git-host-history. This looks like a nice solution and I looked hard at the tutorial on git-home but in the end I decided against it. The author of this solution doesn't speak english as his first language and it's complicated enough I didn't feel comfortable with his explanation. This also adds another tool that will have to carried around or compiled when restoring your dotfiles on a new machine. It seems like a bit too much work...
  • A custom ruby or python solution could be used to ensure the dotfiles in your repository and HOME directory are synced. This of course adds another utility to your list of applications needed to setup a new machine. I passed on this solution because I could find ruby scripts...
  • Martin Kraft's system uses a variety of custom scripts and utilities and seems pretty advanced. In fact I decided it was too advanced. I'm not smart enough to figure how what his tools are doing or how to use them properly.

The solution I decided on uses a bash script and a dotfiles directory but with a slight difference - you use the script to copy files into your repository.

Create a dotfiles directory, initialize it as a repository, and copy dotfiles you want to track into this directory (not symlinks) along with this script.

cd ~
mkdir .dotfiles
cd .dotfiles
git init
cp -a ~/.vim ./vim
cp ~/.vimrc ./vimrc
cp ~/gitup .
git add .
git commit
/media/images/dotfilesdir.jpg

Now when you want to modify a dotfile just do it like you would normally - directly in your $HOME directory. When you're ready to commit changes to the repository, run the gitup script. This will step through all the files in the dotfiles directory, check to see if these same files have changed in your $HOME directory and if they have, will update the file in the dotfile directory. After this is done, you can commit to your source repository like normal.

A nice bonus of only updating files that already exist in the dotfile directory is this automatically ignores files you don't want. I have a usenet configuration directory that contains a 1k config file and a 300MB cache file. Since the dotfile directory only contains the config file, the script won't pull the cache file will called.

Doing the extra step before the commit is a pain but not as fiddly or error prone as some of the other solutions. Setting up a new system is then as simple as copying the files back over with another script. These are all part of the git repository so creating a branch to track files for each machine is trivial.

Finally getting this organized has sped up the development of other changes. I'm always more comfortable experimenting with system changes when I'm working with a safety net.