Stop cherry-picking, start merging, Part 9: Chasing the commit


Consider the following situation:

    apple
    M1   master
apple ↙︎
A
  ↖︎ apple       apple   berry
    V1 ← ← ← V2 V3   victim
  ↖︎   ↙︎  
  F1 F2 ← ← ← F3   feature
  apple   berry   cherry

From a starting common commit A (where the line is "apple"), the master branch makes an unrelated commit M1. Meanwhile we branch off from commit A with a new branch called "victim", on which unrelated commits V1 and V2 are made. From commit V1, another branch called "feature" is created, where an unrelated commit F1 is made. After commit F1, there is another commit F2 which changes the line from "apple" to "berry". At this point, the feature branch merges back to the victim branch, resulting in a merge commit V3, where the line is now "berry". After the merge, another commit F3 is made to the feature branch, which changes the line from "berry" to "cherry".

At this point, you decide that you want commit F2 (the one that changed "apple" to "berry") to go to master. Maybe there was some problem that F2 fixes which you thought was local to your feature branch, but it turns out that it affected the master branch too, and now the people who run the master branch want your temporary fix.

So we follow our cookbook. The patch branch uses commit A as its starting point. It cherry-picks a copy of F2 and merges it into the master branch.

    apple   berry
    M1 ← ← ← ← ← M2   master
apple ↙︎   berry ↙︎
A ← ← ← ← ← P   patch
  ↖︎ apple   apple   berry ↖︎
    V1 ← ← ← V2 V3   ?   victim
  ↖︎   ↙︎  
  F1 F2 ← ← ← F3   feature
  apple   berry   cherry

But what about the other half of the merge pair? Does the patch branch merge into the feature branch?

No, merging into the feature branch won't help. Commit F2 has already been merged into the victim branch, and is on its way to merging into the master branch. Any changes to the feature branch at this point will have no effect on the payload that is already on the train.

You have to merge the patch branch into the branches that have carried the original change closest to its destination, and the cherry-pick closest to the source. In our example, the source is the feature branch and the destination is the master branch. The commit has merged as far as the victim branch, so that's where the patch needs to go. Because the point of the patch branch is to make sure the right thing happens when the original commit (F2) and its cherry-picked doppelgänger (M2) meet and need to merge together.

In other words, you need to catch the train.

    apple   berry
    M1 ← ← ← ← ← M2 M3   master
apple ↙︎   berry ↙︎   ↙︎
A ← ← ← ← ← P     ↙︎   patch
  ↖︎ apple   apple   berry ↖︎   ↙︎
    V1 ← ← ← V2 V3 V4       victim
  ↖︎   ↙︎  
  F1 F2 ← ← ← F3       feature
  apple   berry   cherry

The correct merge destination for the patch branch is the victim branch, resulting in commit V4. That way, when the victim branch merges with the master branch as commit M3, commit P becomes an eligible merge base.

Comments (2)
  1. Simon Clarkstone says:

    What if you didn’t make M3 and instead merged “feature” (F3) into “master” (M2)? AFAICT it would choose merge-base = A, then see A=apple, M2=berry, and F3=cherry which produces a merge conflict. If such a merge is a violation of branch usage rules, then that doesn’t matter.

    If one needed to avoid this (a “fast-track”?), I suggest a different way to make V4:
    * merge P+F2 to make F2b, then F2b+F3 to make F3b (which is the new head of “feature”)
    * also merge F2b+V3 to make V4 (the new head of “victim”)
    Then AFAICT a hypothetical merge of master+feature chooses a merge-base of P, victim+feature chooses F2b, and master+victim chooses P as well. (I think.)

    1. If F3 merged into M2, then the victim branch is out of the picture: You are back in the two-branch scenario, and today’s discussion is moot. And as you noted, it results in a merge conflict, which is one of the problems we’re trying to avoid in the first place. (And yes, you could merge P+F2+V3 to make V4. That is basically performing a double selective merge, first for the payload that got cherry-picked into master, and again for the payload carrying the payload.)

Comments are closed.

Skip to main content