Reputation: 10589
Simplified, this is what happened to us:
Start with this file on master
:
class SomeClass {
...
}
Create branch featureA
off `master.
On featureA
, change file to:
class SomeClass {
...
}
extension SomeClass {
// implement feature A
}
featureB
off `master.On featureB
, change file to:
class SomeClass {
...
}
class OtherClass {
// implement feature B
}
featureB
into master
.featureA
into master
.What we expect is:
class SomeClass {
...
}
extension SomeClass {
// implement feature A
}
class OtherClass {
// implement feature B
}
or the two additions in reverse order, that's fair.
Realistically, Git should probably report a conflict: it has no knowledge about semantics, and the two "simultaneous" changes can not be reconciled.
What we get is:
class SomeClass {
...
}
class OtherClass {
// implement feature B
}
without a conflict. That is, the later commit (that was merged before the other) wins out, silently.
Can this be prevented? How?
Note: If I try this in a clean repo with the steps above, I get a merge conflict in the last step. So either the issue was rooted in something else we did on the repo; hints appreciated, I don't see what could have affected things. Or the problem is the diff algorithm being tripped up by more complicated code; in the production Swift code, we had two extensions on one side, and an enum with nested types on the other side.
Upvotes: 2
Views: 794
Reputation: 10589
Some cross-testing with the same attempted merge:
git merge
and git merge -s patience
.On Mac with Git 2.11.0 and Meld 3.16.0, I see no conflicts with either merge command.
Instead, there's
==== BASE ====
}
==== BASE ====
at the end of the file, so I think Meld is not parsing the diff correctly here.
It seems as if that version of Meld has trouble parsing some diffs. It didn't show me the conflict, so I didn't fix it properly before marking it as resolved.
Nota bene: reproducing this apparently needs more "matching" lines; the small example from my question doesn't do it.
Upvotes: 1
Reputation: 489908
The main thing to consider in a mis-merge case that you can prove was not human error is that Git's merge uses Git's diffs as input. If the diffs synchronize on trivial items, such as close brace lines that happen to have the right indentation, Git can put the merge results in places that are well-indented and hence compile, but are semantically ill-suited and hence do not function.
If you convince Git not to synchronize on trivia, it's more likely to detect actual conflicts. You can do this by changing the diff algorithm used at merge time. You can try choosing the patience
or histogram
algorithms, using -X patience
or -X histogram
. For a (brief) discussion of the details, see what's currently the end of chapter 3 (p. 65) of my not-making-much-progress-on-weekends book.
Upvotes: 2
Reputation: 44649
as you say, this properly creates a conflicts when you try to reproduce it in isolation.
My best guess at this point is the developper of one of your branches merged the other developper branches into its own and resolved the conflict by deleting the second class definition.
Upvotes: 0