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:
Author: Author Name <email@example.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
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:
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
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
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.
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).
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)
The branch and tag information is stored in the refs subdirectory of .git directory.
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).
If you look under the remotes subdirectory, you see all the branches that came from SVN as well as a tags subdirectory.
$ cd ../remotes/
The branches you see here needs to be moved into the heads subdirectory.
$ cd tags
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.
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/*
cp /remotes/* /heads/*
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
As you can see above all these branches are now local branches.
$ git tag
You will also see all the tags properly available.
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
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