Keeping my $HOME in git.
Living in Git, or Why are we Here?
Over time I've accumulated a massive amount of built-up configurations and other cruft in my home directory, and whenever I need to bring a new computer online I have to copy my desktop configuration to it, like a game of software config telephone. (this happens to me more often that you'd think, as I have a number of Raspberry Pi boards I use as desktops until I have a need for it in an embedded solution). I figured there had to be a better way, using the tools I picked up as a developer. Turns out there is :-)
I remembered A Long Time Ago™ reading about Joey Hess writing etckeeper to keep the configuration files in /etc/ under, ahem, control. I also remember vaguely seeing similar software for home directories, but those software projects are lost to years of imperfect memory, and so I couldn't find them. Hence, my writing a new one.
Other Implementations
There are probably many, many, many implementations to keeping your home directory in git. Most of them would probably even work for my personal setup, but NIH and all. So I wrote my own! I'm actually kind of proud of it, but if the gods are kind it stays pretty much the way it is for the foreseeable future, as I've settled somewhat in my 'config' churn and am running Debian Stable anyway so my software shouldn't be changing its config syntax weekly.
Conceptual Design
My requirements are the following:
- the configuration files should be in version control
- the configuration files must be able to be kept separate from the live config files
- the script must be able to be executed on any system I might call home (this means POSIX compliant shells, such as DASH, or perl)
- ideally, allows symlinking so as to make changes easily pushed upstream
Implementation
To achieve this, I went with git for version control. This allows me to utilize the git setup framework I already had installed for my software projects (it's here if you're interested). It's also quite well documented and recipes exist for almost every scenario on either Server Fault or reddit. I initialized a new git repository on my server for this to live in, calling it l-homedir after a bit of self-serving names :-)
In my shiny new git repo copy, I moved (as in mv) the interesting and non-private configurations into it. I maintained the directory structure you would find in my home directory (for example, my .zshrc file is in $REPO_ROOT and my nvim config lives in $REPO_ROOT/.config/nvim). This allows me to separate the files I care about from those that I do not care if get lost, or those that contain private information (ssh private keys and such).
To accomplish the copying/linking files (linking in this case) I wrote a mildly complicated shell file, and a corresponding config file. linked_files contains a list of files I want to maintain here---in case something accidentally ends up in the repo. make_links is the shell script. The script follows this basic flow
- iterate over each line in linked_files
- if it is blank or starts with a hash (#) ignore it
- check if the file already exists?
- if the file already exists, is it running in destructive mode?
- if in destructive mode, rm the original file, otherwise skip it
- if skipped, return to Loop Top
- ln -s the file in the repository to the home directory
- Return to Loop Top
I wrote a README and brought in a license file to top it off, and I have a shiny new home-in-git solution :-D
I want it!
Assuming you're not trolling me, get it right here