How to keep "dot files" under version control?

Etckeeper is a great tool for keeping track of changes to your configuration files in /etc. A few key things about it really stand out. It can be used with a wide variety of VCSs: git, mercurial, darcs, or bzr. It also does auto commits daily and whenever you install, remove or upgrade package. It also keeps track of file permissions and user/group ownership metadata.

I would also like to keep my "dot files" in my home directory under version control as well, preferably bazaar. Does anyone know if a tool like etckeeper exists for this purpose?

Worst case, I imagine that a simple cron job running bzr add && bzr ci once or twice a day along with adding ~/Documents, ~/Music, etc to the .bzrignore Anyone already doing something similar with a script?

While I'd prefer bazaar, other options might be interesting.


Solution 1:

I did not know if there was anything that did this so I whipped up some code to achieve exactly what you want using my repository here: http://github.com/robertmassaioli/config-files

I have a file that says where all of the files belong and the generate_links program just puts them all there. If you know what you are doing and can compile some Haskell code then it is really simple and easy. Though be warned that it really was made for my own personal use.

Solution 2:

Well, I went ahead and did this manually until I find a better solution. So I might as well explain what I did.

First I did a bzr init ~, but the next thing I did was bzr ignore "*". I decided that I didn't want to keep the entire thing under version control. It just wasn't worth it, especially when you consider that there are some things in there that you really shouldn't keep in vcs like your keys. So I then had to bzr add the specific files I wanted. You can also add exceptions to .bzrignore. Python regular expressions are useful in there as well. I'm keeping it pretty slim for now. If all goes well, I might add all of ~/.config and ~/.gconf too.

I also wrote a quick script that I run as a cron job. It checks if the files have changed, and if so does an automatic commit:

#! /bin/bash

set -e

TIME=$(date)
STATUS=$(bzr status)

if [ -n "$STATUS" ]; then
    if [ -n "$1" ]; then
         bzr ci ~ -m "$1"
    else
        bzr ci ~ -m "Automatic commit on $TIME"
    fi
fi

exit

Solution 3:

I turned my whole ~ directory into a Bazaar repository. Storing metadata is not an issue for files in the home directory: everything is owned by the same account and group, and bzr already stores the execution bit.

I manually add the "interesting" files to it (I do not want, e.g., my music collection or the firefox cache to be under version control), but if you want to automate this with a script, I think it the simple solution of doing bzr add && bzr ci on selected directories or on the output of a find command will just do the job.

Solution 4:

I keep my zsh and vim files in git, put on github, in different repositories:

for zsh, for example, i created ".zsh" and put zshrc and zshenv into it, plus a script to link zshrc to ~/.zshrc and zshenv to ~/.zshenv, something like this.

while true
do
read -p "do you want to link zshenv to ~/.zshenv (Y/N)" yn
case $yn in
    [Yy]*) ln -s ~/.zsh/zshenv ~/.zshenv; break;;
    [Nn]*) break;;
    *) echo "please answer yes or no";;
esac
done

while true
do
read -p "do you want to link zshrc to ~/.zshrc (Y/N)" yn
case $yn in
    [Yy]*) ln -s ~/.zsh/zshrc ~/.zshrc; break;;
    [Nn]*) break;;
    *) echo "please answer yes or no";;
esac
done

so i do

git clone git://[email protected]:tshirtman/.zsh
cd .zsh
./init.sh

for .vim, it's almost the same, except i use submodules for plugins, with pathogen, so i added that in the init.sh

git submodule init
git submodule update

and when i want to add a vim plugin, i do

git submodule add git://github.com/nathanaelkane/vim-indent-guides.git bundle/vim-indent-guides

for example.

ok, it would require a bit too much work if you have more than a few dot dirs you want to manage, but nothing prevent you to put them all in the same dir, or seperated by activities (on for all graphical editors, one for web activities…) or so. anyway, that's what i did, so just my two cents :).

Solution 5:

I use a solution that isn't automatic like etckeeper (I have to manually commit), but it has worked well for me. It's not quite as developed as I like, but it works.

I've wrote my own utility that is similar to GNU Stow, as stow didn't do all that I wanted. I call it Stow in Home. When ran, it looks for a directory named "HOME". It then takes everything under that directory and symlinks it to the corresponding location in $HOME, creating directories as necessary. It also will translate filenames -- if a file starts with a '_', it will be replaced with a '.'. I did this because it is nicer for editing my dot files when they aren't hidden (see them in directory listings by default). Then, it would put them in the name their application expects.

So, I have several git repositories for my configuration. I only put dot files that I personally edit in them. The advantage of this is that I can have a repository for dot files that I can share with others (like my Emacs configuration) and one for others that are private (say, my ssh config, with hostnames and such for work). The symlinking puts with stow-in-home puts everything in the right place, but the source control for each can be separate.

It has worked well for me. There really is no reason I couldn't set something up to automatically do commits. Or move all dot files into the appropriate repositories and still use stow in home. But this is how I've done things.