Given a large Subversion repository with many branches, I want to start using git-svn
by cloning trunk
first and adding specific branches later. I saw at least three ways to do this, but are any of them "official" or is there a best way?
Assume the following layout:
https://svn-repo.com/svn/company
+--core
| +--trunk
| +--branches
| | +--fastboot
| | +--playground
| +-tags
+--mobile
+--trunk
+--branches
+--tags
So, to clone only the trunk (no branches) revision 12345 of project core
:
$ git svn clone --username=svnuser -r 12345 -Ttrunk https://svn-repo.com/svn/company/core
This will clone project core
into a directory of the same name and running git svn rebase
will pull in all the changes (after revision 12345). At this point .git/config
should have something like this in it:
[svn-remote "svn"]
url = https://svn-repo.com/svn/company
fetch = core/trunk:refs/remotes/trunk
So far so good. Now, let's say I want to add the playground
branch. This is where it gets a bit hazy.
Option 1: Update the existing remote in .git/config
by adding the branch there:
[svn-remote "svn"]
url = https://svn-repo.com/svn/company
fetch = core/trunk:refs/remotes/trunk
branches = core/branches/{playground}:refs/remotes/branches/*
At this point, I was able to do:
Pull in revision 23456 of branch playground
$ git svn fetch -r 23456
Create a local branch and switch to it
$ git checkout -b playground branches/playground
Pull in the latest changes:
$ git svn rebase
Option 2: Add a new remote in .git/config
(in addition to the existing one):
[svn-remote "playground"]
url = https://svn-repo.com/svn/company
fetch = core/branches/playground:refs/remotes/playground
From here, the steps are similar to the ones from Option 1:
$ git svn fetch playground -r 23456
$ git checkout -b playground remotes/playground
$ git svn rebase
Option 3: I've also seen someone add a new fetch in the existing remote:
[svn-remote "svn"]
url = https://svn-repo.com/svn/company
fetch = core/trunk:refs/remotes/trunk
fetch = core/branches/playground:refs/remotes/branches/playground
I'm not completely certain if that's correct or if it will even work. I can't find where I saw that.
Currently, I'm sticking with Option 1, but I would really like to know the most appropriate way to do this.
All the options you note are valid, and there's no one "canonical" way to do this, partly because (from git svn
's point of view) there's no one canonical way of laying out a Subversion repository.
Options 1 and 3 that you've picked out are essentially equivalent. Personally, I'd have gone with option 3, but the result will be identical to your option 1.
Option 2 would work, but it would prevent Git detecting commit history that crosses branches – Git will normally try to detect Subversion commits that merge or create branches, and record those as such in the Git commits, but it can't do that if it's treating the two branches as entirely separate repositories.
That said, by only adding the new branches at a later date, you're losing a lot of history already. Consider the following flow:
git svn
fetches of trunk.git svn
to fetch trunk; it sees the merge, but knowing nothing about the playground branch, adds it to the Git repository as a regular commit.If you'd been picking up the playground branch all along, Git would have detected the branch and merge, and recorded them as such. Adding the playground branch afterwards won't help, unless you use git svn reset
to re-fetch all the commits, because git svn
won't rewrite the old commits to note the merge.
What I've done is to clone all the branches straight away, as Chronial suggested in the comments. It's a slow process (I've done this with a 100,000 commit Subversion repository with almost 300 branches and tags) that may take a few days to complete, but you can just leave it going in the background, and when it's done you'll have the complete Subversion history.
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