How To Convert a SVN Repository to Gitorious

Recently I need to fork a really old project so I can continue development for my own project. The project to be forked was using SVN, and I am using Gitorious to host my own code.

I decided to clone the SVN repository into my Gitorious repository.

Goals

  • Retain SVN commit history.
  • Retain all tags and branches from the old project.

My Environment

  • Gitorious is hosted on Ubuntu 12.04 LTS.
  • All commands are executed in the same Ubuntu box as Gitorious is hosted.

Reference

I have searched a bit in Google and found the following links useful. Credits to the authors:

Major Flow

  • Fix the format of SVN committer list in Git format.
  • Clone the SVN repository into local computer.
  • Fix local Git repository.
  • Push local Git repostitory to remote Gitorious.

Steps

Checkout SVN Repository

displaytag’s SVN source repository is https://displaytag.svn.sourceforge.net/svnroot/displaytag .

Note that it is incorrect if your SVN link is something with /trunk at the end. Also, it is common that for anonymous access, the link begins with https://, not http:// .

cd ~/
mkdir workspace && cd workspace
svn co https://displaytag.svn.sourceforge.net/svnroot/displaytag svn

This will clone the SVN repository into the subdirectory “svn”. This can take quite a while (several minutes) if the remote SVN repository has some histories.

Retrieve the list of all SVN commiters

For the reason behind, please read “1. Retrieve a list of all Subversion committers” in this link. After that, run the command:

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

This will produce a file “authors-transform.txt” in your workspace root directory. Edit it to convert it from

foo = foo <foo>

to

foo = Foo Bar <foobar@example.com>

You may need to find out the committer’s full name and email address if you wish. But this can be omitted if you are lazy. If the SVN repository is hosted on something like SourceForge.net or Github, you can find out these information by visiting their web’s user profile pages.

Clone the Subversion repository using git-svn

The time used is much slower than purely checking out code from SVN. It takes me an hour for the displaytag project.

cd ~/workspace
git svn clone [SVN repo URL] --no-metadata -A authors-transform.txt --stdlayout git-temp

This will clone and transform the SVN into git format and place the repository into the subdirectory “git-temp”. Note that the time used will be much slower than purely cloning from SVN repository. You can see the progress as it is doing SVN commit by commit. It takes more than 1 hour for displaytag which has 1137 commits at the time of writing.

Convert svn:ignore properties to .gitignore

Refer to “3. Convert svn:ignore properties to .gitignore” in this link for reason.

cd git-temp
 git svn show-ignore > .gitignore
 git add .gitignore
 git commit -m 'Convert svn:ignore properties to .gitignore.'
 cd ..

It is ok if you see error when entering command, which may indicates there is no svn:ignore is using.

Clone to bare git

git init --bare git-bare.git
 cd git-bare.git
 git symbolic-ref HEAD refs/heads/trunk

then

cd ../git-temp
 git remote add bare ../git-bare.git
 git config remote.bare.push 'refs/remotes/*:refs/heads/*'
 git push bare

output

 * [new branch] 1.2.x -> 1.2.x
 * [new branch] displaytag-0.8 -> displaytag-0.8
 * [new branch] displaytag-1.0 -> displaytag-1.0
.. (skipped) ..
 * [new branch] displaytag1_0_branch -> displaytag1_0_branch
 * [new branch] epesh -> epesh
 * [new branch] tags/Root_displaytag11_branch -> tags/Root_displaytag11_branch
 * [new branch] tags/displaytag-1.0 -> tags/displaytag-1.0
 * [new branch] tags/displaytag-1.0-b1 -> tags/displaytag-1.0-b1
.. (skipped) ..
 * [new branch] tags/displaytag1-b3 -> tags/displaytag1-b3
 * [new branch] tags/displaytag1-rc1 -> tags/displaytag1-rc1
 * [new branch] tags/displaytag1-rc2 -> tags/displaytag1-rc2
 * [new branch] tags/start -> tags/start
 * [new branch] trunk -> trunk

note that SVN tags are mistakenly identified as branches. We will fix them later.

Rename trunck branch to master

cd ../git-bare.git
git branch -m trunk master

Clean up branches and tags

git for-each-ref --format='%(refname)' refs/heads/tags |
 cut -d / -f 4 |
 while read ref
  do
  git tag "$ref" "refs/heads/tags/$ref";
  git branch -D "tags/$ref";
 done

Output

 Deleted branch tags/Root_displaytag11_branch (was ce04ea9).
 Deleted branch tags/displaytag-1.0 (was 6b4a3b0).
 Deleted branch tags/displaytag-1.0-b1 (was a61d097).
.. (skipped) ..
 Deleted branch tags/displaytag1-rc1 (was ef9f730).
 Deleted branch tags/displaytag1-rc2 (was bd6a658).
 Deleted branch tags/start (was 416a4c3)

You may verify the tags and branches are restored by typing the following commands:

git tag -l
git branch -a

Push local git repository to remote Gitorious

Make sure you have created a repository in Gitorious, say the repository path is git@git.example.com:displaytag/displaytag (SSH access).

make sure you are in git-bare.git

git remote add origingit@git.example.com:displaytag/displaytag.git
git push --mirror

Output:

Counting objects: 15166, done.
 Compressing objects: 100% (3822/3822), done.
 Writing objects: 100% (15166/15166), 4.04 MiB, done.
 Total 15166 (delta 9706), reused 15166 (delta 9706)
 remote: => Syncing Gitorious... [OK]
 To git@git.museviral.com:displaytag/displaytag-test.git
 * [new branch] 1.2.x -> 1.2.x 
 * [new branch] displaytag-0.8 -> displaytag-0.8
.. (skipped) ..
 * [new branch] epesh -> epesh
 * [new branch] master -> master
 * [new tag] Root_displaytag11_branch -> Root_displaytag11_branch
 * [new tag] displaytag-1.0 -> displaytag-1.0
 * [new tag] displaytag-1.0-b1 -> displaytag-1.0-b1
.. (skipped) ..
 * [new tag] displaytag1-b3 -> displaytag1-b3
 * [new tag] displaytag1-rc1 -> displaytag1-rc1
 * [new tag] displaytag1-rc2 -> displaytag1-rc2
 * [new tag] start -> start

Done!

The SVN repository has been pushed to Gitorious now.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s