Git 合并添加新文件而不是冲突标记 - CONFLICT (rename/add)

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

当在命令行上 运行 git merge origin master 时,我没有得到通常的冲突标记 <<<<<< 而是将冲突文件复制到我的本地环境。

这可能与更改的文件夹名称有关吗?

示例:

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

然后我本地有 2 个文件:js/main.js & js/main.js~%commit-hash%

如何让 git 给我冲突标记而不是新文件?

& 谁能解释一下为什么会这样?

TL;DR

尝试使用 -X find-renames=<value> 获得不同的重命名检测。或者,如果那行不通或您不喜欢该方法,请在必要时从存储在索引中的多个阶段中提取所有文件,然后使用 git merge-file 来创建冲突 "by hand"。

这是一个高级别冲突:由于多个不同的文件更改名称而发生的冲突,而不是由于多个不同的文件而发生的冲突出现在 一个文件中 .

Git 已经告诉你具体问题是什么了:

Rename javascript/main.js->js/main.js in HEAD ...

因此,当将当前或 HEAD 提交与您和他们开始的公共合并基础进行比较时,Git 发现 javascript/main.js 并将该文件重命名为 js/main.js

... js/main.js added in hash

他们,无论他们是谁,在 javascript/main.js 中留下了文件 javascript/main.js,但随后创建了一个名为 js/main.js 文件。

因为只能有一个个名为js/main.js的文件,Git必须做一些特别的事情。它不能把你的js/main.js(你从javascript/main.js重命名的)放到js/main.js他们的是新创建的,但与js/main.js不同js/main.js。所以它把他们的 js/main.js 放到了 js/main.js~<em>hash</em>.

How can I make git give me conflict markers to work with instead of a new file?

也许你可以轻松做到这一点,也许不能。

首先,你要判断Git对情况的分析是否正确。 你把 javascript/main.js 改名为 js/main.js 了吗?而且,他们做了做了他们保留了原来的javascript/main.js并添加了一个新的和不同的js/main.js,或者他们真的重命名了他们的 javascript/main.js 只是 Git 没有意识到这一点,并认为他们创建了一个与原来的 javascript/main.js 无关的全新 js/main.js

如果 问题是 Git 错误检测到两个重命名,您可以尝试调整 -X find-renames=<value> 设置(名为 -X rename-threshold=<value> 在 Git 的旧版本中)。降低数字会使 Git 更愿意将明显不同的文件视为 "the same" 文件。使数字更高会使 Git 不太愿意将此类文件视为 "the same",如果将其设置为 100%,则文件内容必须完全匹配。

如果情况确实如此,并且此过程顺利进行,您可能会得到想要的东西,而不需要任何其他棘手的事情。如果没有,那么:

手工制作

如果Git是正确的,你的js/main.js真的重命名,而他们的js/main.js真的 新的,合并文件可能是不可取的。但是,您 可以 使用 git merge-file 来执行此操作,它适用于工作树中的普通文件。首先,您需要将所有三个文件都放入您的工作树中:

  • 合并基础版本,最初在合并基础提交中命名为 javascript/main.js(无论其哈希 ID 是什么)。
  • --oursHEAD 版本,在当前提交中命名为 js/main.js
  • --theirs 版本,也被命名为 js/main.js,但在他们的提交中。

这三个版本中的两个已经在您的工作树中可用,使用 Git 宣布的两个名称。

您的索引中还应该有每个文件的副本:合并基础作为第 1 阶段条目存在,--oursHEAD 版本作为第 2 阶段存在条目,--theirs 版本作为第 3 阶段条目存在。这意味着您可以使用 git showgit checkout-index 来访问每个。 (事实上​​ ,您可能可以使用 git checkout-idnex --stage=all 将它们全部作为临时文件一次获取,但我没有试验过这个。)由于您仍然需要的是基本版本,您可以使用:

git show :1:js/main.js > main.js.base

例如(假设是 Unix 风格 shell)。

一旦你的工作树中有了所有三个文件,你就可以 运行:

git merge-file <head-version> <base-version> <their-version>

<head-version> 中生成文件的冲突标记化版本。假设您到目前为止显示的名称,并将阶段 1 文件写入 js/main.js.base,那将是:

git merge-file js/main.js js/main.js.base js/main.js.~<hash>