I am trying to use svn2git to migrate a SVN project to git. However I have problems preserving all the history. The reasons seems to be because the trunk was moved in the past. The command I am using is:
$ svn2git http://mysvnserver.com/myproject/iPhone/ --no-minimize-url --authors ../authors.txt
But this only gives me history going back to 2011. The project actually started in 2010. The projected started by looking like this:
myproject
trunk
branches
tags
But in 2011 it was changed to this:
myproject
iPhone
trunk
branches
tags
Android
trunk
branches
tags
The old trunk and branches went under the iPhone directory. The history I get start from when this move was done. If I do svn log
in the iPhone directory I get the shortened history. But if I cd trunk; svn log
then I get the full history.
I have no idea of how to get this history out. My idea was to somehow create a git repository with only the history of the trunk going all the way back to 2010. Then I would later pull this in as a branch in my main repo, and do a rebase to get the history correct. But I have had no luck creating this repo for just the trunk. I have tried:
$ svn2git http://mysvnserver.com/myproject/ --rootistrunk --authors ../authors.txt
and
$ svn2git http://mysvnserver.com/myproject/ --rootistrunk -no-minimize-url --authors ../authors.txt
without any success.
No interaction between them. Just ignore the . git folder for SVN and the . svn folder for Git and you should be fine.
Git has the advantage that it's MUCH better suited if some developers are not always connected to the master repository. Also, it's much faster than SVN. And from what I hear, branching and merging support is a lot better (which is to be expected, as these are the core reasons it was written).
I just had the same problem myself. Here is how I solved it.
Clone both repos separately.
git svn clone -s [original-svn-location] [original-clone-directory]
git svn clone -s [new-svn-location] [new-clone-directory]
Add the old cloned data to the new repo.
cd [new-clone-directory]
git remote add oldstuff ../[original-clone-directory]
git fetch oldstuff
Now the tricky part... Do git log
of master
and of oldstuff/master
(or maybe trunk
and olstuff/trunk
-- however you set it up) and write down the the first commit sha from the new clone and the last commit sha from the old clone (just before the move).
git replace [first-commit-sha-from-new-clone] [last-commit-sha-from-old-clone]
And to rewrite the SHA hashes so everything is kosher and you no longer need the replace ref...
git filter-branch
And now to clean up the no-longer-needed references.
git remote rm oldstuff
rm -rf .git/refs/replace
You will lose the first commit from your history, but since that should be the initial move (ie: no actual file contents have changed) it probably won't matter to you.
Now all history should still be maintained and git blame
reports remember the repo's old history, giving you accurate information again.
You should be able to repeat this as often as needed (depending on how many times your project changed its root location and/or how many branches had commits on both sides of the move).
PS - This solution I adapted for my needs from one I found here (I couldn't get his graft approach to work for my repositories - but using replace seems to work beautifully).
You can use SubGit to convert your SVN repository.
Unfortunately, version 1.0 does not support complex layout like that one you have. But there's 1.1 EAP version that handles it well. Both 1.0 and 1.1 versions work with local SVN repository, so you have to have administrative access to SVN repository.
Please do the following in order to convert SVN repository to Git:
Generate initial configuration.
$ subgit configure SVN_REPO
Most probably, SubGit will detect two projects inside this repository. AFAIU, you need only one Git repository. So, you have to keep just one 'git' section in the config file. Specify all the branches you need to convert there.
$ EDITOR SVN_REPO/conf/subgit.conf
[core]
...
[git "default"]
repository = .git
...
trunk = trunk:refs/heads/master
branches = branches/*:refs/heads/*
tags = tags/*:refs/tags/*
shelves = shelves/*:refs/shelves/*
branches = iPhone/trunk:refs/heads/iPhone/master
branches = iPhone/branches/*:refs/heads/iPhone/*
tags = iPhone/tags/*:refs/tags/iPhone/*
branches = Android/trunk:refs/heads/Android/master
branches = Android/branches/*:refs/heads/Android/*
tags = Android/tags/*:refs/tags/Android/*
...
[daemon]
...
Convert SVN to Git.
$ subgit install SVN_REPO
At this moment SubGit converts all revisions from SVN to Git. You may find converted Git repository at SVN_REPO/.git. Additionally SubGit keeps SVN and Git repositories synchronized, it install special hooks to achieve that. If needed get rid of these hooks.
$ subgit uninstall --purge SVN_REPO
That's all. Now you have converted Git repository with the whole history kept.
Note that SubGit is a commercial product, but this kind of one-time conversion is free. Hope, it works well for you.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With