I don’t really write a lot of blog posts, but when I write one it’s because I have something to say. Today I want to say something about gitg (a graphical interface for git). You can skip to Dawn if you’re not interested in the history of gitg, or directly to The Now if you just want to see pretty pictures of a all new and shiny gitg release.
The initial commit in gitg is dated June 24, 00:04, 2008, which makes gitg to date around five and a half years old. Originally, the development of gitg started as a clone of GitX (a graphical interface for OS X being developed by my roomate at the time, Pieter de Bie) to the GNOME/gtk+ platform. I basically set out to provide the same application (UI wise) but for a different platform and using different technologies. If you look back at early screenshots of gitg and GitX, you’ll be able to see the resemblance between the two applications.
Five years ago, the way that most (if not all) interfaces had to interact with git was through the git cli itself. There was no library underlying git core, so unless you wanted to reimplement the whole of git, you simply didn’t have much of a choice. Luckily for us, git was designed to be used like this. As most of you probably know, git generally has had two types of commands, plumbing and porcelain. The porcelain commands are that ones that users are most familiar with. These commands implement things like commit and rebase and are implemented in terms of the plumbing commands. The plumbing commands are at the very core of git and usually do only a single, lowlevel thing. You can consider the plumbing commands as a very UNIXy way of providing an API through processes (instead of a for example a shared library).
Originally, most of git porcelain was implemented using shell scripts which were simply calling various plumbing commands. Therefore, all plumbing commands usually have very good machine-parseable interfaces for both input and output. Of course, input and output is still all pure text so you’d need to do some amount of interpreting, but at least it is all well defined. To illustrate how this worked, here is an pseudo example of how gitg used to create a commit using plumbing. Given a current index to be committed:
- git write-tree: writes out a new tree object with the contents of the index. The output of this command is the SHA-1 hash of the new tree object.
- git commit-tree <tree-id> -p <parent-id>: writes out a new commit object for the given <tree-id> (obtained previously) setting the parent to <parent-id> (usually the id of HEAD obtained by git rev-parse, or HEAD^ in case of amending). The input of this command is the commit message and the output is the SHA-1 hash of the commit object.
- git update-ref -m <subject> HEAD <commit-id>: this updates the reference pointed to by HEAD (which is a symbolic ref, usually to another ref) to be at <commit-id> (previously obtained). The ref log is also updated with the given <subject> (extracted from the first line of the commit message).
This is pretty much what git commit does behind the scenes, but in a more controllable way. Of course then there is error handling (obtaining stderr), chaining all these commands manually etc. All of the functionality in gitg is implemented in this way, and although it certainly works well, calling out to programs is still a pretty horrid to develop a GUI application.
…you know, that time in between
gitg has been a GObject/C application from the beginning. This kind of made sense at the time. I was pretty familiar with this, coming from gedit, and gobject-introspection wasn’t as mature yet. gitg was also meant to be a simple interface for viewing git history, plus some trinkets like committing and creating a branch here or there.
Of course, looking back, I’m not so sure it was really the right choice. It wasn’t all that easy getting interaction with the git cli working reliably from C. Also, GObject/C requires a huge amount of boilerplate. It’s pretty nice to develop a library (portable, can be consumed by many languages, object oriented), but it definitely does not make sense anymore to develop graphical applications in C. Eventually, gitg development stagnated. There are of course other reasons (it was functioning so why work on it), but in the end I didn’t feel as much to work on it. New functionality was hard to implement, going through the git cli. Porting to gtk+3 was painful doing everything in C, etc. gitg is pretty much unchanged since the 0.2.5 release from September 1, 2011 (more than two years ago).
Around april 2012, we decided to start development of the next version of gitg. Unhappy with the current state of things, we decided to make two major changes. The first was to use Vala instead of C. By the time, Vala had matured enough for us to be considered as a very viable solution to the problem of writing GUI applications in C. It is made exactly for writing GObject based applications, while providing a level of programming interface very close to C#. The second change was to use libgit2 instead of git cli to interface with git. Implemented as a re-entrant shared library, libgit2 provides a great interface to almost all facets of git and is used by a great many projects (not the least of which is github). Other than that, we also wanted to refresh the gitg interface in accordance with the GNOME 3 interface guidelines, have a plugin architecture to extend functionality, improve our diff rendering etc.
Having made these decisions, we started from scratch to reimplement everything, throwing away any inherited bagage from the old gitg. This was almost two years ago.
Personally, I can’t develop for extended periods of time (I mean like months) anymore consistently on a single project. I usually have urges for little sprints, working all evenings for one week long (if permitted), but not much more. This means of course that development is pretty slow overall. So it took some time to get gitg back to it’s original state, but we are nearing the end.
Yesterday, I released gitg 0.3.1, the first release (of hopefully many) of the new gitg. We have most of the basic functionality implemented (viewing history, making commits), but we still have some regressions in functionality compared to 0.2.x. We are mainly missing create/rename/delete branch/tag and push/pull, but these will hopefully land soon enough.
I hope that people will find the refresh interface as much of an improvement as we think it is and that gitg might continue to be a useful tool to visualise and interact with git. Please do try it out if you can (you will need to build it in jhbuild until distro’s start shipping it) and report issues!