Evan Martin (evan) wrote in evan_tech,
Evan Martin
evan
evan_tech

using git grafts to restore svn merge history

Here's a quick tutorial on using git grafts to fill in implied svn merge history.

Say you're using git-svn to track a project, which has a trunk (we'll call it "trunk") and a branch (we'll call it "webkit_merge"). Suppose people have been merging from trunk into the branch using svn, which has a weak notion of history, especially pre 1.5: when you merge, you customarily note what was merged in the commit log so that subsequent mergers know what remains to be merged. But Git can do smart merges if it knows the real history of branches.

Sounds like a complicated surgical procedure, but it turns out to be surprisingly easy to fix.

Start by finding the commit where the merge happened:
% git log -1 --grep=Merge --parents webkit_merge
commit 146aeb3c1fbf68830925737929c162057db514bf 842b53b23115e944a22a72556748d2bcb9b7e4c4
Author: tc@google.com <tc@google.com@0039d316-1c4b-4281-b951-d872f2087c98>
Date: Tue Sep 16 18:27:32 2008 +0000

Merge trunk@r2267 to branch. test_shell still runs. chrome still
has a sad tab on every new tab. test_shell crashes when trying to
login to gmail.

The biggest conflicts were in v8_proxy.cpp and v8_custom.cpp.

TBR=eseidel

So 146aeb3 is the merge commit, and 842b53b is the parent commit on the webkit_merge branch. Find the trunk commit that was merged as noted in that commit log:
% git svn find-rev r2267 trunk
039a95f78e94168487510bb961c0dd6a804b6a25

We want to inject that commit as a second parent of the above one. The grafts file is a list, one per line, of a commit followed by its parents. So cut'n'pasting from above:
echo "146aeb3c1fbf68830925737929c162057db514bf 842b53b23115e944a22a72556748d2bcb9b7e4c4 039a95f78e94168487510bb961c0dd6a804b6a25" > .git/info/grafts

And you can verify Git now knows the lineage of that commit:
% git log -1 --grep=Merge --parents --abbrev-commit webkit_merge | head -1
commit 146aeb3... 842b53b... 039a95f...

More easy is to just run gitk, which will have all the lines match up as you'd like.

So now, for example, to merge trunk you just can run git merge trunk, and Git will have enough history to be intelligent about what needs to be merged.

If you want, it appears you can also rewrite the actual branch history (since the graft is just a local change) using git filter-branch, but since these are all svn branches there's little reason to.
Tags: git, vcs
Subscribe

  • your vcs sucks

    I've been hacking on some Haskell stuff lately that's all managed in darcs and it's reminded me of an observation I made over two years ago now (see…

  • git evangelism: enough already

    As a person who uses Git extensively and thoroughly, and as someone works on/around two large open source projects (Chrome, WebKit) that are managed…

  • using git with svnsync

    git.chromium.org is a git-svn mirror of the canonical SVN repository. It works like this: the SVN server pushes out, with svnsync, a mirror to…

  • Post a new comment

    Error

    default userpic
    When you submit the form an invisible reCAPTCHA check will be performed.
    You must follow the Privacy Policy and Google Terms of use.
  • 6 comments