threads / discuss / 22731

unexpected git-merge result

Subject: unexpected git-merge result

## tl;dr

5 messages between Feb 19, 2010 and Feb 22, 2010.

replies: 4people: 3as markdown or json

Dale Rowley· Feb 19, 2010, 21:35 UTC · lore
Our branch history looked something like the following:
  B---C
 /     \
A---D---E---H
     \     /
      F---G

In commit D a few lines were added to a file, and then in commit G the same lines were removed. When branches E and G were merged, those lines unexpectedly re-appeared in the merge commit (H), even though no other commits had touched that file.

I think I understand why this happened: git-merge-base reports that the common ancestor for E and G is A. Since those lines don't appear in that file in commits A or G, git-merge assumes that they were added independently on branch E, so it decides to keep the lines in the merged result.

This merge problem arises because although A is the most recent common ancestor of branches E and G in general, it is *not* the most recent common ancestor as far as that single file is concerned. The most recent common ancestor for that particular file is commit D.

This is worrisome because I imagine the converse will also be a potential problem: lines are removed in commit D, and then re-added in commit G, and they will unexpectedly disappear in the merge (H). So my question is whether this is a bug in git (ie, shouldn't git be considering independent common ancestors for each file that is merged)? This doesn't seem like a particularly unique or rare scenario - how is everyone else preventing these kinds of problems?

Dale
Junio C Hamano· Feb 19, 2010, 22:27 UTC · re: Dale Rowley · lore

Re: unexpected git-merge result

Dale Rowley <ddrowley3@juno.com> writes:
Show 15 quoted lines
> Our branch history looked something like the following:
>
>   B---C
>  /     \
> A---D---E---H
>      \     /
>       F---G
>
> In commit D a few lines were added to a file, and then in commit G the same
> lines were removed. When branches E and G were merged, those lines unexpectedly
> re-appeared in the merge commit (H), even though no other commits had touched
> that file.
>
> I think I understand why this happened: git-merge-base reports that the
> common ancestor for E and G is A.
Do you?  I don't.

D is the merge base between E and G. A and D are both common ancestor between E and G, but because D is a descendant of A, A is not a merge base (the definition of merge-base is "common ancestors none of whose children is common ancestor"). A is not.

Are you sure you really have ancestry relationship between D and G? If the history were like this:

   B---C
  /     \
 A---D---E---H
  \         /
   F-------G

and both D and F add the same set of "few lines", and G removes it, then I can understand how you would get these "removed by G" lines appear in H, as the side branch F--G didn't have no net effect on these lines and D is the only one that added them.

It can happen if F is a cherry-pick of D and G is a revert of F, for example.

Dale Rowley· Feb 20, 2010, 03:45 UTC · re: Junio C Hamano · lore

Re: unexpected git-merge result

Junio C Hamano <gitster <at> pobox.com> writes:
> It can happen if F is a cherry-pick of D and G is a revert of F, for
> example.
> 

You're exactly right. I overlooked the cherry-pick, which clears things up a bit. But the basic problem remains:

A----D---E---H
 \          /
  B--D'----G

G only removed a few of the lines that were brought over in the cherry-pick (D'), so it was surprising when they re-appeared in H. Intuitively, one would at least expect a conflict in H since D'+G is asserting that these lines should not exist, whereas D (on the other branch) is asserting that they should. I can see how it would be difficult to make git-merge account for this though, so maybe this is just a subtle gotcha when merging branches? Is there an easy way to avoid this gotcha?

Dale
Dmitry Potapov· Feb 22, 2010, 05:44 UTC · re: Dale Rowley · lore

Re: unexpected git-merge result

On Sat, Feb 20, 2010 at 03:45:09AM +0000, Dale Rowley wrote:
Show 15 quoted lines
> 
> You're exactly right. I overlooked the cherry-pick, which clears things up a
> bit. But the basic problem remains:
> 
> A----D---E---H
>  \          /
>   B--D'----G
> 
> G only removed a few of the lines that were brought over in the cherry-pick
> (D'), so it was surprising when they re-appeared in H. Intuitively, one would at
> least expect a conflict in H since D'+G is asserting that these lines should not
> exist, whereas D (on the other branch) is asserting that they should. I can see
> how it would be difficult to make git-merge account for this though, so maybe
> this is just a subtle gotcha when merging branches? Is there an easy way to
> avoid this gotcha?

git merge does 3-way merge, which means that it does not look at whole history but only on the current state and the merge base. So, if you look at changes between A and G then those lines were not touched, and A-E adds those lines, thus the end result is that these lines are added.

Dmitry
Dale Rowley· Feb 22, 2010, 17:24 UTC · re: Dmitry Potapov · lore

Re: unexpected git-merge result

Dmitry Potapov <dpotapov <at> gmail.com> writes:
Show 6 quoted lines
> > 
> > G only removed a few of the lines that were brought over in the cherry-pick
> > (D'), so it was surprising when they re-appeared in H. 
> 
> git merge does 3-way merge, which means that it does not look at whole
> history but only on the current state and the merge base.

Yes, but my point is that this is the wrong thing to do in the case that I described above. If you explicitly remove some content in your branch, then it's bad when a merge causes it to re-appear without even any conflicts. The opposite is also possible (you add content to your branch and it silently disappears during a merge), so shouldn't this be a big concern?

← back to recent threads