问题
When running git merge origin master
on the command-line I'm not getting the usual conflict markers <<<<<<
but instead conflicting files are being copied down to my local environment.
Could this have something to do with the folder-name being changed?
Example:
git fetch origin master && git merge origin master
CONFLICT (rename/add): Rename javascript/main.js->js/main.js in HEAD. js/main.js added in %commit-hash%
Adding as js/main.js~%commit-hash% instead
Then I have 2x files on my local: js/main.js
& js/main.js~%commit-hash%
How can I make git give me conflict markers to work with instead of a new file?
& Can anyone shed some light on why this happens?
- note:
%commit-hash%
is just a placeholder for the actual commit-hash for sake of example.
回答1:
TL;DR
Try using -X find-renames=<value>
to get different rename detection. Or, if that won't work or you don't like that method, extract all the files from the multiple stages stored in the index if necessary, and then use git merge-file
to create the conflicts "by hand".
Long
This is a high level conflict: a conflict that occurs due to multiple different files with changing names, instead of a conflict that occurs within one single file.
Git has told you exactly what the problem is:
Rename
javascript/main.js->js/main.js
inHEAD
...
So when comparing the current or HEAD
commit to the common merge-base from which both you and they started, Git finds that you took javascript/main.js
and renamed that file to js/main.js
.
...
js/main.js
added inhash
They, whoever they are, left file javascript/main.js
in javascript/main.js
, but then created a new file called js/main.js
.
Because there can only be one file named js/main.js
, Git has to do something special. It can't put your js/main.js
(that you renamed from javascript/main.js
) into js/main.js
and put their newly-created but different js/main.js
into js/main.js
. So it has put their js/main.js
into js/main.js~hash
.
How can I make git give me conflict markers to work with instead of a new file?
Maybe you can do this trivially, and maybe not.
First, you have to decide whether Git's analysis of the situation is correct. Did you rename javascript/main.js
to js/main.js
? And, what did they do: did they keep their original javascript/main.js
and add a new and different js/main.js
, or did they actually rename their javascript/main.js
and it's just that Git didn't realize this and thought they created a totally new js/main.js
that was not related to the original javascript/main.js
?
If the problem is that Git has mis-detected the two renames, you can try tweaking the -X find-renames=<value>
setting (named -X rename-threshold=<value>
in older versions of Git). Making the number lower makes Git more willing to treat apparently-different files as "the same" file. Making the number higher makes Git less willing to treat such files as "the same", to the point where if you set it to 100%, the files' contents must match exactly.
If all this is the case and this process goes well, you may get what you want and not need any further tricky bits. If not, well:
Doing it by hand
If Git is correct, and your js/main.js
really is renamed while their js/main.js
really is new, it may be inadvisable to combine the files. However, you can do this, using git merge-file
, which works with ordinary files in the work-tree. First, you will need to get all three files into your work-tree:
- The merge base version, originally named
javascript/main.js
in the merge base commit (whatever its hash ID is). - The
--ours
orHEAD
version, namedjs/main.js
in the current commit. - The
--theirs
version, also namedjs/main.js
but in their commit.
Two of these three versions are already available in your work-tree, using the two names Git has announced.
There should also be a copy of each file in your index: the merge base is there as a stage-1 entry, the --ours
or HEAD
version is there as a stage-2 entry, and the --theirs
version is there as a stage-3 entry. This means that you can use git show
or git checkout-index
to get to each. (In fact, you can probably use git checkout-idnex --stage=all
to get all of them as temporary files all at once, but I have not experimented with this.) Since the one you still need is the base version, you could use:
git show :1:js/main.js > main.js.base
for instance (assuming a Unix-style shell).
Once you have all three files in your work-tree, you can run:
git merge-file <head-version> <base-version> <their-version>
to produce, in <head-version>
, a conflict-marker-ized version of the file. Assuming the names you've shown so far, and writing the stage-1 file to js/main.js.base
, that would be:
git merge-file js/main.js js/main.js.base js/main.js.~<hash>
来源:https://stackoverflow.com/questions/50649882/git-merge-adds-new-file-instead-of-conflict-markers-conflict-rename-add