The version controlled home directory
For the last year or two i've been using SVN to store my common configuration files, this has worked wonders and has enabled me to move my config seamlessly between systems with a few simple commands. In the last day or so i've decided to move from SVN to Git as my control system, and now I think it's a time to do a post on why exactly i'm doing this. The idea of a version controlled home directory stemmed from people storing their /etc config files in CVS, this allowed for any modifications to be tracked, tested, and if worse came to worse, rolled back without much hassle. These ideas can be very useful for the end user, imagine you want to fiddle around with your terminal settings but forget to make a backup of your original settings, the time you spend trying to fix it back can be avoid with a simple vcs command. Another situation that I often get into is when you format or move to another system, a few quick commands can return your config and no pain of trying to remember your favourite settings. So, how do we do this? Each person has their own method, and hopefully I'll describe my little world to everyone in a easily digestible way. It's neither pretty or easy but it works for me. My SVN version was very simplistic, a single repository broke down into "packages", which contained the batch of config files for each program, such as "irssi" or "bash", these would live under "trunk" in the repository.
~/trunk $ ls abook gtk2 ikog keepass-private mutt ssh tin gnupg-private hamachi irssi mozilla pine ssh-private xchat
For each machine I made a new branch under "branches" then I would use the "externals" properties to pull in the packages that I needed from trunk. So, when I wanted to pull in my configuration I would simply checkout that machine's branch into a folder then symlink the required files over as needed.
~/branches $ ls ithaca manex orion vektor
This took time to setup but once the initial linking was done it was a simple matter of managing the files in the single checkout folder. This system served me well for a year or two, but with the increase of machines and the general pain of symlinks I decided I needed a new method. I reviewed a few examples but the one that stuck with me was Martin Krafft's system using Git, MR and a few handy scripts. I've now managed to rework this into a similar system for myself. First of all, you need a method of getting the configuration files in the location you require. Git has this excellent feature to having detached worktrees, this allows you to remove the need for symlinking all together. For example, we can setup a git repository in a storage directory then tell the repo to checkout the files to your home directory.
$ mkdir -p ~/.dotfiles/test.git $ cd ~/.dotfiles/test.git $ git init --bare $ git config core.worktree ../../
So now, you have the test.git repository, and the worktree is your home directory. Now it's simply a case of checking in the files you require and commit them to the repo. This scenario is a little different from the original Git idea so a little bit of a workaround is needed to actually use the repo in this way. Two variables need to be configured for Git to use the detached worktree as desired.
$ export GIT_DIR=~/.dotfiles/test.git $ export GIT_WORK_TREE=~/.dotfiles/test.git/../../
Now, you can use the Git command as if you were in a normal Git worktree. This is a pain to work with by hand but luckily Martin also created a little shell script to set these variables as needed. It's based on zsh but i'm in the process to converting this to bash to avoid a extra unneeded dependency on my part. So, we can get the configuration files to the place they need to be, now we move onto actually packaging and distributing the files. I decided that Martin's method works the best, using the mr tool you can configure and manage multiple repositories and automate the checkout and update of these. This with tool the management of your packages can be done by simply changing the config file of mr. mr supports importing extra configuration files based on wildcards, this allows for a global configuration to be setup which will only include configuration on a per machine basis. For example in the current .mrconfig I have this.
[DEFAULT] include = cat ~/tools/mr/lib/* ~/.mr/* 2>/dev/null || :
Simply put, this will include any files in my ~/tools/mr/lib/ and ~/.mr/ folder. Then in my .mr folder I have a file for each type of package I have available
[.dotfiles/mr.git] checkout = git_fake_bare_checkout 'ssh://git.tensixtyone.com/mr.git' 'mr.git' '../../' [.dotfiles/bash.git] checkout = git_fake_bare_checkout 'ssh://git.tensixtyone.com/bash.git' 'bash.git' '../../' [.dotfiles/bin.git] checkout = git_fake_bare_checkout 'ssh://git.tensixtyone.com/bin.git' 'bin.git' '../../' [.dotfiles/ssh.git] checkout = git_fake_bare_checkout 'ssh://git.tensixtyone.com/ssh.git' 'ssh.git' '../../'
So when I execute the mr command this will checkout each of those repositories as needed. If I require any extra packages I can pull in another config file and drop it into the .mr folder. Now we have the method and the configuration sorted, how do we get this onto a bare machine? Again, Martin has come to the rescue in a form of a script he has setup to do the initial bootstrapping of a fresh account, it pulls in the basic configuration for mr and then it's a case of dropping in the require config files into the .mr folder. Job done. While my system isn't perfect yet, it is workable and very flexible. The benefit of being able to move my active configuration between machines with a few commands outweighs the time needed to setup and configure the system. If you are interested my public configuration files are available via gitweb, hopefully from the mass of files you can work out what i'm doing. For the bootstrapping script check the setup.git repository, for my mr configuration files check mr.git. If your interested in setting up a version controlled home directory, I'd advise you to join the vcs-home mailing list and check out their archives and wiki. Also, remember there's no all ruling version control system to use for your home directory, Git works well for me but it doesn't for everyone. The idea is to have a system that works for you, while I've followed Martin's example very closely, again, this wont fit all.
comments powered by Disqus