1

I have a base branch base with a file called base.md(for the sake of understanding, i add the line number):

1:
2:
3: b

Then I check out a new branch feat and edit the base.md as below:

1:
2:
3: b
4: 
5: c

I add a commit feat-1. Then I go back to branch base and edit base.md:

1: a
2:
3: b
4:

After adding a commit base-1, I want to merge(using --conflict=diff3) feat into base but the merge conflicts occur:

01: a
02:
03: <<<<<<< ours
04: b
05: ||||||| base
06:
07: b
08: =======
09:
10: b
11:
12: c
13: >>>>>>> theirs
14:

You can see the character b located at line 3 in ours(Current Change) but at line 4 in both theirs(Incoming Change) and merge base. Actually, the b is located at line 3 in feat branch or merge base.

If I accept the current changes, it will be ok. But if the incoming changes, the file is changed to:

1: a
2:
3:
4: b
5:
6: c
7:

Intuitively, I think there should be no conflicts and the changes(line c) appended to the end.

So why this happened? How git calculates the conflicts in this case?

tianzhich
  • 31
  • 3
  • Set `merge.conflictStyle` to `diff3` before you start your merge, or use `git checkout --conflict=diff3` after merge stops with the merge conflict. You will see the three inputs that are causing the actual conflict, with the merge base version shown below the seven vertical bar markers `|||||||`. – torek Sep 15 '21 at 09:37
  • @torek While i run `git checkout --conflict=diff3`, got `base.md: needs merge \n error: you need to resolve your current index first` – tianzhich Sep 15 '21 at 09:40
  • It should work without `-m` but you can try `git checkout -m --conflict=diff3 base.md`. You *do* have to specify *one file;* Git discards any progress you've made resolving the file and re-creates the conflict at this point. – torek Sep 15 '21 at 09:46
  • I edited the question, but still can't figure out why the line `b` changed. Is this related to the line terminator? – tianzhich Sep 15 '21 at 10:04
  • Probably. The main issue is that the left side replaced "blank line, line with b" with just "line with b", and the right side replaced "blank line, line with b" with "blank line, line with b, blank line, line with c". If the right side had matched up the blank-line-plus-line-with-b entries so that it didn't consider both lines *changed*, it would just have the addition of the two lines at the end, which might not be a conflict at all. – torek Sep 15 '21 at 10:11
  • @torek I think this is probably related to the instructions set the diff engine produced. I'm not familiar with the merge conflicts. But as the `base` branch, one of the instructions is **remove one blank line** , like you just answered: https://stackoverflow.com/a/69187611/14251417. mate, you saved me a lot of time. Could you give me more hints? – tianzhich Sep 15 '21 at 10:32
  • It definitely does relate to the output from the diff engine, as `git merge` is driven by two diffs. Git locates a *merge base* commit: a common commit reachable from both *branch tips*. It then runs two `git diff`s, internally, to find changes from the merge base to each branch tip. The merge code then combines these changes; where they overlap or abut (touch line ranges), Git declares a conflict. – torek Sep 15 '21 at 10:35
  • See one or more of my many answers about merges in Git. If you could change the behavior of the underlying diff engine, you would change the behavior of the merge. Some merge options *do* change that, but probably not in any way useful for this particular case. – torek Sep 15 '21 at 10:37
  • You're right. In this particular case. If the diff engine outputs the instructions list in my first comment below your answer: https://stackoverflow.com/a/69187611/14251417. This issue might be fixed? – tianzhich Sep 15 '21 at 10:50
  • Yes - this sort of thing is why some people think that diffs (and merges) should be done in a "language aware" style, for instance. Currently that's still too hard for general purpose software though. – torek Sep 16 '21 at 00:40

0 Answers0