SVN to GIT Migration Complete Tutorial

Filed Under: Scripts

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:

  • SVN Repository: I have created a public repository online, it’s URL is https://pl6.projectlocker.com/JournalDev/JDProject/svn . Below image shows the directory structure.

    SVN-Repository

    Notice that I have a standard directory structure with trunk, branches and tags. I have also created an extra file (README.txt) that is outside this directory hierarchy.

  • GIT Repository: I am using Github as my repository. It’s free to use and my project git URL is https://github.com/pankaj0323/JDProjects.git

Git Native Commands for SVN to Git Migration

  1. 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.
    
    $ 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.

  2. Find the revision number at which project was created. Use command below:
    
    $ 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.

  3. 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.

    
    $ git svn clone -r1:HEAD --no-minimize-url --stdlayout --no-metadata --authors-file authors.txt https://pl6.projectlocker.com/JournalDev/JDProject/svn
    Initialized empty Git repository in /Users/pankaj/temp/SVN_TO_GIT/svn/.git/
    r2 = 06ca74b0800199e459628cec09a559491da39999 (refs/remotes/origin/trunk)
    	A	abc.html
    r3 = ba90b46b60785a7fbd583e4ac197e4e8052e61b5 (refs/remotes/origin/trunk)
    	A	ClassM2.java
    r4 = 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, 4
    Found branch parent: (refs/remotes/origin/MyDevBranch) 3667ce254366e8e020b6e9516979695d9f00f1b9
    Following parent with do_switch
    Successfully followed parent
    r5 = 6b78ccabce56601ef6de255eab6d7fcd8980f99b (refs/remotes/origin/MyDevBranch)
    	A	branch_file.txt
    r6 = 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, 6
    Found branch parent: (refs/remotes/origin/tags/MyDevBranch-1.0) c940c6a4cc2b357985867ca239fba7b91e7038e5
    Following parent with do_switch
    Successfully followed parent
    r7 = 3041d81b3a4fec5f4ca1b2e04ad5730f67e677b9 (refs/remotes/origin/tags/MyDevBranch-1.0)
    Checked out HEAD:
      https://pl6.projectlocker.com/JournalDev/JDProject/svn/trunk r4
    $
    
  4. You will have the project directory created, go into that and add remote git url as origin.
    
    $ cd svn
    $ git remote add origin https://github.com/pankaj0323/JDProjects.git
    
  5. Converting SVN Branches to Git Branches: If you will list branches at this time, you will get something like below.
    
    $ git branch -a
    * master
      remotes/origin/MyDevBranch
      remotes/origin/tags/MyDevBranch-1.0
      remotes/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:

    
    $ git checkout -b MyDevBranch origin/MyDevBranch
    Branch MyDevBranch set up to track remote branch MyDevBranch from origin.
    Switched to a new branch 'MyDevBranch'
    $ git branch -a
    * MyDevBranch
      master
      remotes/origin/MyDevBranch
      remotes/origin/tags/MyDevBranch-1.0
      remotes/origin/trunk
    $
    
  6. Migrating Tags: Git svn clone command doesn’t create tags, follow below commands for creating tags and make them ready to push to remote.
    
    $git tag
    $git checkout origin/tags/MyDevBranch-1.0
    Note: checking out 'origin/tags/MyDevBranch-1.0'.
    
    You are in 'detached HEAD' state. You can look around, make experimental
    changes and commit them, and you can discard any commits you make in this
    state without impacting any branches by performing another checkout.
    
    If you want to create a new branch to retain commits you create, you may
    do so (now or later) by using -b with the checkout command again. Example:
    
      git checkout -b new_branch_name
    
    HEAD is now at 3041d81... Creating a tag
    $ git branch -a
    * (detached from origin/tags/MyDevBranch-1.0)
      MyDevBranch
      master
      remotes/origin/MyDevBranch
      remotes/origin/tags/MyDevBranch-1.0
      remotes/origin/trunk
    $ git tag -a MyDevBranch-1.0 -m "creating tag"
    $git tag
    MyDevBranch-1.0
    $
    
  7. 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.
    
    $ git push origin master MyDevBranch MyDevBranch-1.0
    Counting 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.

  1. 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.
  2. 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.


$ 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.

    
    $ sudo gem install svn2git
    

    Once svn2git is installed, use below commands to migrate SVN repository to Git.

    1. First create the authors file using above command.
    2. Find the initial svn revision from above svn log command.
    3. Use below command to create local git project from svn repository.
      
      $ svn2git https://pl6.projectlocker.com/JournalDev/JDProject/svn --authors authors.txt --revision 1
      Initialized empty Git repository in /Users/pankaj/temp/SVN_TO_GIT/.git/
      r2 = 8beacf45e1b82b27bd27891040ea9c77b88d6c37 (refs/remotes/svn/trunk)
      	A	abc.html
      r3 = 52c125d5c68edf2ddd00143d308ba56ea0024f90 (refs/remotes/svn/trunk)
      	A	ClassM2.java
      r4 = 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, 4
      Found branch parent: (refs/remotes/svn/MyDevBranch) f9863ff1c1e1ff323a2f96141c05f69278f830c5
      Following parent with do_switch
      Successfully followed parent
      r5 = fd5f535cf5d467df014e621ae48c22a1b7c568fa (refs/remotes/svn/MyDevBranch)
      	A	branch_file.txt
      r6 = 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, 6
      Found branch parent: (refs/remotes/svn/tags/MyDevBranch-1.0) a04dc2dfe83419ece649d9d192406f01214bd5ab
      Following parent with do_switch
      Successfully followed parent
      r7 = f84c0a289589976fe8c879868626a096e36c98ef (refs/remotes/svn/tags/MyDevBranch-1.0)
      Checked out HEAD:
        https://pl6.projectlocker.com/JournalDev/JDProject/svn/trunk r4
      $ 
      
    4. 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.
      
      $ git remote add origin https://github.com/pankaj0323/JDProjects.git
      $ git branch -a
        MyDevBranch
      * master
        remotes/svn/MyDevBranch
        remotes/svn/trunk
      $ git tag
      MyDevBranch-1.0
      $ git push origin master MyDevBranch MyDevBranch-1.0
      Counting 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.

  • Comments

    1. Vinod says:

      This is really helpful. I am able to migrate my SVN repo to Git.
      Thank you for this wonderful article.

      Could you please let us know how can we ignore some files (Ex: files with extension .ear) while cloning the SVN repository?

      I can see that –ignore-paths option for git svn command. I could not be able to make it.

      Could you please suggest?

    2. shailendra says:

      This is a very good post. Steps are very clear. I have tried these steps. However I am below message. Have you ever experienced such issue while running executing push command?

      git push origin master Release_1.0.7
      Enumerating objects: 1383, done.
      Counting objects: 100% (1383/1383), done.
      Delta compression using up to 4 threads.
      Compressing objects: 100% (1162/1162), done.
      Writing objects: 100% (1383/1383), 87.85 MiB | 4.62 MiB/s, done.
      Total 1383 (delta 592), reused 0 (delta 0)
      remote: Resolving deltas: 100% (592/592), done.
      remote: GitLab: Author ‘nairvvin@shail.com’ is not a member of team
      To gitlab.shail.com:Shail-Book/DataFileProject.git
      ! [remote rejected] master -> master (pre-receive hook declined)
      ! [remote rejected] Release_1.0.7 -> Release_1.0.7 (pre-receive hook declined)

    Leave a Reply

    Your email address will not be published. Required fields are marked *

    close
    Generic selectors
    Exact matches only
    Search in title
    Search in content
    Search in posts
    Search in pages