By using git-svn I was able to convert my Subversion repo – which contains several projects, some with multiple branches – into Git repos, one per project. This page details the history of that effort, and the Git config setup that is necessary for success.

Using git-svnimport was hopeless. Its use is now deprecated by the Git authors as well. As of 2009 September 11 16:02, it’s gone.

Using my Lua code – to parse the dump file created by running “svnadmin dump” on my repo and feed a stream of commands to git-fast-import – showed promise and ran extremely fast (30 commits/s), but because of the twisted structure of my Subversion repository, and because of the way that paths are represented in the dump, it finally became obvious that that approach wasn’t going to work.

It was quite depressing to realise this. I liked my Lua code, and I had almost enjoyed trying to understand the Subversion dump file format. git-fast-import is cool too. Oh well.

git-svn actually rocks. It is intended to be used as a two-way conduit between Subversion and Git. The idea is that a Git user could work on a Subversion-hosted project by using git-svn to clone the repo into Git, and by carefully creating only linear history on the Git side (by rebasing and not doing git-style merges), make local commits to Git that can subsequently be pushed to the Subversion repo. This kind of usage has lots of advantages, not least of which is that the entire history of the Subversion repo is available in the local Git repo, and commits to the local repo can be made offline and later pushed. Subversion users have neither of these – they are tethered to the central repo for both browsing history and committing.

However, these lovely features of git-svn were irrelevant to me, as I was trying to get my code out of Subversion so I can leave Subversion behind, forever.

git-svn works well, but setting it up is a bit strange. The documentation suggests that it can understand and parse a Subversion repo (or project in a subdirectory) with the “standard” layout: trunk/, branches/, tags/. I was unable to get this to work, at least with the muforth code, which has been moved around a lot – checked into CVS, moved around; converted to Subversion, and then moved around some more, partly to fix how cvs2svn interpreted by repo, and partly to fix mistakes I had made along the way.

Using git-svn to “clone” single branches worked perfectly, though. So I simply set up by hand all the branches that I wanted, and then one by one did

  git svn fetch <branch>

The whole process went something like this. First I made a new Git repo for the project.

  mkdir muforth
  cd muforth
  git init

If you want decent commit messages with real email addresses you need to create an “authors” file that maps Subversion user names to email addresses. It looks like this:

  david   = David Frech <david@example.com>
  john    = John Deere <john@example.com>
  (no author) = some lousy conversion tool <none>

The "(no author)" entry is necessary because cvs2svn and also some Subversion tools create log entries like that. Yes, it’s lame.

There are two ways to tell git-svn about our authors file. I created an entry in my global Git config (ie, the file .gitconfig in my home directory), like this:

  [svn]
        authorsfile = /home/david/.svn-authors-for-git

I did this so I wouldn’t forget to set the right command line switches; but it’s also possible on each invocation of git-svn to specify

  -A<filename>

or

  --authors-file=<filename>

on the command line.

After playing around with git-svn init to see what kind of config entries it creates, I manually edited muforth/.git/config and added lines like these, one per branch:

  [svn-remote "trunk"]
        url = file:///home/david/tashtego/svn/muforth/trunk
        fetch = :refs/remotes/muforth-trunk
  [svn-remote "itc"]
        url = file:///home/david/tashtego/svn/muforth/branches/itc
        fetch = :refs/remotes/muforth-itc
  [svn-remote "x86-native"]
        url = file:///home/david/tashtego/svn/muforth/branches/x86_native
        fetch = :refs/remotes/muforth-x86-native

I used file:// URIs because the Subversion repo was local, but any scheme that Subversion understands will work. (You can also write file URIs as /path/to/some/file. I’ve been doing more of that since I wrote this.)

The “fetch =" lines tell Git where to put the heads for the imported branches.

With the above config I then did:

  git svn fetch trunk
  git svn fetch itc
  git svn fetch x86-native

I probably then did something like

  git branch master muforth-trunk

to create a local master branch based on muforth-trunk.