Git is everywhere these days, and I can't really remember how I used to cope without the power of local distributed source control and quick branching. But once in a while I find an old SVN repository I need to convert to git and then push to a git server like github.

Here are the easy steps to switch a repositiry from SVN to git and keep the full history. Much is based on the excellent Pro Git book http://git-scm.com/book/en/Git-and-Other-Systems-Migrating-to-Git

Create an Authors.txt File

Git needs a real name and an email, svn only has username so you need to give git a mapping between the two for pretty history. the file should have one line per user like:

marvin = Paranoid Android <[email protected]>  

You can do this manually, but this script may help if you have a bash shell handy.

If you have hundreds of usernames and are in in a corporate environment you can use these very hack steps with Outlook and regex to quickly resolve many of the usernames to real names and emails as I did.

  • Paste the user names into an outlook email "To" field
  • Click check names
  • Copy the list into a text editor
  • Find ";" and Replace with "^11" to get new lines.
  • Trim whitespace with regex find "^\W" and replace with ""
  • Copy as 2 columns into excel and check they line up
  • Copy back to text editor and do find/replace again to replace tab "\t" with " = "
  • Find/Replace unknown users with "= ([^=>]+)$" replaced by "= $1 <[email protected]>"
  • Do any manual tidying up and save it somewhere.

Create a destination git repository

Create a new git repo in your github/bitbucket/VS-Online/gitlab server for the existing svn repository.

Use the git command line to export the SVN repo

Did you know git is a full svn client? It's surprisingly powerful. You need to use git to download, checkout, and convert, every single svn commit from SVN into git. It my take several hours for a big repo, just leave it running.

git svn clone "http://your-svn-server/repos/REPO-NAME" "C:/Projects/REPO-NAME" -s --no-metadata --authors-file="where-i-saved-my-authors.txt"  

Crashed half way through converting from svn to git? Use git svn fetch to resume the process since git is just fetching commits one at a time.

Migrate SVN tags to be git tags (optional)

Move any SVN tags to be proper git tags, or delete them

git for-each-ref refs/remotes/tags | cut -d / -f 4- | grep -v @ | while read tagname; do git tag "$tagname" "tags/$tagname"; git branch -r -d "tags/$tagname"; done  

Create all the svn branches as proper git branches

So we need to move the rest of the remote references under refs/remotes to be proper local branches so we can push them up as real branches.

git for-each-ref refs/remotes | cut -d / -f 3- | grep -v @ | while read branchname; do git branch "$branchname" "refs/remotes/$branchname"; git branch -r -d "$branchname"; done  

Clean up and test

Remove any tags and branches you don't want to migrate. Old branches are just clutter!

Now try and build/run your application in master from you new local git repo. You may need to fix anything that you have broken, such as....

Need to fix SVN externals when migrating to git?

Got issues with missing externals in the converted repo? Git does not have externals like svn.

Your options are in my preference order:

1) Get rid of externals, they are an unreliable way to share code anyway. Use package management (npm, nuget, gems...) everywhere possible so you have nicely managed dependencies.

2) Replace the externals with a git submodule. This requires that the dependent repo is also in git. It also means that the dependency must be in the root of the submodule, or you need to use a junction to remap the directory structure which can be messy.

3) Update your build script (you do have one right?!) to pull in the dependencies automagically using a powershell script or the svn/git command lines on your dev box/build server. Remember to exclude the externals folders using the gitignore file so they are always invisible to git and just appear during your build.

4) Hell with it, just include the svn-external folder of code in your new repo and move on.

Push the migrated code to the new home

Add the destination as the origin remote for the local project, say github.com in this case and push all those branches and tags.

$ git remote add origin [email protected]:some-username/some-project.git
$ git push origin --all
$ git push origin --tags

Get rid of SVN

Phew, all done. Don't forget to delete/archive the svn repo, or at least make it readonly so no-one else uses it.