Monday, May 06, 2013

Migrating a Sourceforge repository from Subversion to Git

I still remember when a friend at church came up to me and said, "I'm gonna tell 'bout something you're gonna love. It's called Subversion." At the time, CVS had been the main version control system for keeping track of files, and it had revolutionized my way of thinking about backups and record-keeping. But CVS had its limitations, including lack of basic functionality such as renaming files cleanly. Subversion was like "a breath of fresh air," where seemingly all of the limitations of CVS went "poof."

But alas, the world has moved on, and Git has grit its teeth deeply into the stronghold of Subversion. Having built so many projects with Subversion behind the scenes, I was rather reluctant to git over to Git. I knew it was only a matter of time, however, and finally decided that I must give it a shot, starting with one of the several Sourceforge projects I administer.

Sourceforge supports a number of version control systems, including both Subversion and Git. Surprisingly, the documentation for migrating a Subversion repository to Git on Sourceforge was rather sparse, and as far as I can see, there's no auto-migration mechanism to simplify the task. Fortunately, there are many other tools to simplify the process, which I'd like to document for posterity here.

The beauty of the migration is that it doesn't require downloading the whole Subversion repository. The tool svn2git can apparently work on the remote repository to do all the conversion, and then the resulting local Git repository can be pushed onto the Sourceforge-hosted remote Git repo.

On my Mac, I first made sure that git, git-svn, ruby, and rubygems were installed. All the packages must have come with XCode Developer Tools as they were all already installed and ready to go. I next installed svn2git using the simple command:

$ sudo gem install svn2git

I then created a new directory to hold the new repository and entered it:

$ mkdir jaj
$ cd jaj

The simplest command for import, which assumes the standard trunk/tags/branches layout, would have been (for my "jarajar" project with mountpoint "code"):

$ svn2git

To map the author names to Sourceforge email addresses, I made a simple authors.txt file of the format:

sourceforgeusername =
sourceforgeusername1 =

GitHub recommends import of each project within a Subversion repository to a separate Git repo. In my case, my Subversion repo was laid out for multiple projects, even though it really only contained one. To import only this project, I pointed svn2git to this project folder alone and passed the "--rootistrunk" argument:

$ svn2git --rootistrunk --authors ~/authors.txt

Note that in the process of experimenting, I had failed imports that kept on failing, even though the subsequent commands were correct as far as I could tell. It turns out that the import process created a .git folder that had become corrupted and was preventing subsequent exports, even with the correct command. Deleting the .git file fixed these errors to start afresh, and running the commands with the "--verbose" command greatly simplifying troubleshooting.

Once I had imported the repository into my new local Git repo, I simply needed to push it to the Sourceforge-hosted Git repo. After creating an empty Git repo using the Sourceforge project Admin tool, I followed the Sourceforge import instructions for pushing a local repository (conducted from within the same directory):

$ git remote add origin ssh://
$ git config branch.master.remote origin
$ git config branch.master.merge refs/heads/master
$ git push origin master

And voila, my Subversion repository popped up in my Git repo, including all historical dates from revisions of old. Had I imported the entire project, maybe I would even see that venerable commit message, "New repository initialized by csv2svn." And back then, that had to be done by a Sourceforge engineer.
Post a Comment