Putting Dotfiles in Git

If you’re a Windows user, then you probably won’t have come across dotfiles before. For Mac (a form of Unix) and Linux users, dotfiles hold certain environmental settings and customisations, so if you work on more than one computer, you might like a way of sharing your preferences between them.

And they’re called “dotfiles” because any filename that begins with a full stop (period) is a hidden file in Unix, Linux, etc.

Since I started using vim for text editing and made some tweaks to my .vimrc file and added some plugins (pathogen, vim-fugitive and vim-latex), I quickly realised that I’d like to be able to take these settings with me, so I started looking at keeping the configuration files in version control.

Now there are any number of dotfile repositories on github and many, many guides on setting up your dotfiles with git, but I noticed that there were two main arrangements, but the pros and cons of each arrangement seemed to be spread out around the web.

  1. Put your whole home directory into revision control and track only a few files.
  2. Add a dotfiles subfolder in your home directory that is under version control, move in the files that you want to track and symlink them back to the original location.

Which one to choose? I tried both, but I like the second best.

Why? See below:

Home Directory

Just creating a git repository of your home directory looks like the simplest solution, but you soon realise that you have to exclude a lot of files from being tracked, or you’ll be seeing lots of files listed every time you do git status. This isn’t too difficult though, just ignore every file (/*), except dotfiles (!.*), except the dotfiles that you don’t want to track (e.g. .bash_history). Now any new dotfiles will be automatically added by a git add . unless you choose to ignore them.

Except it’s not that simple. Adding a file listing to .gitignore will propagate to any other git repositories in you entire home directory. Ah. It’s not too bad though, you can just use the .git/info/exclude file for repo specific exclusions. Except that the .git/info/exclude doesn’t propagate to other repositories, so you’ll have to add the exclusions again for each clone.

Using the home directory gets worse though. If you run a git clean on this repository, you’ll remove any files in the directory that are untracked by git, e.g. every other file. This isn’t too likely in normal practice, and you’ll probably have to add -f and either -x or -X to really mess things up, but I don’t like the idea that a normal cleanup command for a repository now holds the keys to clear out all the contents of my home directory!

dotfiles Subfolder and Symlinks

Adding your dotfiles to a subfolder and then symlinking them back to the original location looks like it’ll be more complicated, but it does keep all of those files nicely separate. All you have to do is add each file to the repository once, and then any other file remains completely unaffected. You can nuke and re-create the directory without going anywhere near you other files.

The main effects of using a subfolder are that: you have to manually select which dotfiles you want to include (where as with a home directory you have to manually exclude them), but this tends to lead to more of a curated repository; and you have to add the symlinks manually for any new clone or new file on every clone.

Symlink control is probably best left to a script though, maybe even in a post-receive hook if you really trust the code. There are examples in make, ruby, and this interesting “dot files management” (dfm) program in perl. I think I’ll have to spend smae time with the dfm documentation

Leave a Reply

Your email address will not be published. Required fields are marked *

To create code blocks or other preformatted text, indent by four spaces:

    This will be displayed in a monospaced font. The first four 
    spaces will be stripped off, but all other whitespace
    will be preserved.
    Markdown is turned off in code blocks:
     [This is not a link](http://example.com)

To create not a block, but an inline code span, use backticks:

Here is some inline `code`.

For more help see http://daringfireball.net/projects/markdown/syntax

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>