I have worked with SVN for a long time and recently I have started working on Git. After getting familiar with Git, I can clearly say that it’s far better than SVN. If you work with multiple branches and take a merge between branches or reintegrate (svn terminology) then you will know the benefit of Git over SVN.
I have recently moved my Google Code project to Github since google code is closed, so I thought to write a tutorial on SVN to Git Migration.
First we will look into using Git native commands to migrate the SVN repository to Git repository and then see what are the drawbacks and then we will do the same thing with SVN2Git tool.
SVN and Git Repositories Details:
Git Native Commands for SVN to Git Migration
- First step is to create the authors file from the SVN commits, below is the command for that. We need this file for git migration. It’s a big command, make sure you put all these in a single command.
123$ svn log -q https://pl6.projectlocker.com/JournalDev/JDProject/svn | awk -F '|' '/^r/ {sub("^ ", "", $2); sub(" $", "", $2); print $2" = "$2" <"$2">"}' | sort -u > authors.txt
After this, you will have authors.txt file that will have all the authors details who have committed code into this SVN project. - Find the revision number at which project was created. Use command below:
123$ svn log --stop-on-copy https://pl6.projectlocker.com/JournalDev/JDProject/svn
You will get the first revision number, if you have a bigger project with release cycles and you are importing from specific release, then this number could be something different. For me it’s 1 because I just created this sample SVN project for this tutorial. - Run below command to use
git svn clone
to convert your SVN project into Git. Use revision number when your project repository was created.Passing –no-minimize-url will allow git svn to accept URLs as-is without attempting to connect to a higher level directory.For other options, read git-svn documentation.
123456789101112131415161718192021222324$ git svn clone -r1:HEAD --no-minimize-url --stdlayout --no-metadata --authors-file authors.txt https://pl6.projectlocker.com/JournalDev/JDProject/svnInitialized empty Git repository in /Users/pankaj/temp/SVN_TO_GIT/svn/.git/r2 = 06ca74b0800199e459628cec09a559491da39999 (refs/remotes/origin/trunk)A abc.htmlr3 = ba90b46b60785a7fbd583e4ac197e4e8052e61b5 (refs/remotes/origin/trunk)A ClassM2.javar4 = 3667ce254366e8e020b6e9516979695d9f00f1b9 (refs/remotes/origin/trunk)Found possible branch point: https://pl6.projectlocker.com/JournalDev/JDProject/svn/trunk => https://pl6.projectlocker.com/JournalDev/JDProject/svn/branches/MyDevBranch, 4Found branch parent: (refs/remotes/origin/MyDevBranch) 3667ce254366e8e020b6e9516979695d9f00f1b9Following parent with do_switchSuccessfully followed parentr5 = 6b78ccabce56601ef6de255eab6d7fcd8980f99b (refs/remotes/origin/MyDevBranch)A branch_file.txtr6 = c940c6a4cc2b357985867ca239fba7b91e7038e5 (refs/remotes/origin/MyDevBranch)Found possible branch point: https://pl6.projectlocker.com/JournalDev/JDProject/svn/branches/MyDevBranch => https://pl6.projectlocker.com/JournalDev/JDProject/svn/tags/MyDevBranch-1.0, 6Found branch parent: (refs/remotes/origin/tags/MyDevBranch-1.0) c940c6a4cc2b357985867ca239fba7b91e7038e5Following parent with do_switchSuccessfully followed parentr7 = 3041d81b3a4fec5f4ca1b2e04ad5730f67e677b9 (refs/remotes/origin/tags/MyDevBranch-1.0)Checked out HEAD:https://pl6.projectlocker.com/JournalDev/JDProject/svn/trunk r4$ - You will have the project directory created, go into that and add remote git url as origin.
1234$ cd svn$ git remote add origin https://github.com/pankaj0323/JDProjects.git - Converting SVN Branches to Git Branches: If you will list branches at this time, you will get something like below.
12345678$ git branch -a* masterremotes/origin/MyDevBranchremotes/origin/tags/MyDevBranch-1.0remotes/origin/trunk$
Git svn clone command makes master from trunk that is ready to be pushed to remote git repository. But we want to push branches too. Use below commands for that:
123456789101112$ git checkout -b MyDevBranch origin/MyDevBranchBranch MyDevBranch set up to track remote branch MyDevBranch from origin.Switched to a new branch 'MyDevBranch'$ git branch -a* MyDevBranchmasterremotes/origin/MyDevBranchremotes/origin/tags/MyDevBranch-1.0remotes/origin/trunk$ - Migrating Tags: Git svn clone command doesn’t create tags, follow below commands for creating tags and make them ready to push to remote.
1234567891011121314151617181920212223$git tag$git checkout origin/tags/MyDevBranch-1.0Note: checking out 'origin/tags/MyDevBranch-1.0'.You are in 'detached HEAD' state. You can look around, make experimentalchanges and commit them, and you can discard any commits you make in thisstate without impacting any branches by performing another checkout.If you want to create a new branch to retain commits you create, you maydo so (now or later) by using -b with the checkout command again. Example:git checkout -b new_branch_nameHEAD is now at 3041d81... Creating a tag$ git branch -a* (detached from origin/tags/MyDevBranch-1.0)MyDevBranchmasterremotes/origin/MyDevBranchremotes/origin/tags/MyDevBranch-1.0remotes/origin/trunk$ git tag -a MyDevBranch-1.0 -m "creating tag"$git tagMyDevBranch-1.0$ - Pushing Git Branches and Tags to Remote: My master, branches and tags are ready to be pushed, use below
git push
command to publish them to remote repository.
12345678910111213$ git push origin master MyDevBranch MyDevBranch-1.0Counting objects: 14, done.Delta compression using up to 8 threads.Compressing objects: 100% (11/11), done.Writing objects: 100% (14/14), 2.28 KiB | 0 bytes/s, done.Total 14 (delta 3), reused 0 (delta 0)To https://github.com/pankaj0323/JDProjects.git* [new branch] master -> master* [new branch] MyDevBranch -> MyDevBranch* [new tag] MyDevBranch-1.0 -> MyDevBranch-1.0$
That’s it. We have moved our SVN project to Git. While this process seems easy, there are two drawbacks with git svn clone
.
- It doesn’t create branches for us to push to remote repository. There is a manual work involved, imagine you have 20 branches. It will take a lot of time to create branches and there are chances of errors or typos.
- No support for tags, I had to checkout the tag as branch and then create tag from it. This is not like moving tags from SVN to Git.
SVN to GIT Migration using svn2git tool
svn2git tool solves above two problems with native commands. Before we use this tool, we need to install it. It requires git, git-svn, and ruby installed. svn2git is a ruby wrapper around git’s native SVN support through git-svn. You can install the pre-requisites using below command.
1 2 3 |
$ sudo apt-get install git-core git-svn ruby |
-
Once you have the necessary software on your system, you can install svn2git through rubygems, which will add the svn2git command to your PATH.
123$ sudo gem install svn2gitOnce svn2git is installed, use below commands to migrate SVN repository to Git.
- First create the authors file using above command.
- Find the initial svn revision from above svn log command.
- Use below command to create local git project from svn repository.
123456789101112131415161718192021222324$ svn2git https://pl6.projectlocker.com/JournalDev/JDProject/svn --authors authors.txt --revision 1Initialized empty Git repository in /Users/pankaj/temp/SVN_TO_GIT/.git/r2 = 8beacf45e1b82b27bd27891040ea9c77b88d6c37 (refs/remotes/svn/trunk)A abc.htmlr3 = 52c125d5c68edf2ddd00143d308ba56ea0024f90 (refs/remotes/svn/trunk)A ClassM2.javar4 = f9863ff1c1e1ff323a2f96141c05f69278f830c5 (refs/remotes/svn/trunk)Found possible branch point: https://pl6.projectlocker.com/JournalDev/JDProject/svn/trunk => https://pl6.projectlocker.com/JournalDev/JDProject/svn/branches/MyDevBranch, 4Found branch parent: (refs/remotes/svn/MyDevBranch) f9863ff1c1e1ff323a2f96141c05f69278f830c5Following parent with do_switchSuccessfully followed parentr5 = fd5f535cf5d467df014e621ae48c22a1b7c568fa (refs/remotes/svn/MyDevBranch)A branch_file.txtr6 = a04dc2dfe83419ece649d9d192406f01214bd5ab (refs/remotes/svn/MyDevBranch)Found possible branch point: https://pl6.projectlocker.com/JournalDev/JDProject/svn/branches/MyDevBranch => https://pl6.projectlocker.com/JournalDev/JDProject/svn/tags/MyDevBranch-1.0, 6Found branch parent: (refs/remotes/svn/tags/MyDevBranch-1.0) a04dc2dfe83419ece649d9d192406f01214bd5abFollowing parent with do_switchSuccessfully followed parentr7 = f84c0a289589976fe8c879868626a096e36c98ef (refs/remotes/svn/tags/MyDevBranch-1.0)Checked out HEAD:https://pl6.projectlocker.com/JournalDev/JDProject/svn/trunk r4$ - Pushing Branches and Tags to Remote Git Repository: You will notice that svn2git has already created Git branches and tags for you to push to remote. Just add the remote origin and push whatever branches and tags you want to remote repository.
123456789101112131415161718192021$ git remote add origin https://github.com/pankaj0323/JDProjects.git$ git branch -aMyDevBranch* masterremotes/svn/MyDevBranchremotes/svn/trunk$ git tagMyDevBranch-1.0$ git push origin master MyDevBranch MyDevBranch-1.0Counting objects: 14, done.Delta compression using up to 8 threads.Compressing objects: 100% (8/8), done.Writing objects: 100% (14/14), 2.32 KiB | 0 bytes/s, done.Total 14 (delta 3), reused 14 (delta 3)To https://github.com/pankaj0323/JDProjects.git* [new branch] master -> master* [new branch] MyDevBranch -> MyDevBranch* [new tag] MyDevBranch-1.0 -> MyDevBranch-1.0$
That’s it. We have migrated SVN repository to Git using svn2git tool. There are various options that we can use with svn2git, for example –notags if you don’t want to migrate tags. Please go through svn2git Usage section for various options. Also note that README.txt file that was not part of standard svn structure is not migrated.
That’s all for svn to git migration. Based on above analysis, svn2git tool seems a better choice to me than
git svn clone
native command.