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.
-
Put your whole home directory into revision control and track only a few files.
-
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