September 19th, 2008

  • evan

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.
  • evan

de facto

I enjoyed reading this interview of Simon Peyton-Jones of Haskell fame. He comes across as so humble and good-natured, and uses "jolly" as an intensifier. This especially resonated:
One way that this [discussion about writing down a new shared standard for recent Haskell developments] has come about, is that the compiler I am responsible for (the GHC or Glasgow Haskell Compiler), has become the de facto standard. There are lots of people using that, so if you use GHC then your program will work.

I don’t think that’s a good thing in principle, however, for a language to be defined by an implementation. Haskell is based whatever GHC accepts right now, but it [Haskell] should have an independent definition. So I would like to see Haskell Prime [their upcoming language spec] happen because I think it’s healthy to see an independent definition of the language rather than for it to be defined by a de facto standard of a particular compiler.
I've seen it over and over -- no matter how well-intentioned the stewards of a standard are, when you only have one implementation you end up getting tied to unintentional details.