我 fork 了一个 repo 并更改了文件 A。现在上游 repo 中的文件 A 已移动到子目录。我正在尝试将上游 repo merge 到我的 fork 上。
Git 认为文件 A 在其原始位置被删除,并在新的子目录中创建了一个新文件(这也可能是因为他们将文件向上游移动的方式)。
我想在新位置对这个文件进行修改,尽可能减少影响,w.r.t 提交历史和其他东西。谁能帮我解决这个问题?
最佳答案
Git 总是通过比较有问题的两棵树(或一棵树和索引,对于不包括 git merge
本身的情况)“事后”检测重命名。 (Linus Torvalds 认为这是一个特性;例如参见 this SO question。)
在任何情况下,git merge
都会运行 git 的内部 diff,并启用 merge 检测和默认的相似度指数 50%,除非您另外配置它。1 类似地, git diff
有一些默认值也是可配置的。如果您在 merge 基础和上游之间手动运行 git diff --find-renames -M50%
,您可能没问题(但请参阅关于配置的脚注 1)。
如果 git 没有检测到重命名,您可能需要调整重命名检测阈值和/或增加 git 应该考虑的文件数量。其中第一个是 -X
选项中的 rename-threshold
值(rename-threshold
首次出现在 git 1.7.4 中)。参见 the documentation了解详情。
1您可以将 merge.renameLimit
设置为在重命名检测方面要考虑的文件数。如果您不设置它,当前默认值为 1000 个文件(但默认值已随时间变化)。此外,如果您不设置它,merge 将使用 diff.renameLimit
,因此您可以只设置其中的第二个,并且 diff 和 merge 都使用这两个值。
文件重命名检测的工作方式有点复杂,但足够简单,可以通过示例进行描述。假设 git 正在比较提交 12345
和提交 67890
,并且在 12345
中有路径名为 A
的文件,B/C
, and D
;但在 67890
中有路径名 B/gronk
、B/C
和 D
。这意味着路径 A
消失了,但新路径 B/gronk
出现了。然后 Git 会记住这些路径(直到重命名限制值),并将 12345:A
的内容与 67890:B/gronk
的内容进行比较。如果文件“足够相似”,git 将声明 12345:A
已重命名为 67890:B/gronk
。
我不确定 git 是如何确定一个文件是 50%、75% 或其他相似/不同的。不过,我已经看到相似性指数是基于“ block ”而不是行(即使通常的 diff 输出是面向行的)。
关于移动文件的 Git merge ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33269861/