Migrate SVN repositories to Git banner image

In this blog post I'll explain how to migrate SVN repositories to Git in less than 10 steps. This step by step tutorial will result in a Git repository that includes all the users and commit's from all branches and the tags that are available in the current history of your SVN repository.

Requirements

Git

  • git-svn (included in the installation of Git-scm)
  • Git bash

Steps

Step 1: Getting all the users from the SVN repository history and save them to a text file

The code below will display all the commit messages from the selected SVN repository.

svn log https://svn.example.com/example-repository

We can extend this with a -q or --quiet parameter to only show the revision number, author and date. Because we use the -q parameter, every revision we read will start with an r (for revision).

Next we add a part to this command to process the svn log output to match the format that git needs to match SVN users as Git users. You can do this by adding the following part to the command we are going to execute:

awk -F '|' '/^r/ {sub("^ ", "", $2); sub(" $", "", $2); print $2" = "$2" <"$2">"}'

The code above will check fi the line starts with an r, and if so, explode the output at the |, remove the white spaces, and put that output between < and >. Because the user from our log result is the second value from the exploded value, we will use $2 to get the username.

Now it's time to filter out the duplicate users, we can do that by using the sort command and adding the -u parameter, so that only unique values will be returned.

At last we want to print all the above processed data to a text file, so that Git can later use this to convert it to Git data. We can do this by adding > authors-transform.txt to the end of our command.

Result:

With all the commands combined, the command you want to run will look like this:

svn log https://svn.example.com/example-repository -q | awk -F '|' '/^r/ {sub("^ ", "", $2); sub(" $", "", $2); print $2" = "$2" <"$2">"}' | sort -u > authors-transform.txt

If you run this command in a bash shell, you will get the following output in your authors-transform.txt file:

user1 = user1 <user1>
user2 = user2 <user2>
user3 = user3 <user3>

Step 2: Convert the SVN users to Git users ๐Ÿค 

Git doesn't work with usernames like SVN, but in stead uses e-mail adresses. In this step we are going to convert the usernames stored in the authors-transform.txt file we created in step 1 into the corresponding e-mail addresses.

To match an SVN user to the new Git user, our migration command will check the username before the = symbol, so we should leave this like it is. Everything after the = can be changed as you like. For example if we changed user1 = user1 <user1> into user1 = John Doe <[email protected]>, Git will identify SVN user user1 as John Doe with e-mail address [email protected].

Make sure to change all the users in the authors-transform.txt file, so that Git can match the corresponding users to every revision.

Result:

user1 = John Doe <[email protected]>
user2 = Jane Doe <[email protected]>

Step 3: Cloning the SVN repository as Git repository

First we need to clone our newly created empty Git repository. We can simply do that by running the git clone command.

git clone [email protected]:example-repository.git

The command above will clone the remote repository to the current folder on our local machine with the repository as folder name (example-repository).

Next we are going to clone the SVN repository as a Git repository. How we do this depends on the structure of your SVN repository.

If you are using the default trunk, branches, tags folder structure we can run the git svn clone command like this:

git svn clone https://svn.example.com/example-repository -s --no-metadata -A authors-transform.txt example-repository

If you are using a different structure in your SVN repository, you need to manually define the trunk, branches and tags locations in the git svn clone command. I like to use this option, even though I am using the default folder structure, just to make sure that I'm matching the right folders with the right Git data. We can do this by running the following command:

git svn clone https://svn.example.com/example-repository -T trunk -b branches -t tags -A authors-transform.txt example-repository

This will clone the svn repository with the authors-transform.txt file as a guide to match the users to the revisions (using the -A parameter). The SVN repository will be cloned as Git repository into the example-repository folder (which is the empty cloned new Git repository).

Note that for big SVN repositories this could take a while to run, because the command will go through every revision in the SVN repository history.

Step 4: Converting the svn:ignore to .gitignore

Next we are going to convert the svn:ignore properties to a suitable .gitignore file.

We can do this by using the git svn show-ignore command. This command will find and list the svn:ignore properties on every directory, then output it so that we can add this to a .gitignore file.

To do this we run the following command in our new Git repository root folder:

git svn show-ignore > .gitignore

Now we just need to commit our new .gitignore file to the repository. We can do that by running the following command:

git add .gitignore
git commit -m 'Converted svn:ignore to .gitignore'

Step 5: Creating Git tags for every tag in SVN

Next we want to create a Git tag for every tag in SVN. After cloning the SVN repository as Git repository, all the tags and branches are cloned as Git branches, therefor we are going to run the git branch command to check if we have any tags.

We can simply do this by running the following command:

git branch -r | sed -rne 's, *tags/([^@]+)$,\1,p' | while read tag; do echo "git tag $tag 'tags/${tag}^'; git branch -r -d tags/$tag"; done | sh

The -r parameter on git branch causes the remote-tracking branches to be listed.

In the above command we check if git branch reads any tags in the tags branch folder. If git finds any branches here, it will run the git tag command to create a tag in our Git repository. After creating the Git tag, it will remove the tag branch which has been created by the git svn clone migration.

We now have succesfully created Git tags for every SVN tag.

Step 6: Creating Git branches for every branch in SVN

Since we have no more tag branches, we can now create a branch for every branch that still extists in the SVN repository.

We can simply run the same command again with a few small changes, since we are not checking for tags anymore.

git branch -r | grep -v tags | sed -rne 's, *([^@]+)$,\1,p' | while read branch; do echo "git branch $branch $branch"; done | sh

As you can see we are using the git branch command again, this time we are not reading for tags but for branch, this is because all the migrated branches are now located in a branch Git branch, this means for example that SVN branch branch-1 which was located at branches/branch-1, now is in the git branch branch/branch-1. All we now do is for example, create a branch that is called branch-1 on the position of branch/branch-1.

That is all we had to do to create Git branches for our SVN branches.

Step 7: Pushing the Git repository to remote

Now we just need to push everything to our remote Git repository, we'll do that by running the following commands:

git remote add origin [email protected]:example-repository.git
git push --all
git push --tags

Step 8: Cleaning up ๐Ÿงน

Finally to clean up the SVN meta-data in our new Git repository, we can run the following few commands.

To remove the SVN remote section from our git config:

git config --remove-section svn-remote.svn

To remove the SVN section from our git config:

git config --remove-section svn

And at last to remove the svn meta data from our .git folder:

rm -r .git/svn

Thats it! ๐ŸŽ‰

Now everything should be in place, and your SVN repository should be succesfully migrated to Git!