Managing Config Files with Git

Keeping config files synchronized across multiple computers can be a pain. Simply putting config files into a git repository and cloning it on all your computers still requires you to make symlinks to your config files. I wanted an easier solution, so I wrote some Makefiles to make symlinking new files almost automatic.

Goals:

  • Config files are stored in subdirectories at ~/config
  • Each subdirectory has rules on where to symlink the config files (eg. ~/config/home makes symlinks in ~)
  • Subdirectories are handled automatically (eg. ~/config/home/.ssh/config makes a symlink in ~/.ssh/config)
  • Symlinks are updated by running make install in directories with Makefiles
  • Support for both GNU Make and BSD Make

Set up the repository on the server:

$ cd /path/to/git/repositories
$ mkdir config.git
$ cd config.git
$ git init --bare

Clone the repository to a machine and set it up:

# Substitute the location of your git repository
$ git clone http://git.example.com/config
$ cd config
# Make a directory to store config files from ~
$ mkdir home
$ cd home
# Add some files
$ cp ~/.gitconfig .
$ cp ~/.tmux.conf .
$ cp ~/.vimrc .
$ mkdir .ssh
$ cp ~/.ssh/config .ssh

Now, add the Makefiles. Here is config/config.mk:

GIT_LS_COMMAND= git ls-files | grep -v -e Makefile  
GIT_FILES=      $(shell $(GIT_LS_COMMAND))   # GNU Make compatible  
GIT_FILES!=     $(GIT_LS_COMMAND)            # BSD Make compatible

FILES?=         $(GIT_FILES)  
CURDIR?=        $(.CURDIR)                   # BSD Make compatibility

COMMAND?=       ln -sf  
DEST?=          $(HOME)

.PHONY: all
all:  
  @echo Usage:
  @echo make install - Run default command set in the Makefile \(default is to symlink\)

.PHONY: install $(FILES)
install: $(FILES)

$(FILES):
  @echo $(DEST)/[email protected]
  @if test ! -d `dirname "$(DEST)/[email protected]"`; then \
    mkdir -p `dirname "$(DEST)/[email protected]"`; \
  fi
  @if test -e "$(DEST)/[email protected]"; then \
    rm "$(DEST)/[email protected]"; \
  fi
  @$(COMMAND) "$(CURDIR)/[email protected]" "$(DEST)/[email protected]"

And config/home/Makefile:

COMMAND= ln -sf  
DEST=    $(HOME)

include ../config.mk  

The makefile only tracks files which are added to git, so make sure to add and commit all the config files you want to track. You can add more directories to the repository and make a Makefile for each. By editing DEST variable in the Makefile, you can set the destination directory, and by editing COMMAND to cp for instance, you can copy files instead of symlinking.

To install the config files on another computer after committing and pushing the repository:

# Substitute the location of your git repository
$ git clone http://git.example.com/config
$ cd config/home
$ make install

Easy as that! Hope this helps someone.