At the end of last semester I became serious about managing my home directory with some form of version control so that I could keep files somewhat synchronized across multiple computers.
Versioning $HOME provides several benefits from my perspective:
- Making a backup is as easy as a new checkout of your $HOME.
- Distributed version control systems make it easy to eliminate single points of failure.
- A distributed VCS will also provide a built in backup mechanism that is temporal and spacial (that is as far back as you've been using the VCS and as distributed as your computers are).
The only con i have encountered so far is that it takes quite a bit of thought to plan how you want to setup your repositor(y|ies).
I ended up going with the dVCS git as it is very robust and fast. I also have more experience using it than any other DVCS. Most of the concepts I show should easily apply to any distributed system with a little tweaking. Some things I've discovered git does well that I had not anticipated:
- Using SHA1 sums for identifying content works well to ensure integrity of files.
- An efficient packing structure ensures that each file is only stored once.
- Bash completion (under Ubuntu) is very convenient and can be adapted to improve the workflow I now use.
When I started playing with versioning $HOME, I put all files into one big repository. I quickly realized this was not the best solution as it made managing of config files harder than I wanted; for example, I have three computers I use regularly: one is a dual-head desktop, one a T60, and one is an EEE 900. Because of the different configurations of hardware, my .conkyrc is slightly different for each. The logical solution is to have a separate branch for each machine, each with a different .conkyrc. The problem comes in when I also manage my coursework in the same repo. The coursework is agnostic as to what hardware I'm running, and thus must be the same across all branches. If I were to merge changes from one branch into another, it would also merge the .conkyrc. An alternative to merging would be cherry-picking changes or using stgit to maintain the patches. I chose a different, more flexible solution.
Each logical set of files has its own git repo. My dotfiles have their own repo. As these are not going to change often, the hassle of cherry-picking changes is reduced, and the expense of a separate branch for each computer is reduced to something I will tolerate. The set of coursework can remain on a single branch for all machines (or one branch for each semester if I wish to hide older coursework). My resume has a branch for each employer I submit a custom resume to. Overall using multiple repositories to manage my $HOME works well with few hiccups.
To do this I created a few different repos, and then added a few bash aliases to streamline the process of maintaining the repos.
I'll go through the steps I performed to create the repo for my dotfiles. All commands were run in ~/
- Initialize an empty repository with: git --git-dir=.config.git/init
- Add some dotfiles: git --git-dir=.config.git/ --work-tree=. add .bash_logout .bashrc .profile
- Commit the changes: git --git-dir=.config.git/ --work-tree=. -m "Bash dotfiles"
- Edit .bashrc and add the following alias line: alias config='git --git-dir=$HOME/.config.git/ --work-tree=$HOME'
This will create a git repo for your home directory and allow you to use all of the normal git commands without --git-dir or --work-tree by substituting 'config' for 'git'. For example I can see a change log by typing config log.
The only thing left to do locally is to add bash completion to your bashrc. In the default Ubuntu bashrc there is a conditional:
if [ -f /etc/bash_completion ]; then
that loads the bash completion file for the system. After this line all routines defined by the git bash completion scripts will be available. Inside the conditional I added the line:
complete -o default -o nospace -F _git config
which enables bash completion for the config command. Save your changes and open a new bash instance to reload the changes.
Where to go from here:
- Setup a remote git repository to share your local repo with your other computers.
- Setup SSH Keys to save yourself from entering the password each time you push/pull from your remote(s).
- Setup a cron script to use git-archive to create snapshot tarballs, and encrypt/email them to a gmail account.
- Let me know if you find this useful or improve upon any techniques I've developed.
Update: Silas Sewell has written a great article expanding upon what I wrote here. He's taken what I have done a step further to use GitHub as a remote repository.