Open Source

Manage dotfile configuration with subversion

Vincent Danen shows you an easier way of managing your "dotfiles," those customized configuration files for various CLI programs that you use frequently. In order to manage them and keep them up-to-date on differing systems and computers, subversion offers a solution.

If you are at all like me, you have customized configuration files for various CLI programs, so-called "dotfiles" such as ~/.zshrc or ~/.vimrc. If you use more than one computer system, you probably re-use these dotfiles on many of them. Unfortunately, this can make management of the dotfiles, and keeping them up-to-date on differing systems, challenging. Particularly if you use them on a large number of computers.

One solution is to use version control to manage these files, such as with subversion, CVS, or git. This can easily be accomplished by making a subversion repository for storing these files. For instance, on a "master" system that is accessible by the others (via ssh, perhaps), create the repository and store the files in it. A working copy of the repository might exist in ~/svn/configs/ with sub-directories for each type of dotfile: ~/svn/configs/zsh, ~/svn/configs/procmail, ~/svn/configs/zsh, and so on.

Using subversion as a means of distributing these files to varying computers works well, but copying files and keeping them up-to-date may be cumbersome. You could use symlinks so that the actual dotfile points to the working copy: such as symlinking ~/.zshrc to ~/svn/configs/zsh/zshrc.

Another method is to use the standard "make" command to manage them. This solution takes a bit of time to set up at the outset, but only really has to be done once (and updated for new dotfiles you may create later). What follows is an example Makefile that would be placed in the top-level directory of the working copy, such as ~/svn/configs/Makefile:

# Makefile to update dot-files

# $Id$

ifndef SRCDIR

SRCDIR := $(shell pwd)


DOTDIRS = $(shell find . -type d -depth 1 \! -name .svn | cut -d '/' -f 2 )

REPO_FETCHMAILRC = $(SRCDIR)/fetchmail/fetchmailrc

LOCAL_FETCHMAILRC = $(HOME)/.fetchmailrc

REPO_ZSHRC = $(SRCDIR)/zsh/zshrc


REPO_ZSH_HOSTS = $(SRCDIR)/zsh_hosts

LOCAL_ZSHRC = $(HOME)/.zshrc

LOCAL_ZSHENV = $(HOME)/.zshenv

LOCAL_ZSH_HOSTS = $(HOME)/.zsh_hosts

.PHONY: fetchmail zsh


@test -d $(SRCDIR)/fetchmail || ( echo "fetchmail sourcedir does not exist!" ; exit 1 )



@test -d $(SRCDIR)/fetchmail || ( echo "fetchmail sourcedir does not exist!" ; exit 1 )

@diff -uN $(REPO_FETCHMAILRC) $(LOCAL_FETCHMAILRC) || ( echo "")


@test -d $(SRCDIR)/fetchmail || ( echo "fetchmail sourcedir does not exist!" ; exit 1 )

svn commit $(SRCDIR)/fetchmail


@test -d $(SRCDIR)/fetchmail || ( echo "fetchmail sourcedir does not exist!" ; exit 1 )



@test -d $(SRCDIR)/zsh || ( echo "zsh sourcedir does not exist!" ; exit 1 )





@test -d $(SRCDIR)/zsh || ( echo "zsh sourcedir does not exist!" ; exit 1 )

@diff -uN $(REPO_ZSHRC) $(LOCAL_ZSHRC) || ( echo "")

@diff -uN $(REPO_ZSHENV) $(LOCAL_ZSHENV) || ( echo "")

@diff -uN $(REPO_ZSH_HOSTS) $(LOCAL_ZSH_HOSTS) || ( echo "")


@test -d $(SRCDIR)/zsh || ( echo "zsh sourcedir does not exist!" ; exit 1 )

svn commit $(SRCDIR)/zsh


@test -d $(SRCDIR)/zsh || ( echo "zsh sourcedir does not exist!" ; exit 1 )




install: fetchmail zsh

diff: fetchmail-diff zsh-diff

commit: fetchmail-commit zsh-commit

updaterepo: fetchmail-updaterepo zsh-updaterepo


@echo "Usage: make <target>"

@echo "Available targets are:"

@echo "help                          Show this text"

@echo "install                       Install all dotfiles"

@echo "diff                          Diff all dotfiles"

@echo "updaterepo                    Update repository from local dotfiles"

@echo ""

@echo "The following dotfiles are available for use with the below commands:"

@echo "   $(DOTDIRS)"

@echo ""

@echo "[dotfile]-install             Install [dotfile] configs"

@echo "[dotfile]-diff                Diff local [dotfile] configs to that in repository working copy"

@echo "[dotfile]-commit              Commit [dotfile] from working copy to repository"

@echo "[dotfile]-updaterepo          Update working copy for [dotfile] from local files"

This Makefile handles zsh and fetchmail and allows for a variety of functions (use "make help" if you need a refresher of the commands). With it, you can manage all the dotfiles at once using the "make install" or "make diff" commands. You can also operate on single dotfile types alone with "make zsh-install" or "make fetchmail-commit". This Makefile, of course, assumes the use of subversion and also assumes you are in ~/svn/configs/ (or wherever it is installed) when you call it.

The REPO_* and LOCAL_* variables are pointers to the various dotfiles, used largely to reduce typing in the Makefile. The Makefile itself is quite self-explanatory and can easily be customized to handle all kinds of files. There may be more efficient ways to create dynamic assignments to reduce the size and complexity of the Makefile; if you have any suggestions for improvement, please share them.

Delivered each Tuesday, TechRepublic's free Linux and Open Source newsletter provides tips, articles, and other resources to help you hone your Linux skills. Automatically sign up today!


Vincent Danen works on the Red Hat Security Response Team and lives in Canada. He has been writing about and developing on Linux for over 10 years and is a veteran Mac user.

Editor's Picks