Raphael
Raphael

Reputation: 10589

Git silently merges as updates what should be conflicts

Simplified, this is what happened to us:

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

Answers (3)

Raphael
Raphael

Reputation: 10589

Some cross-testing with the same attempted merge:

  • On Ubuntu with Git 2.7.4 and Meld 3.14.2, I see conflicts with 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.

  • On the same Mac and during the same merge, the diff viewer in AppCode 2017.3 shows a conflict.

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

torek
torek

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

Simon Boudrias
Simon Boudrias

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

Related Questions