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.