Monday, October 1, 2012

Backup and manage linux configuration files for multiple machines

If you have multiple computers running linux, you've probably faced the same problem I do right now:
Dealing with your own personally customized configuration files like .vimrc, .bashrc, .screenrc, etc., which are called dotfiles. This includes situations like:
  • You setup a new machine and want to configure it the way you want
  • You upgrade your linux distro and now you have to merge your changes into the new config files
  • You already have multiple machines with different configurations but forgot what is where
I discussed this with a good friend (who also has a blog and you should totally check it out) and he suggested using git to manage them.

Now, I'm certainly not the first one to think about that and this problem has been solved often enough. I also don't want to copy or repeat what others have already written else, firstly because I probably can't make it much better, and secondly because I'm lazy. So I'll just explain the basic steps and link to the sources where I got it from.

Git and Github

The first thing I found was the post Using git and github to manage your dotfiles by Micheal Smalley and I liked it very much. It is a good starting point that explains how to set up git and also show a small script to do some managing of the dotfiles.

This will be from where I'll proceed now, because Fabian (above mentioned friend) wouldn't stop annoying me until I signed up at github.


But you shouldn't stop there, because there are some issues that can be solved even better.

Different machines need different dotfiles

I wasn't quite sure about the symlinking thing so I continued searching.I found the post Why I use git and puppet to manage my dotfiles and what immediately convinced me was this statement:
Of course if I only used the default master branch of git I may as well be storing all of my dotfiles in Dropbox. Since many of my machines need to have their own various customizations I use a branch for each machine. Then I periodically rebase each individual branch on the latest master and use git cherry-pick to move changes from the custom branch to the master branch.
If your machines are on different upgrade levels or even on different distributions, dotfiles that might work on one machine can easily be invalid on another, even if you want to have the same configuration on all of them.

Symlinks with Puppet

I've never heard of Puppet, but the clue seems to be that you don't specify steps, but the only the goals, and Puppet ensures that your goals are fulfilled.
file { "/home/${id}/.bashrc":
 ensure => link,
 target => "/home/${id}/config/my.bashrc",
}
With this configuration, Puppet will create the symlink, but only if it doesn't exist already. The command for this is
puppet apply symlinks.pp
assuming of course your file is called symlinks.pp

Edit:
Actually, I have to revoke what I said there. I've tried it right now and the problem is that if the files already exists, they will be deleted. At least, I couldn't find the original .bashrc anymore, there was only the symlink to the one in my .dotfiles directory.
I will use a modified version of the bash script from the first link I provided and provide it here later.

Edit 2:
Here it is. My script is based on that from Micheal Smalley, but I didn't like the idea of a separate folder for the old configuration files. Instead, I move old configuration files that are not symlinks to the same .dotfiles folder, but add a suffix that indicated when they where moved there and from which machine. That way, you can put them under revision control and merge them later into your current configuration file.

Edit 3: small correction to the script, it didn't link when there was not previous dotfile to be moved to .dotfiles.

#!/bin/bash

dir=~/.dotfiles                    # dotfiles directory
time=$(date +%Y%m%d_%H%m%S)
oldsuffix="old.$(hostname)-$time"

# list of files/folders to symlink in homedir
files="bashrc bash_aliases screenrc vimrc"

##########

# move any existing dotfiles in homedir to dotfiles_old directory, then create symlinks
echo "Moving any existing dotfiles from ~ to $dir with suffix $oldsuffix"
for file in $files; do
  absfile=~/.$file
  # if file exists and is no symlink, move it to .dotfiles
  if [[ -e $absfile ]] && ! [[ -h $absfile ]]; then
    mv ~/.$file $dir/$file.$oldsuffix
  fi
  # if file doesn't exist, link it
  if ! [[ -e $absfile ]]; then
    echo "Creating symlink to $file in home directory."
    ln -s $dir/$file ~/.$file
  fi
done

By the way, you can find my github repository of my dotfiles here: https://github.com/TheSentry/dotfiles

Reuse existing dotfiles

Because other people had the same problem, there are already lots of repositories for dotfiles available. You can browse them and pick some you like, e.g. at http://dotfiles.org/

And don't forget: Dotfiles Are Meant to Be Forked


Thats it. I'm lazy and I want to actually implement this solution on my computers, because until know, there is no backup or management of my dotfiles whatsoever. If you spot any errors here or have questions and problems that you are too lazy to solve yourself, comment below and I'll see what I can do ;)

No comments:

Post a Comment