How to convert from Subversion to Git
When I was moving EC2 on Rails to Git I found several posts that explained how to convert a repo from svn to Git. But none of them included converting your svn tags to Git tags, so here’s yet another how-to guide. (Git experts please comment if I’m doing anything dumb.)
1. Install Git
First, you’ll need Git installed with git-svn included (git-svn will actually allow you to push changes back to the original Subversion repository, but for our purposes we’re assuming that this is a one-time conversion).
If you’re using OS X you should already be using MacPorts, so just do:
prompt> sudo port install git-core +svn
Or, on Ubuntu or Debian Linux:
prompt> sudo apt-get install git-svn
2. Create the authors file
Next, create a text file that maps Subversion committers to Git authors so the names and email addresses will be correct in the history. Save it as authors.txt:
pdowman = Paul Dowman <paul@hellospambot.com> svnuser2 = Another User <anotheruser@whatever.com>
3. Clone the repository
Now run the command that will import your svn repo into a local Git repo. I’m assuming your svn repo had the standard layout of /trunk, /tags and /branches.
prompt> git svn clone <svn repo url> --no-metadata -A authors.txt -t tags -b branches -T trunk<destination dir name>
Now running git log should show all your commit history with the correct authors.
4. Convert branches to tags
There’s one more thing. All your tags are now remote branches, not tags, in your Git repo. So you’ll need to convert them manually (or write a script to do it if you have a lot, I’ll leave that as an exercise for the reader). For each Subversion tag (i.e. Git remote branch) you’ll add it as a Git tag, then delete the remote branch. List them with:
promp> git branch -r
Then for each tag listed do:
prompt> git tag tagname tags/tagname prompt> git branch -r -d tags/tagname
You now have a local Git repository with all your history and tags. If you don’t need to share it with anyone else then you’re done.
5. Push to a public repo (optional)
If you want to publish to a public repository (for example Github), you’ll need to add it as a remote repo and then push to it.
prompt> git remote add origin git@github.com:userid/project.git prompt> git push origin master --tags
You next stop should probably be the Git tutorial for Subversion users. Enjoy!
Gianni Chiappetta:
Thanks Paul, I’ll be referring to this article!
26 July 2008, 8:46 amfloehopper:
Thanks - that’s helpful. In case anyone else finds it useul, here’s a quick one-liner to list all the users that have committed to your svn repository…
svn log –quiet | grep ‘^r.*’ | cut -d ‘ ‘ -f 3 | sort | uniq
26 July 2008, 5:36 pmMartin:
floehopper: I make that
13 September 2008, 2:52 amsvn log –quiet | grep ^r | cut -d ‘|’ -f 2 | sort | uniq
Ron Evans:
For me, I use:
svn -q log | grep ^r | cut -d ‘|’ -f 2 | sort | uniq
23 October 2008, 4:37 pmRon Bieber:
Quick and dirty shell script to convert remote tags/branches to tags per this article:
#!/bin/sh
26 January 2009, 6:50 amfor i in `git branch -r|grep tags\/|grep -v \\@`
do
TAGNAME=`echo $i | perl -p -e ’s/tags\///sig;’`
echo “Converting $i to $TAGNAME”;
git tag $TAGNAME $i
git branch -r -d $i >/dev/nul
done
matt:
Thanks for this explanation. For the most part, very helpful. Only got stuck on step 3, as there are some parameters missing.
Intead of:
git svn clone –no-metadata -A authors.txt -t tags -b branches -T trunk
it would be clearer to indicate:
git svn clone [svn repository] –no-metadata -A authors.txt -t tags -b branches -T trunk [destination]
other than that, very helpful!
27 May 2009, 11:27 amPaul Dowman:
Thanks Matt, I’ve fixed it.
27 May 2009, 12:23 pmandreas:
Step 4 isn’t working on my machine.
I’ve got the listing of the remote branches:
git branch -r
Ver2.x
tags/Ver1.0
tags/Ver1.1
tags/Ver2.0
trunk
But the git tag only tags in the remote branch. After deleting the remote branch I end up with no tags in my local clone. Am I missing somthing?
The thing is I want to totally convert to git, no step back. So I want to have all remote branches in the local master.
18 June 2009, 4:30 pmShaun Mangelsdorf:
andreas:
My best guess without any more information than you’ve given here is that you have committed to your tags as though they were branches. When you do that, there is an extra changeset (or more than one) that is unique to the svn tag, so git needs to treat it as a branch.
To revert this behaviour, you can do something like this:
$ git merge-base trunk tags/Ver1.0
abcdef1234567890abcdef1234567890abcdef12
$ git tag Ver1.0 abcdef1234567890abcdef1234567890abcdef12
$ git branch -r -d tags/Ver1.0
Note though that you’ll likely lose revisions if you do this. If you want to see what revisions you’ll lose:
$ git merge-base trunk tags/Ver1.0
abcdef1234567890abcdef1234567890abcdef12
$ git log abcdef1234..trunk
Note I’ve used a shortened form of the revision hash, two periods, and then “trunk” to specify the range. (Just making it obvious that it’s to be taken literally :)
22 June 2009, 3:56 amDustin:
I haven’t gotten this to work yet, but it seems step 3 should be [svn repo url] rather than [git repo url], right?
28 August 2009, 6:25 amPaul Dowman:
Oops, thanks Dustin! I’ve fixed it.
28 August 2009, 10:16 amJason L:
FYI - for the “authors.txt” file, the blog post ate the email part of it (because of the greater-than less-than brackets). It should be:
username = John Doe (less-than bracket)some.email@example.com(greater-than bracket)
Thanks for the article!
10 September 2009, 10:39 amPaul Dowman:
Thanks Jason, I’ve fixed that. As you said, the formatting was messed up, it had actual angle-bracket characters instead of HTML entities.
10 September 2009, 11:01 amRodrigo:
I’m getting the following error on step 3
Found possible branch point: http://svn2.xp-dev.com/svn/oncemade-cssSys/trunk => http://svn2.xp-dev.com/svn/oncemade-cssSys/tags/ModernBrowsers, 62
Use of uninitialized value in substitution (s///) at /opt/local/libexec/git-core/git-svn line 1657.
Use of uninitialized value in concatenation (.) or string at /opt/local/libexec/git-core/git-svn line 1657.
refs/remotes/trunk: ‘http://svn2.xp-dev.com/svn/oncemade-cssSys’ not found in ”
how can I fix it?
Thanks!
22 September 2009, 3:22 pmW-Mark Kubacki:
If you have more than one repository, this loop might help you finding all users:
for R in repo1 repo2 repo3 …; do svn log –quiet file:///var/svn/$R | grep ^r | cut -d ‘|’ -f 2; done | sort -u
2 October 2009, 8:15 amMatt:
Thanks a lot — this is a very helpful no-nonsense guide!
21 January 2010, 11:47 am