Git for Config Management

Though the most common use of git is source code version control, it also works well for maintaining Software configuration files. Consider the case of a Software that receives some data, does some processing based on some parameters provided by the user and generates some results. The user could tinker with the parameters to find the optimal solution. As long as the change history is maintained the user can go back and forth with all the parameter combinations that were tried so far. It is a common approach to save these parameters, settings and user preferences in flat, ini, xml or json files. But once the program ends it wouldn’t be possible to get back to the previous parameter combinations, or to know if someone else accidentally changed the parameters.

Just like checkpoints feature in jupyter notebooks, one could use git to make snapshots of configuration files. It gives all the goodies of a version control system, like change history, tags etc. The user can revert to older configurations using git commands. To integrate this feature into the software, one could use the library libgit. It is a portable, pure C implementation of the Git core methods. Bindings are available for most of the popular languages like python, ruby, lua, C# etc.

To further demonstrate this use case, let us consider this toy application written in Python with Qt bindings. It converts a color image to binary image. It needs two parameters, a lower threshold and an upper threshold. As the application starts, it creates a git repository to store the configuration file. When the user saves the settings it creates a new commit. As shown in the gif below the git log shows all the commits.

png

Following code snippet shows all the API’s that were used for the toy application

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# Create an empty git repository
repo = pygit2.init_repository(config_path, False)

# Stage the changes
repo.index.add("config.json")
repo.index.write()

# Commit the changes
author = pygit2.Signature("Author", "mailto@authors.tld")
committer = pygit2.Signature("Committer", "mailto@committers.tld")

parents = []
commit = None
try:
commit = repo.revparse_single("HEAD")
except (KeyError, AttributeError):
pass

if commit:
parents = [commit.oid.hex]

repo.create_commit( "HEAD", author, committer, str(datetime.now()),
repo.index.write_tree(), parents)