{infiniteZest}
// Articles. Tutorials. Utilities.
Home  |   Search  |   Login  
Categories Skip Navigation Links
New / All
AJAX
Apple
ASP.NET
.NET
Git
Google / Android
Python / IronPython
Miscellaneous
SQL Server
One-way migration from SVN to Git
Summary
This article talks about migrating a repository from SVN to Git one way – meaning, after the migration, the project is expected to be developed only in Git. It also talks about the cleanup of the migrated Git repository.
 
Table of Contents

Basic migration from SVN to Git

One-way migration from SVN to Git

Metadata from Subversion

No Metadata from Subversion

Getting the .gitignore information from subversion

Cleaning up branches and tags from the migration

Master Branches

Branches

Figure 1: Branches and Tags after migration (this is the .git directory)

Trunk

Pushing to the new repository to server

 
Article Series
Previous Article:
Basic Migration from SVN to Git
This article is part of the Series:
Article Series: Migrating from Subversion to Git
Next Article:
Pushing the New Git Repository to Server

Basic migration from SVN to Git

The basic migration from SVN to Git is detailed in this article:

Basic Migration from SVN to Git

One-way migration from SVN to Git

The command ‘git svn’ can be used bi-directionally – meaning, you can still have the Subversion repository and continue to use that and update that using the git svn command. However, a lot of times you just want to NOT use the Subversion repository, once the source has been migrated over to git.

In order to facilitate the bi-directional functionality between svn and git, the ‘git svn’ tool adds additional information to the commits. With one-way migration, you don’t care about that.

Metadata from Subversion

For example, if you do ‘git log’ on the newly migrated repository, you will find the commits like this:

$git log

commit 09450cd0f82693036fd62ed067f1ba802c2448be8
Author: Author Name <author@authoremail.com>
Date: <Original Revision Date>

    Comment for the revision
    
    git-svn-id: file:///Users/user/documents/subversion/project/trunk@498 83abe658-1f70-4718-b890-5

For each of the commits, you will see a git-svn-id, which links back to the change in svn. If you are not going to use svn for this project anymore, all this information is unnecessary.

With the above information, the command ‘git svn log’ will also work, for example:

$git svn log

r498 | author | <Original Revision Date> | 2 lines

Comment for the revision

No Metadata from Subversion

In order to cut off the linkage from Subversion, you can use --no-metadata flag.

git svn clone --stdlayout --no-metadata --authors-file=authorinfo.txt file:///Users/username/documents/subversion/projectname/

So, the above command migrates a Subversion repository with standard layout, where the author detail (email, etc.) is in the authorinfo.txt.

After migrating the repository with --no-metadata flag, you will not see the git-svn-id when the ‘git log’ command is issued.

The ‘git svn log’ command will fail since no metadata has been imported.

$ git svn log
fatal: bad default revision ’refs/remotes/git-svn’

Getting the .gitignore information from subversion

You can get the ignored files (for example, the files with extensions .o (in a C based project) will not need to be version controlled) by using the following command

$ git svn show-ignore
[CODE]

You can put the output in .gitignore file; Or, you can place it in the exclude file in the .git directory. Full path to this file is: …/.git/info/exclude. For example, if you use Xcode to create project that is on git repository, it will add .DS_Store and UserInterface.xcuerstate to the exclude file.

GitHub adds the following to .gitignore for an Xcode/Objective-C project:

[CODE]
# Xcode
build/*
*.pbxuser
!default.pbxuser
*.mode1v3
!default.mode1v3
*.mode2v3
!default.mode2v3
*.perspectivev3
!default.perspectivev3
*.xcworkspace
!default.xcworkspace
xcuserdata
profile
*.moved-aside

Cleaning up branches and tags from the migration

Some cleanup needs to be done after the repository migration, primarily because of the way git and svn treat the tags and how the directories are structured.

In Subversion, the tags are essentially branches; or, rather Subversion does not distinguish between branches and tags. If you do an svn checkout on the repository, you will get the trunk and branches and tags.

$svn checkout file:///therepostorypath

$ls
branches tags trunk

Under the branches directory, you will find more subdirectories. These subdirectories could have been named projname1.0, projname1.1, projname2.0, etc. Under tags also, you might find further subdirectories; for example, projtagA, projtagB, and so on.

In both individual branch subdirectories and tag subdirectories, you will find the full source code for that particular branch or tag. Meaning, you can go to that individual subdirectory of branch or tag and you can compile that specific binary without any further dependencies.

In the above directory structure, the trunk will have the full current source code.

The way git works in this regard is different.

First of all, once you ‘checkout’ (after fetch-ing) the code, there will only be one copy of the source in the project directory. There is a hidden directory named .git, which contains the source database to get any branch you want.

$ git branch -a

* master
  remotes/projbranch1.0
  remotes/projbranch1.1
  remotes/projbranch0.1
  remotes/tags/projtagA
  remotes/tags/projtagB
  remotes/tags/projtagC
  remotes/trunk

Right after the svn to git migration, if you list all the branches in the newly migrated git repository, you will see a ton of branches.

In Subversion, branches and tags are essentially same. They both are created by using the command ‘svn copy’. Essentially, for a branch creation, you will specify the ‘branch’ directory; and for a tag creation, you will specify the ‘tag’ directory. Since both branches and tags are essentially branches (in the git terminology), you will see the tags from SVN world are also listed as branches. But, if you want to do away with Subversion and be in git only, these tags need to be cleaned up as well.

Master Branches

You will have a master branch – this is kind of equivalent to trunk (though not exactly). You are expected to do the latest development on the master branch; this is main line of source – eventually, most (perhaps all of the source in some form or other) will make it into this branch. So, you would need to keep this master branch in the new git repository.

You will also see a * in front of the master branch. That means, this branch is currently checked out. In Subversion, this code will have been in it’s own branch (in SVN, there is no master branch, but, the source for trunk will be in its own directory; individual branch source will be in their own separate directories. However, in git, there is only on source directory. That source keeps changing according to what branch you are in).

Branches

And then we see the three branches in the above repositories. This is, obviously, correct. We would want to keep all these branches in the new repository as well. However, these branches are made to look like remote repositories.

All the branches except master have remotes/ in front of it. Meaning, git is saying these branches are in the remote server (in this case, it is the svn server).

Figure 1: Branches and Tags after migration (this is the .git directory)

Figure 1: Branches and Tags after migration (this is the .git directory)

The branch and tag information is stored in the refs subdirectory of .git directory.

$ pwd
…/.git/refs

$ ls
heads remotes tags

The refs directory has three subdirectories where pointers to local, remote branches are stored.

The local branches are in the heads subdirectory. Right after the migration, only one file is in this directory: master (which contains a pointer to the master branch).

$ pwd
…/.git/refs/heads

$ ls
master

If you look under the remotes subdirectory, you see all the branches that came from SVN as well as a tags subdirectory.

$ cd ../remotes/

$ pwd
…/.git/refs/remotes

$ ls
proj1.0
proj1.1
proj0.1
tags
trunk

The branches you see here needs to be moved into the heads subdirectory.

$ cd tags
$ pwd
…/.git/refs/remotes/tags
$ ls
tag1.0
tag1.1
tag0.1

There is also a tags subdirectory under remotes. These are the branches you see listed as /remotes/tags/…

These tags need to be moved into the tags directory one step above in the hierarchy.

$ pwd
…/.git/refs/tags
$ ls
<Empty>

In order to do this, you can first copy the tags and then remove them. If you don’t want confirmations, you can use the flags -Rf. If you are migrating a large number of repositories, you can automate this. However, for one or two repositories, it won’t take that long.

cp /remotes/tags/* /tags/*
rm /remotes/tags/*

cp /remotes/* /heads/*
rm /remotes/*

See if you have discrepancy like this in the logs directory as well; You need to make the appropriate moves there as well.

Once you are done with that, you will see proper results with the git commands

$ git branch

* master
proj1.0
proj1.1
proj0.1
 trunk

As you can see above all these branches are now local branches.

$ git tag
tag1.0
tag1.1
tag0.1

You will also see all the tags properly available.

Trunk

After the migration, you will see both master and trunk branches in the new git repository. Master is the main branch in the git world; and trunk is the main branch in the Subversion world.

$ git branch -a -v

* master 0b53cd0 A commit with lot of post 1.1 changes.
trunk 0b53cd0 A commit with lot of post 1.1 changes.

The flag -v to the command ‘git branch’ gives the latest commit on a branch (and the flag ‘-a’ shows all the branches). As you can see above, both master and trunk have exactly the same last commits.

So, in the git world, these two are exactly the same branches. You can also confirm this by seeing which branches are merged into the current branch (here we are on the master branch) by using the flag --merged on the command git branch

$ git branch --merged

* master
  trunk

Now you have two options with respect to the trunk branch if you are firmly moving away from Subversion and into git: You can keep it or remove it.

The case for keeping trunk: Going forward you will be making changes to master (and other branches). This trunk branch could remain as the final branch from svn (kind of a snapshot from the old days).

The case for removing trunk: clean up. There will be ton of branches in git (especially since git makes it so easy to create branches, there will be many many more branches in the new git repository). Removing trunk will make it one less branch (if you are moving away from svn, there is no reason for having it). Also, there might be confusion with having both master and trunk.

You can delete the branch trunk by using the flag –d (be careful though: once you delete it’s gone)

$ git branch -d trunk

Deleted branch trunk (was 54b72a9).

If you didn’t care for the tags that came from Subversion, you can also delete them (before moving them into the tags subdirectory (as discussed above)

$ git branch -d -r tags/tag1.0
Deleted remote branch tags/tag1.0 (was df8b9ee).

Pushing to the new repository to server

And the notes on pushing the finalized repository to the server are detailed in the following article:

Pushing the New Git Repository to Server

Article Series
Previous Article:
Basic Migration from SVN to Git
This article is part of the Series:
Article Series: Migrating from Subversion to Git
Next Article:
Pushing the New Git Repository to Server
Bookmark and Share This

More Articles With Similar Tags
icon-git-install.jpg
By default, git is available on the Mountain Lion. However, it is not added to the path. This article also discusses getting the git via Command Line Tools.
This article talks about the important aspects of migrating a repository from Subversion (SVN) to Git Version Control System.
This article talks about the steps involved in pushing a newly migrated Git repository to a server location.
This series of articles explains migrating Subversion repositories into Git.
About  Contact  Privacy Policy  Site Map