Git for other purposes

Git is usually used to manage source code, though it’s described by its creator as a stupid information tracker. When my team was looking to rework our CM system, I was able to apply my spare-time dabbling with git.

CM is a software engineering discipline all its own, and a large company can easily have several people whose full-time job it is to manage software configurations. CM basically boils down to taking several independent components and combining them into something consumable.

In our case, we have an executable produced by one team, a set of manuals that comes from another team, some kernel-mode drivers that are on their own timeline because of WHQL, and some other odds and ends. The goal of the new system was to allow things that change together to be kept in the same place, and simply refer to fixed versions of other things. For instance, version 9 of our driver might need to pull in version “2010-06-10” of the manuals.

We currently use a VSS -workalike to manage these things, but that has some problems. Our tool can’t manage file renames or reorganization, so we’re stuck with a directory that has every historical name for a file, and the directories have no sanity. It’s a mess.

The problems we have with our current tool simply don’t exist with git. You can move files around and rename them with impunity, since a git commit is just a bunch of path/object mappings (rather than a listing of files, each with its own history). So I hacked together a set of scripts that would take built binaries, commit, tag, and push them to a central repository for safekeeping. Each component comes with a script that knows how to pull other components in. The whole thing uses git tags to manage component versions.

One thing we had to manage properly was nightly builds. The central repo is only used for actually-released versions of the software; pushing all the nightly builds to it would be a waste of time. However, we wanted the automated nightly to be able to use the CM machinery to create an installable package. This is a bit tricky, and at first glance seems silly: why would you commit something into a version control system if you only want some of the versions to actually be stored?

It’s not so bad. The trick is to git reset --hard origin/master before the script copies in the new versions of the files. Here’s what a fresh clone of a component looks like:

This is a component with three real versions stored on the server. Now we’ll wait four days, and see what happens to our local repository:

Pretty messy. There are four throwaway builds stored in there. We haven’t pushed any of these, so all of those commits only exist on this machine. Now we’ll do a real build:

And now we need to give the server both the commit on master as well as the new tag:

$ git push origin master Counting objects: 5, done. Writing objects: 100% (3/3), 233 bytes, done. Total 3 (delta 0), reused 0 (delta 0) Unpacking objects: 100% (3/3), done. To <remote> ad9c250..725bf06 master -> master $ git push origin v4 Total 0 (delta 0), reused 0 (delta 0) To <remote> * [new tag] v4 -> v4

And now our gitk window looks like this:

And a fresh clone looks like this:

Success: none of the nightly builds were stored in the central repository. Git is a pretty nice source control system, but it does a pretty decent job at configuration management as well.