Saturday, February 14, 2009

Convert a Repository from Subversion to Git

(Most of this I learned from a blog post by Paul Dowman. This is my personal reminder of how to do this with possibly a couple extra nuggets of information thrown in.)

This article assumes you want to preserve the entirety of the commit history. If you do not want to do that, then you can initialize a new git repository from an old subversion repository in many fewer steps - but I won't be discussing that here.

If you want to keep all commits attributed to the right people the first thing you are going to want to do is to make your authors mapping file (if you don't care about this, you can skip this step and forget about the -A parameter below). This file will be a mapping of svn login names to the full name and email of that committer. The format of that file is simple and as follows:

Name that file something like authors.txt. Now don't worry if you can't remember who all the committers were, you don't have to get this perfectly complete up front. When you issue the following command with the -A authors.txt argument, if a login name that is not in your authors mapping file it encountered the import will stop and tell you which login could not be found. Then, you can just add that author to the file and issue the command again and it will pick up where it left off. Here is the command you need to issue:

Ok so breaking that down the --stdlayout instructs git-svn that you have a typical svn structure by passing the arguments "-t tags -b branches -T trunk". If your structure differs from this, then don't use --stdlayout and adjust accordingly. The --no-metadata argument instructs git-svn to not bring in the svn directories and metadata that allow it to operate as an svn repository. The -A authors.txt file is what allows the import to get the committers correct as discussed above. The final two arguments are the location of your subversion repository and the directory to make your shiny new git repository in locally.

This import command may take a very long time to run as the entire history of commits is constructed.

After the import finishes you probably want to change what were tags in your subversion repository back into tags in this fresh import. To do that cd into your git repository and issue the following command:

This will list all the remote branches in your repository and you will likely see a bunch of them starting with tags/* (depending upon what your svn repository was like of course). For each of those branches that was actually a tag, you want to issue the following two commands (where release-0.2 was the name of my tag):

That first line creates a tag from that remote branch while the second command deletes the remote branch. If you have a bunch of these you will probably want a little script to do this step and I believe that Paul's article mentioned at the top of this post has an example (possibly in the comments).

Now you pretty much have your subversion repository converted to git with the last step being putting this repository out as a public repository you will share with your team. To do that first go to your public git server and set up a new bare repository using git init. The project I was converting when making this blog post is called TACT so for me that looked like this:

The final step is to push your git repository into its publicly hosted space. That is done with two commands. First, add your remote as the origin for your repo, and second, push to the origin. With your current directory being the root of your shiny new git repository that you imported above, here is what that might look like:

That is about it. The very next step you probably want to do is to set up your .gitignore file.