svn to git
Svn to git, full migration
Finally you've decided that git is more suitable than svn for your work. But, what happens when you have projects that where using svn for a while?
All of that information represented in thousand of svn revisions is something that normally you don't want to lose. For these cases I wrote this step by step guide to successfully migrate all the history stored in svn on a git repository, included all branches and tags no matter svn repository size. The only drawback is, with more revisions you have more time you need to wait to get migration finished.
Step by step
To start the migration process, you need some info about how data is organized in your svn.
Layout of directories inside svn
If you are lucky your project follows this directory's layout
- a/path/projectname
- trunk
- branches
- tags
This can be simply informed to git-svn
with -s
or --stdlayout
. If it's not your case, you'll have to inform to git-svn
where is every one of these tree directories.
-T trunkSubdirecty or --trunk=trunkSubdirecty
-t tagsSubdirecty or --tags=tagsSubdirecty
-b brenchesSubdirecty or --branches=brenchesSubdirecty
For example, you could have a layout like this:
- a/path
- trunk
- projectname1
- projectname2
- branches
- projectname1
- projectname2
- tags
- projectname1
- projectname2
- trunk
If you are migrating projectname1
the arguments must look like this
-T trunk/projectname1 -t tags/projectname1 -b branches/projectname1
First svn revision where git history will start
The other thing you need to know is the revision number where to start the history of what you want to migrate. First candidate is first revision number where your project exists. You can ask svn by running this line.
svn log -r 1:HEAD --limit 1 svnrepourl/a/path/trunkSubdirectory
If you want to truncate some of the old history, simply choose a newer revision number.
Creating git repository
Standard
git svn clone --username=yourSvnUsername --stdlayout -r aRevisionNumber svnurl/a/path/projectname gitreponame
Custom layout
git svn clone --username=yourSvnUsername -T trunk/projectname -t tags/projectname -b branches/projectname -r aRevisionNumber svnurl/a/path/projectname gitreponame
Fetching data from svn
cd gitreponame
git svn fetch
This step could last a long time, even days, depending on the amount of revisions, data transfer ratios and, from my experience, if you use windows takes more time than linux or osx. Git-svn will perform one request per revision to svn and will create a git commit if considered convenient. If something goes wrong during data fetching, you simply run again "git svn fetch"
and work will resume from last svn revision successfully processed. That's the reason why you must use "git clone -r n"
and then "git svn fetch"
.
When you run "git svn fetch"
and finish with nothing to log it means you've finished the hardest part, now you have all the data in your local git repository. But to finish your work you still need to put all this information in github, bitbucket, your intranet git repositories container or where you consider useful.
Preparing local repository to push to an external repository
Updating master branch
Run this line
git svn rebase
This has the same effect of
git reset --hard origin/trunk
but have the advantage of confirming you that origin/trunk
is already updated with the last svn revision
Adding svn branches to local repository
Regarding branches in git, are references to commit-objects inside git database you can simply copy those references that git-svn
made.
cp .git/refs/remotes/origin/* .git/refs/heads/
If you run
git branch
You will see all branches that exists in svn including trunk
Adding svn tags as git tags on local repository
Tags in git are different than branches, tag references point to tag-objects inside git database. The references that git-svn
created are references that point to commit-objects instead of tag-objects, so they are branches instead of tags. Well, lets create a tag for every references that git-svn have created inside .git/refs/remotes/origin/tags
.
Just run this line, if you are using windows you have to run it inside the git bash console
git for-each-ref refs/remotes/origin/tags | sed 's#^.*\([[:xdigit:]]\{40\}\).*refs/remotes/origin/tags/\(.*\)$#\2 \1#g' | while read p; do git tag -m "tag from svn" $p; done
If you run
git tag
You will see the same list of tags that exists in svn.
Pushing data
Create an empty repository in your repositories container, for example github. Then in your local repository add remote and push.
git remotes add newrepo git@github.com:aUser/aProjectName.git
git push newrepo refs/heads/*
git push --tags newrepo
Say goodbye to svn
At this point you can forget that your project once was using svn.