Git Merge Adds New File Instead of Conflict Markers - CONFLICT (rename/add)

丶灬走出姿态 提交于 2019-12-10 19:44:28

问题


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 in HEAD ...

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 in hash

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 or HEAD version, named js/main.js in the current commit.
  • The --theirs version, also named js/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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!