2010/07/03

Git-merge: a legitimate use and a goof

In spite of general allergy that Git users have against merge, there are perfectly legitimate uses for it. I currently work in a project where merging is routinely used.

The following cases are real-world. the specific details of my work are not relevant for this post, but if someone is curious, the
sources are public; they can be found here, and they are based on this other project.

The story is: my work is based on someone else's project, let's call it project Foo. I keep a branch called "fixes", which is based on Foo main line of development, plus some bugfixing commits that have not been integrated into Foo itself yet.

Since Foo is in active development, I need to rebase "fixes" often, so the patches will apply cleanly when Foo maintainers take a look on them. Some fixes are independently made by Foo, so my patches conflict and sometimes become obsolete, and they can simply skipped.

Then I have the "new_feature" branch, that is an implementation if a new feature (d0h). I need to base new_feature on "fixes" branch, so when I rebase fixes, in turn I rebase new_feature again, too.

I have a third branch, called "testing", which adds some code to fixes branch that will probably never make it into the main project, but it is useful for testing. It is based on fixes branch too, so it is rebased often as well.

Then, the problem: I need to test my new feature. It is not possible to rebase on both "new_feature" and "testing".

But, since they touch completely different sections of code, merging becomes trivial. So I created the "new_feature_testing" branch, which is based on "testing", but with "new_feature" merged into it.

It is a legitimate use of git-merge (or sounds legitimate to me) because a) it expresses exactly what I want to do: merge two diverging development lines; b) it does not affect the history of original branches; c) it is a "final" branch, something that will not see further developments based on it; any bugfix or new functionality goes either to "plugin" or to "new_feature".

When either "plugin" or "new_feature" changes, because of my development or because they had to be rebased against Foo, in general I try to update "new_feature_testing" using rebase and merge again. It works in 3 out of 4 times. But sometimes it fails, so I simply rebuild it from scratch, as if I did the first time.

Now, the goof :)

I develop this thing in 3 computers and need to push/pull commits often. Generally I take care to avoid merges in history, so all push/pulls are fast-forwarded. But I let one merge slip into the history. I thought it could not do much harm, because, after all, it was merging two almost identical branches.

Bad mistake, because I have to rebase "plugin" often on "fixes", as I said. Git got completely lost in the next rebase because of this merge. Could Git be more "intelligent"? Perhaps, but the fact was that rebase was full of conflicts and this "plugin" branch have commits that I can't lose.

Well, time to resort to the "stupid" technique again: dump the patches and apply manually. I did a format-patch -n HEAD~15, and about 100 patches were dumped out, because of the merge. Then the cause of problems was immediately obvious: the "same" patches were dumped twice, one from each merged branch, and of course that failed in rebase because it was trying to apply the same sequence twice.

Since I had the patches "saved" now, I resorted to recreate the "plugin" branch from "fixes" and apply the additional patches using git-am. Once the duplicates were eliminated, a git am 00* without -3 worked perfectly.
blog comments powered by Disqus