Migrating a Subversion Repository to Git
With BitBucket's decision to add support for Git repositories, I decided it was time to get rid of my self-hosted svn repositories. If you don't know about BitBucket, it is a service that offers unlimited public and private Mercurial and Git hosting for free. Their pricing model scales based on the number of users with read or write access to your private repositories, which makes it infinitely more flexible than GitHub.
Spiel aside, lets get to the meat of this post. So I want to convert my svn repositories to git, and by that I mean that I want to keep all revisions, branches, and tags. Most posts online list a few commands to fire off but fail to mention a few important post import cleanup steps.
Migration Steps
Create a mapping file to map svn users to Git authors. You can start by running the following command from the root of a local copy of the svn repository: svn log -q | awk -F '|' '/^r/ {sub("^ ", "", $2); sub(" $", "", $2); print $2" = "$2" <"$2">"}' | sort -u > authors-transform.txt which you can than reformat from: username = username to: username = Firstname Lastname <[email protected]>
Next we clone the Subversion repositoy using git-svn. git svn clone [url to svn repository] --no-metadata -A authors-transform.txt --stdlayout [path to local git repo] The -A parameter point to the mapping we created in step 1. The --no-metadata flag tells git to leave all the svn details behind (excluding the commit log). The --stdlayout flag tells git to assume the common "trunk/branches/tags" layout. You can can also follow branches and tags in any layout with the -T/-t/-b options.
You can convert svn:ignore properties to .gitignore with: git svn show-ignore > .gitignore Feel free to than version control the file with git: git add .gitignore git commit -m 'Convert svn:ignore properties to .gitignore.'
Next we need to handle branches and tags which git-svn imports as strange remote branches. We can do this in two ways, depending on how the git-svn handled the import. First, you can try to move the remote references to local branches using: cp -Rf .git/refs/remotes/tags/* .git/refs/tags/ rm -Rf .git/refs/remotes/tags cp -Rf .git/refs/remotes/* .git/refs/heads/ rm -Rf .git/refs/remotes If your .git/refs/remotes directory is empty, aside from an also empty tags directory, this will fail because there is nothing to copy. You can fix the issue by checking the file .git/packed-refs and doing a search and replace in the following order: refs/remotes/tags => refs/tags refs/remotes => refs/heads
When importing, git-svn should have created a remote branch called trunk than is synonymous with git's standard master branch. We should merge this branch back into master using: git checkout master git merge trunk git branch -d trunk
We can now add a remote repository alias to our bitbucket repository: git remote add origin [url to bitbucket repo]
And finally we push a mirror of our local repository to bitbucket git push origin --mirror
The end result should be a git repository with all svn revisions, branches, and tags. That was way more complicated than it should have been :) Hopefully in the future these steps are incorporated into git-svn.
References
Convert SVN Repositories to Git Repositories. [epicserve gist]
Stackoverflow Question with insight into handling branches/tags










