There is a conflict, but not about the file content. It is about the
tree content.
- In one tree, the
case2
directory (in master), there is a new file b.txt
- in the same directory (in XBranch), there is a renamed file
a.txt => b.txt
When you are resolving the conflict, you are in effect choosing one file or the
other (not one line within the file). Hence the "Old Content" in the resulting
file.
The OP adds in the comments:
But then how logically is it different from the following situation:
- I add a file
a.txt
in master
with "Old Content" and commit it.
- I add a file
a.txt
in XBranch
with "New Content" and commit it.
- I merge
XBranch
into master
.
This time it is showing both contents in that file!
This time, both trees (the case2 directory in branches master
and XBranch
)
reference a new file a.txt
: its content get merged, with conflict
resolution. Before, there was a conflict between a a.txt
(renamed as b.txt
) and a new b.txt: both files cannot exist in the
same branch, a choice (of file, not of file content) had to be made.
In step 4 of my question, if I do "git rm
" and "git add
" in a single
commit, it works as I expect! I fail to understand that now.
How can I predict when the file will have both contents?
When it will just have the content of XBranch
and when will it have just the
content of master
?
That means that:
- instead of merging
XBranch
(a.txt
renamed as b.txt
) to master
commit
with a new b.txt
from step 6 (conflict of tree),
- you would merge
XBranch
(a.txt
renamed as b.txt
) with master from new
step 4 (a.txt
also renamed as b.txt
): same tree content, but different
blob content: conflict of lines.
That being said, the OP still thinks there must be a bug:
Note: Git 2.18 (Q2 2018) changes that conflict detection report with a merge recursive.
See commit 6e7e027 (19 Apr 2018) by Elijah Newren (newren
).
merge-recursive
: avoid spurious rename/rename conflict from dir renames
If a file on one side of history was renamed, and merely modified on the
other side, then applying a directory rename to the modified side gives us
a rename/rename(1to2)
conflict.
We should only apply directory renames to pairs representing either adds or renames.
Making this change means that a directory rename testcase that was
previously reported as a rename/delete
conflict will now be reported as a
modify/delete
conflict.
When a binary file gets modified and renamed on both sides of history to different locations, both files would be written to the working tree but both would have the contents from "ours
".
This has been corrected with Git 2.27 (Q2 2020), so that the path from each side gets their original content.
See commit 95983da (13 May 2020) by Elijah Newren (newren
).
(Merged by Junio C Hamano -- gitster
-- in commit abbd1d9, 20 May 2020)
merge-recursive
: fix rename/rename(1to2) for working tree with a binary
Reported-by: Chunlin Zhang
Signed-off-by: Elijah Newren
With a rename/rename(1to2) conflict, we attempt to do a three-way merge of the file contents, so that the correct contents can be placed in the working tree at both paths.
If the file is a binary, however, no content merging is possible and we should just use the original version of the file at each of the paths.