Chapter 3.2 of the Git book states:
…Occasionally, this process doesn’t go smoothly. If you changed the same part of the same file differently in the two branches you’re merging, Git won’t be able to merge them cleanly.…
How should the ambiguous "change the same part of the same file differently" expression be interpreted? Does Git internally perform a line by line comparison in the conflicted file across branches?
Example:
Suppose on a branch L I add an extra newline at the beggining of README.md. Would that mean that a modification on any line different than the first to README.md on other branch R would trigger a conflict upon a merge?
You would expect a naive line by line comparison to fail since all lines have been shifted a position in L and some fraction of lines in R remain unshifted.
Remember that Git is doing not one but two diffs:
The merge base B is the same in both git diff
commands:
git diff --find-renames <hash-of-B> <hash-of-L> # what we changed
git diff --find-renames <hash-of-B> <hash-of-R> # what they changed
So, suppose we and they both modified file F.ext
. It's clear from the first diff which lines of F.ext
we changed: the ones listed as deleted in the diff hunk regarding B, plus one more "in between" line at the edge for safety—the edge goes forwards, so if we replaced original line 3, we "touched" lines 3 and "3-and-a-half". If we didn't delete any lines—if we inserted a line after line 3 before line 4—then we touched line "3-and-a-half".
Meanwhile, it's also clear from the second diff which lines of F.ext
they changed. The same rules apply: if they replaced original line 3 with a replacement line 3, then they touched line 3 (which includes line "3.5"). So if we touched line 3, or line 3.5, we have a conflict. Otherwise, there is no conflict: Git can just take the change from whichever side made a change to the line(s) in question.
(Note that git diff
presents the diff as a unified context diff. The merge code uses the raw, non-unified diff. It therefore has a list that says "at line X of original, delete D lines and insert I new replacement lines", where at most one of D or I can be zero. The touched span is line X through line X + D + 0.5, more or less. With my weird "plus a half", I am really just waving hands vigorously here to cover up the empty-span problem, which is a problem. You'll have to experiment with Git to see exactly what it does in every case.)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With