2

This question is inspired by the following excellent post: https://blogs.msdn.microsoft.com/oldnewthing/20180312-00/?p=98215 https://blogs.msdn.microsoft.com/oldnewthing/20180313-00/?p=98225 https://blogs.msdn.microsoft.com/oldnewthing/20180314-00/?p=98235

This post explains why cherry picking is evil and how it can be replaced with partial merge. Here is the picture: enter image description here

Its meaning is that if we need to make a change in the feature branch that will have to also be in the master branch, we do it on a patch branch and then merge it to both the feature and the master branches.

But it implies that we know beforehand that the change will have to be in the master too. The post does not explain what to do if the change is originally checked in to the feature branch and only later do we discover it has to be in the master branch as well.

What to do then? How to merge only this change to the master? No cherry picking, please.

mark
  • 49,076
  • 65
  • 227
  • 485
  • Git does not support partial merges. It does have a utility to do file merges, but, if I'm not mistaken, you end up with a revision that is not a merge of the other part that you tried to merge from .... and, just in case, what do you mean with "cherry-pick is evil"? cherry-picking is the swiss army knife of version control. https://git-scm.com/docs/git-merge-file – eftshift0 Sep 26 '18 at 23:12
  • Ok.... I started reading the first article and I already want to say something. So, first example of a conflict.... why did you keep an _unfinished_ item on master in the first place? Why did you (hi/she, whoever) use cherry-pick for a single revision from a feature? I would assume that the feature will be merged as a single unit when it's finished, not cherry-pick one piece here, another piece there... oh, and finally, let's **merge**!!! If you had, just like you did before, cherry-picked the change you are missing from feature 3, there would be no conflict... – eftshift0 Sep 26 '18 at 23:25
  • and if you wanted to merge just because you could... then you should have taken out the partial feature from the branch (by reverting or removing the revisions from the history altogether). All in all: **don't mess up with cherry-pick!!!** D-: Just kidding.... as I said, cherry-pick is most useful tool in your arsenal when doing version control... and I stand behind my word. – eftshift0 Sep 26 '18 at 23:27
  • 2
    You stopped reading at part 3. See [Part 5](https://blogs.msdn.microsoft.com/oldnewthing/20180316-00/?p=98255): "What if I already made the fix in my feature branch by committing directly to it, rather than creating a patch branch?" Many more other scenarios in that and other parts. – Raymond Chen Sep 27 '18 at 05:31
  • I did not know about parts 4 and 5. Will read them of course – mark Sep 27 '18 at 21:31
  • 1
    Read the whole series, all 10 posts. VSTS web interface does not seem to support merge as ours, right? – mark Sep 28 '18 at 21:23
  • @RaymondChen - is there a channel I can ask you a few questions on the subject? – mark Oct 03 '18 at 14:55
  • See also [git partial merge, not whole branch](https://stackoverflow.com/questions/4315948/git-partial-merge-not-whole-branch) – Vadzim Jun 08 '20 at 20:26
  • I just run the git commands on my local git repository then push it to DevOps Manager. We have the on premise version on Azure DevOps. Can you perform direct git pushes with the hosted version as well? If not, I'd imagine that would be a huge drawback. – Brain2000 Jun 15 '20 at 23:31

1 Answers1

8

(As several people have noted, there is no such thing as a partial merge in Git.)

I am not the author of the original blog posts and cannot speak for him, but I will say that he is right in general. The inspiring example is a little silly, but this is almost inevitable when one attempts to make a simple example of why we might do something that looks complicated.

If you know in advance that some change needs to be applied to several branches (and are using Git), you can work your way back to the earliest commit at which the change can be made—which, by our definition of "be applied", is going to be before the other branches fork from this commit—and make a new branch from that point. You can then make the change and commit. This produces the patch branch (see the diagram Mr Chen shows in the third post, that you have copied into the question).

You can then merge this new branch into all the other branches, as shown here (and there).

But it implies that we know beforehand that the change will have to be in the master too.

Correct. In order to employ this strategy, we must know that this particular patch is destined to go into some set of N branches, and find a suitable ancestor commit that is contained in all of them.

The post does not explain what to do if the change is originally checked in to the feature branch and only later do we discover it has to be in [another] branch as well.

There is no perfect solution to this, but there is one that is Good Enough. It violates your complaint, though:

What to do then? How to merge only this change to the [other branch]? No cherry picking, please.

The way we do this is by identifying that ancestor commit—wherever it may be—and cherry-picking. (Sorry!) The cherry-pick creates one new commit that is solely on the patch branch. We then merge the patch branch into both branches, as if we had done the Right Thing the first time. This produces the following:

(apple)   (berry)
  M1---------M2     <-- master
 /          /
A----------P'     <-- patch
 \          \
  F1------P--F2     <-- feature
(apple)   (berry)

Note that merging patch into feature has no effect on the source tree in commit F2 on feature: the source tree in F2 matches that in the original patch P. This is true even if there are commits on feature after P, e.g.:

  M1---------M2     <-- master
 /          /
A----------P'     <-- patch
 \          \
  F1--P--Q---F2     <-- feature

If necessary, we can do the merge into feature with -s ours to avoid "undoing" some change or getting some sort of merge conflict. The point of doing this merge, into feature, is to make Git aware of the fact that the common ancestor of master and feature is now commit P'. Commit P' must exist, even if we have to create it just for this purpose. The easiest way to create it is to use git cherry-pick.

Cherry picking is a tool, not a solution. Mr Chen's blog post is pointing out that people use the tool poorly. That does not mean that the tool itself is bad!

torek
  • 330,127
  • 43
  • 437
  • 552