I had a git-svn checkout of coolo’s branch where we are porting yast2-qt to Qt 4.x. I also publish that git repo at git.icculus.org. Yesterday coolo moved the svn tree to trunk/qt4 and I did not want to do a git-svn clone from scratch because then I would need to start my published repo from scratch.
doener on #git helped me. I had no idea how this works, but it worked. So I blog it in case I need it again in the future. May be useful if you have the same problem:
git clone git://git.icculus.org/duncan/yast2-qt4 cd yast2-qt4 git-svn init http://svn.opensuse.org/svn/yast/trunk/qt4/ git svn fetch -r42760 svn git branch tmp git-svn git-filter-branch --parent-filter "echo -p $(git rev-parse master)" tmp git reset --hard tmp git update-ref refs/remotes/git-svn master find -name .rev_db* | xargs rm git svn rebase




KDE
Kopete
Duncan Mac-Vicar’s profile on LinkedIn
Spam Poison
In case that anyone cares, here’s a small explanation of what this does:
First, we tell git-svn which svn branch we want to track. Because the repo already has all revisions from the old branch location, we don’t have to update anything and can start right anyway with getting the new stuff. Thus we can immediately use the URL to the new branch. For a non-up-to-date repo, you’d have to fetch the old stuff first, so make sure that you’re up-to-date before following these steps.
The next step is to fetch to “connector” revision. That is, the first one in the new location. Usually that’s just a move in the svn repo, but it shouldn’t matter if some files were changed along the way. In this case, that was revision 42760.
(The final “svn” part in the “git svn fetch” command just specifies from which svn repo we want to fetch. It’s actually redundant for this case, but folks who track multiple svn repos in a single git repo will hopefully know what this is for and what to do with it
)
Then we create a temporary local branch with which we can mess around. Using that branch, we can perform some “black magic”. The problem is, that the “connector” commit that we now have is totally unconnected: no children, no parents. git-svn had no way to figure out that it is actually coming straight from our old commits and had nothing else that could act as a parent for that commit either. So we have to manually tell git that it is actually a child of our latest commit on master. And that’s what we do with git-filter-branch, changing the parent of this lonely commit.
The –parent-filter option of git-filter-branch accepts a command that must return “-p $PARENT_SHA1″ if the parent should be changed. As we want the commit to become a child of the latest commit on master and there’s only a single commit, we can simply use echo + git rev-parse. If you look at the tmp branch in gitk after this command finished, you’ll see that tmp is now connected to master, just as we wanted.
The git reset command just moves our master branch to tmp, because we want to work with master, not tmp (remember, branches are just some kind of sticky notes attached to commits, you can move them around freely).
The update-ref call moves the remote tracking branch git-svn to the latest commit on master. This is required because we rewrote the commit we got from git-svn, so that git-svn looks at the rewritten commit. (This is something you probably shouldn’t do with any remote branch but git-svn ones. And only if you know what you’re doing anyway…)
To explain the find+xargs+rm command, we’ll need to look into git-svn. git-svn keeps the information that connects svn revisions to commits twice. Once in the commit messages via the git-svn-id line, and once in a db file. The latter associates revisions with commit sha1 values and, besides a performance boost, it also provides a safety net, e.g. for cherry-picks across svn branches. So the db file would refuse our rewritten commit, because the sha1 differs from what git-svn recorded when it fetched revision 42760 earlier. We could simply modify the db file manually, but the rebuilding is so fast, that you don’t care, so we just purge the db files. (If you configured git-svn to not create git-svn-id lines, you better don’t do this!)
The final “git svn rebase” call will then rebuild the db file from the information in the git-svn-id lines. As we did the update-ref call, it will use the commit that we have rewritten to perform the rebuild and thereby make it the definitive commit for revision 42760.
From there on, business goes on as usual. All git-svn things are in sync: the branch has a commit that refers to the new location, all commits are correctly connected and the rev db file is happy with the commits, too. So git svn rebase, after the rebuild is done, will start fetching stuff from the repo from revision 42761 onwards and things just work.
Note: As we just cloned the repo, there’s no git-svn information in it yet. For repos that are already git-svn enabled, these steps probably need to be adapted.
Thanks for the info and for the help!
Thanks for this post, it was helpful. Just a note: .revdb* are now called .revmap*