Using GIT to Manage Config Files

One thing I like about GIT, among others, is that it creates a repository locally. This makes simple things easy, still not disallowing complex things.

A good use of GIT is to manage the configuration files in a GNU/Linux system. This article describes the way I do it.

In this example, I will use the Squid proxy/cache server configuration as an example, but the principles apply to any configuration.

Ok, so here are the steps.

Zeroth step is to install GIT. ;-) On Debian/Ubuntu systems, install the "git-core" package.

First create a git repository in /etc/. On Ubuntu systems, you may have to use "sudo", or become root with "sudo -s" before running the following commands.

# cd /etc
# git init

This will create a GIT repository in /etc/.git/. This step needs to be done only once. Any recent version of GIT should accept the "init" command, otherwise run "git init-db".

Now add and commit a file, so GIT will create the "master" branch. We add the "hostname" file in this example.

# git add hostname
# git commit -m "Initial commit." hostname

If you don't use the "-m" option, GIT will start an editor to enter a comment.

I prefer to use three branches.

  • master: This is the branch that holds the working configuration of the running system.
  • stock: This branch contains the "default" configuration files as installed.
  • play: This branch is used for experimenting.
Now that the "master" branch is already created, let's create the other two.
# git branch stock
# git branch play

You can always use "git branch" command to see available branches with active branch highlighted.

In this example, we install Squid, and manage its configuration file /etc/squid/squid.conf using GIT.

Let us switch to the "stock" branch, install Squid, add the config file, commit it, and switch back to the "master" branch. Switching to a branch is called "checking out".

# git checkout stock
# apt-get install squid
# git add squid/squid.conf
# git commit -m "Adding stock config file." squid/squid.conf
# git checkout master

It is always a good idea to switch back quickly to the "master" branch, as we need to keep the "stock" branch clean without any of our changes going there accidentally.

Now you will notice that the "squid/squid.conf" file has gone missing, because we added it in the "stock" branch, not in "master".

To get the config file to the "master" branch, we need to merge it with the "stock" branch.

# git merge stock

I do all my experimenting, however small, in the "play" branch. Before starting an experiment, I switch to the "play" branch and merge it with "master", so both "master" and "play" will be identical at the beginning.

# git checkout play
# git merge master

Now the experimenting begins. I would change the config file, start/restart Squid, and 1001 other things.

During experimenting, it is very useful to view the changes I have done by using the "git diff" command.

Even if the experiments are not successful, I would still commit any partial work to continue later. There is nothing to worry as we are in the "play" branch. Use the "git branch" command to verify this.

# git commit -m "Partially finished experiment." squid/squid.conf

To get the system back to its previous state, we can always switch to the "master" branch.

# git checkout master

Make sure to commit the changes in the "play" branch before checking out the "master" branch. Otherwise, those changes will be lost.

Once the experimenting is successful in the "play" branch, we can merge them to the master branch.

# git checkout master
# git merge play

When backing up the system, make sure you include /etc/.git/ to save the history of your configurations.

Use "git log" to view the history of commits.

Happy gitting!


Unknown said...

Cool! This is very useful to backup critical config files. I used to backup my /home into svn sometime back. That came out handy when I had to change machines/distros with a clean sweep.

forrie said...

To augment this (I'm new to GIT), I'd like to push the GIT archive to a remote server for redundancy/backup purposes; but, I want the configs for each system to remain individual, not in a massive archive.

As I'm understanding, for each directory you want to have GIT management, you must do "git init" in -- or is there a simpler way to manage a larger tree? I wouldn't want, for example, to have GIT be aware of /dev (grin).