Reputation: 25599
I'm trying to use the GCC git mirror, documented here.
Some time ago, I cloned the git repository:
git clone git://gcc.gnu.org/git/gcc.git
Added the git-svn stuff:
git svn init -Ttrunk --prefix=origin/ svn+ssh://gcc.gnu.org/svn/gcc
And then git svn rebase
and git svn dcommit
etc. all worked nicely.
Some months later, I've done various development work on local git branches, and I've come to commit more changes to upstream SVN:
Update from the git miror:
$ git rebase
Ensure I have the absolute latest from SVN, but it doesn't work:
$ git svn rebase -v
Unable to determine upstream SVN information from working tree history
Somehow I've broken the meta data! As well as the above, I think I did git svn fetch
at some point, by mistake, but that shouldn't be harmful, should it?
So, I tried creating a fresh branch from the remote git mirror:
$ git branch svntrunk remotes/origin/trunk
$ git checkout svntrunk
$ git svn rebase
Unable to determine upstream SVN information from working tree history
A web search suggests that the branch history has somehow diverged from SVN, but I've checked git log
and every commit has a corresponding git-svn-id
, which seems to disprove that, no?
So, I tried a fresh clone from git://gcc.gnu.org/git/gcc.git, and in that repository git svn rebase
works fine. How can the two repos, in which both have had git rebase
from the same source, have different history? Presumably they can't, and the difference is in the local meta-data?
Now, I don't want to trash the repo that I've been working in (although I could), and exporting the patches to another repo to commit defeats the point of having git-svn in the first place. So, how can I repair it?
Upvotes: 15
Views: 17500
Reputation: 26171
The simplest thing that might work is to run git svn fetch
. If you re-attach an existing git repo to svn, you'll get this error for no good reason when you git svn rebase
. Underlying problem is that git-svn makes assumptions about the state of your repo that don't always hold if you didn't start from a clean svn clone.
The next option is to backup master git branch master-bkp
. And then run git reset --hard <way-back>
. Then run git svn rebase
.
Only if you're working on a git repo that you can in no way attach back to svn in a normal way, you can try grafting. Grafting is clever and complex, but possible. It's also hard to do right, easy to screw up, and very time consuming. Not recommended as a first option.
Upvotes: 3
Reputation: 10730
You should be able to do this with a graft. Grafting is designed to be used for bringing in legacy repositories is my understanding. It lets you manually tell git that some ref has a common parent.
As mentioned in the comments, there may be a simpler solution. This would work if all else failed though.
You'd pull down the current git repo (either with git or git-svn) and add your old git-svn repo as a remote. They won't be related, so gitk will look like this:
I had an incident at work where we had some do a file system copy instead of an svn copy, so some of my branch names allude to that. Hopefully it all makes sense anyway. Pretty lucky that I just happen to have all these images and story. What are the chances!? Probably pretty good, git-svn is easily confused.
The copied_from branch is where they copied from. The graft_ref is where this met up. They had added a bunch of files, changes properties, and then changed some of the files. It was a bit of a mess.
The general idea is to get the index of the original source, but the file contents to match the modifications. So we start in the ref branch, then reset mixed to get the index.
$ git checkout graft_ref
$ git checkout -b graft_parent
$ git reset --mixed copied_from
If you didn't make changes between the two branches when it was broken, then you shouldn't have to worry about this step.
$ git commit -a -m "svn_branch changes made on svn_trunk filesystem copy"
Now we need to do the actual graft. I trimmed the hashes here for readability.
$ git log -1 --pretty=format:%H graft_ref
631d3c84e35de98236c3d36c08d14ec92f9c62ae
$ git log -1 --pretty=format:%H graft_parent
96a4e87b554e0030035d35ca3aac23e9d71962af
$ echo "631d3... 96a4e8..." > .git/info/grafts
Which looks about how you would expect. Now we just need to rebase the changes up the tree. My notes are missing for this, but I think this is what I would have done, hehe.
$ git checkout svn_branch/master
$ git checkout -b consolidate_changes
$ git rebase master
You should be able to push these changes where ever. Grafts are not tracked by git though, so the grafted branch (svn_branch/master and friends) will break again. It is effectively a dead tree unless you do the graft again. For git-svn this isn't much of an issue because you just commit changes and then pull the source down again as a clean copy.
Upvotes: 14
Reputation: 23896
This is a fairly common scenario. I, too, have run into this when attempting to synchronize my newer Git repositories against my older, SVN-backed data store.
The secret is to keep SVN consistent with the working master branch in Git. The common commands to do so are, as you mentioned, git svn rebase
(to unwind your changes and synchronize back with SVN) and git reset --hard
(to perform a hard rollback to a previous revision when your internal index is in an inconsistent state). It took a great deal of searching to root this procedure out for me. (Take a backup copy before you perform either of these.)
The reason this appears to happen is Git becomes deeply confused when you manage two or more change histories simultaneously against the same working branch, which should be HEAD
by default. If something changes in the upstream SVN repository and downstream change histories that Git cannot reconcile, it loses its place and throws the error you've listed above.
This problem is additionally addressed here. As mentioned in the top answer, you'll want to rule out the possibility that your version of git needs to be upgraded and attempt the fixes they've recommended, as well.
Upvotes: 3