administration Uncategorized

Finally putting my personal configuration files under version control

Version controlling your config files, it seems to be like flossing: everyone knows it’s a good idea and they should be doing it, but never get around to do so. I finally got around to put my files under version control – again. I used to use darcs, but I ran into the dreaded exponential merge issues, so this time I’ll try git for this. Mercurial would have been an even nicer choice, but git seems to have a bigger mind share these days and is a bit more difficult to learn, so I’d rather learn some git.

While having your personal config files under version control is a good idea, making your home directory version controlled isn’t – it’s not easy to see what files are under version control, and some operations just take ages because they have to crawl through your all your personal files. So I created a git controlled directory, named “.vc” and did symbolic links from there to the config files locations. As I add more files to version control, this will get tedious to do by hand, so I wrote a little script to help me that I want to share with you: I just called it “setup” and put it into .vc as well:

#!/bin/sh
cd $(dirname $0)
VC_DIR=$(pwd)
find . \( -path \*/.git \) -prune -o -type f -not -name "$(basename $0)" | \
    while read path; do
        if [ "X$(basename "$path")" = "X.git" ]; then
            continue
        fi
        destination="$HOME/$path"
        if [ -e "$destination" ]; then
            if [ -L "$destination" ]; then
                echo "Symlink for $path exists, skipping."
                continue
            else
                echo "backing up existing $destination to ${destination}.vc_backup"
                mv "$destination" "${destination}.vc_backup"
            fi
        fi
        echo "doing symlink for $path"
        ln -s "$VC_DIR/$path" "$HOME/$path"
    done

4 Comments

  1. Ignore files help a lot when you want to avoid crawling huge and largely irrelevant subdirectories of $HOME.

    My first commit at $HOME/.hg/ about a year ago was:

    $ hg log -r0
    changeset: 0:51a27c91da6a
    user: Giorgos Keramidas
    date: Sun Feb 10 22:34:41 2008 +0200
    summary: Initial revision: ignore everything by default in $HOME dirs.

    This was just an .hgignore file that ignores ‘**’, the pattern that matches any file in any subdirectory.

    Then I “hg add”-ed only the files that I want to track. A short script that prints pairs of {rev, number of files} pairs shows that I have been slowly increasing the number of tracked files since last year. I started with only one file (the .hgignore file) and have reached 400 files now:

    $ hg log –template ‘{rev}\n’ -r 0:tip | \
    while read rev ; do \
    echo “${rev}” $(hg manifest “${rev}” | \
    wc -l | awk ‘{print $1}’) ; \
    done | \
    awk ‘BEGIN {ofiles=0;}
    { if ($2 != ofiles) {
    printf ” {%d %d},”, $1, $2;
    ofiles=$2;
    fflush();
    }
    }’
    => {0 1}, {1 2}, {2 8}, … {497 399}, {500 400},

    Running “hg stat” is almost instantaneous, even though my entire $HOME is quite a few GB now:

    $ time hg stat
    M .newsrc
    M .newsrc.eld

    real 0m0.796s
    user 0m0.407s
    sys 0m0.381s
    $

    This is for a different version control system, but my intuition says not traversing ignored subdirs should be ‘fixable’ in other VCSs too.

  2. Good point, I haven’t thought of that. But the symlinking-approach still has some potential advantages: it’s immediately apparent what files are under VC; I can have several repositories, e.g. a repository that I want to make public, and one for private data. Fortunately, emacs sees that the symlinks lead to version controlled files, so this is only mildly inconvenient. But still, good point.

  3. A valid argument for the symlinking-approach: you can easily opt-out if you want to use a differing config file on some host for some odd reason, so you don’t have to worry about unintentionally updating some file if you don’t want to.

  4. managing multiple repositories is the only scenario for such a script.

    i’ve rewritten this tool to support this feature.
    it can be found along with an explanation at http://struction.de/projects/dotVC

    until my need for that feature using the suggested .htignore hack worked fine.

Comments are closed.