# unexpected git-merge result

5 messages from 2010-02-19 to 2010-02-22. Participants: Dale Rowley, Junio C Hamano, Dmitry Potapov.
Thread: https://gitlist.dev/t/22731

## Dale Rowley, 2010-02-19 21:35

Subject: unexpected git-merge result
Message-ID: <loom.20100219T202452-35@post.gmane.org>
URL: https://gitlist.dev/e/loom.20100219T202452-35%40post.gmane.org

```
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, 2010-02-19 22:27

Subject: Re: unexpected git-merge result
Message-ID: <7vaav4amjj.fsf@alter.siamese.dyndns.org>
URL: https://gitlist.dev/e/7vaav4amjj.fsf%40alter.siamese.dyndns.org
In-Reply-To: <loom.20100219T202452-35@post.gmane.org>

```
Dale Rowley <ddrowley3@juno.com> writes:

> 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, 2010-02-20 03:45

Subject: Re: unexpected git-merge result
Message-ID: <loom.20100220T031401-572@post.gmane.org>
URL: https://gitlist.dev/e/loom.20100220T031401-572%40post.gmane.org
In-Reply-To: <7vaav4amjj.fsf@alter.siamese.dyndns.org>

```
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, 2010-02-22 05:44

Subject: Re: unexpected git-merge result
Message-ID: <20100222054425.GC10191@dpotapov.dyndns.org>
URL: https://gitlist.dev/e/20100222054425.GC10191%40dpotapov.dyndns.org
In-Reply-To: <loom.20100220T031401-572@post.gmane.org>

```
On Sat, Feb 20, 2010 at 03:45:09AM +0000, Dale Rowley wrote:
> 
> 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, 2010-02-22 17:24

Subject: Re: unexpected git-merge result
Message-ID: <loom.20100222T173851-763@post.gmane.org>
URL: https://gitlist.dev/e/loom.20100222T173851-763%40post.gmane.org
In-Reply-To: <20100222054425.GC10191@dpotapov.dyndns.org>

```
Dmitry Potapov <dpotapov <at> gmail.com> writes:

> > 
> > 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?

```
