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!