Steve Frécinaux

Subverting git

So Gnome has finally switched over to Subversion. This is a really good news and a big improvement over our old CVS, for a bunch of reasons.

So far so good. But I’m one of those who prefer git over SVN, simply because it has some advantages that makes it fit better to the way I like to work. For instance it has a full local history and branching is very cheap, not to say it’s very fast and easily scriptable. In two words, I love it.

And what’s great with Subversion is that there is a lot of interoperability layers between it and others SCM. In particular, since git 1.4.4 there is git-svn, that can fetch from and commit to a Subversion repository, in a very pleasant way. So, here are a few hints on how to use git when you want to write some code for the Gnome project.

Note: git 1.4.4 is probably not available in your distro yet, so you are likely to have to compile it by yourself. No panic, it’s not hard at all. I’ve also requested a backport for Edgy.

Small overview of git-svn

So let’s start with the beginning: how to checkout your favourite project, for instance gedit. First you have to create a directory and initialise it as a git repository.

$ mkdir gedit
$ cd gedit
$ git-svn init svn+ssh://svn.gnome.org/svn/gedit/trunk

Then you need to fetch the history from the repository. If you are not interested in the whole history, I suggest you to do this way, otherwise you< can just skip the first one in the following commands.

$ git-svn fetch -r5000
$ git-svn fetch
$ git checkout -b work remotes/git-svn
$ git repack -d

The first command fetches a given revision (here, the 5000th one), so your history will start at that revision. If you don’t do it, you will just end up downloading every single revision of the project, from the first one. The third command will create a work branch (you shouldn’t commit anything on the remote branch). The last command will repack the local repository, ie compress it, to make it smaller. After that, the whole gedit history is about 31MB big. As a comparision, the SVN checkout weights 47MB.

Update: You can also ignore the files set in the svnignore property: $ (echo; git-svn show-ignore) >> .git/info/exclude

Later, to update your git repository, you need to run git-svn fetch again, and fast-forward your working branch using git rebase, which is recomended over git merge, in order to keep the history as linear as possible.

When you have made some changes on your work branch, you have to commit it locally to git, then mirror the commit into SVN using git-svn dcommit. This will actually send every single new commit of your current branch into the SVN repository, so be careful. Then update your local repository as usual, in order to take the changes into account. Note that the commit messages in SVN will be the same as the ones in git.

This works pretty well, the only drawback I’ve seen yet is that git rebase does not like edited Changelogs. I’ve also tried a few strange commands to send several commits at once (like git-svn commit-diff, but I won’t explain those further here since if you need to, you should definitely prettify your patches in git itself and use git-svn dcommit.