移动文件的Git合并

5
我fork了一个仓库并更改了文件A。现在,上游仓库中的文件A已经移动到子目录中。我正在尝试将上游仓库合并到我的分支中。 Git认为文件A已被删除,同时在新的子目录中创建了一个新的文件(这可能是因为他们上游如何移动该文件)。 我想以最小的影响将我的修改内容合并到该文件的新位置,并保留提交历史等信息。请问有什么方法可以做到这一点吗?

当合并时,您是否会遇到冲突?通常Git足够聪明,可以找出文件被移动的情况。如果您只是运行git merge origin/master(或者您的上游分支叫什么),会发生什么? - knittl
2个回答

11
Git通常通过比较两个树(或一个树和索引,对于不包括git merge本身的情况)来“事后”检测重命名。(Linus Torvalds认为这是一种特性,例如请参见此SO问题。)
无论如何,git merge将启用合并检测,并使用默认的相似度指数50%运行git的内部差异,除非您进行其他配置。1同样,git diff也有一些可配置的默认值。如果您在合并基础和上游之间手动运行git diff --find-renames -M50%,那么您可能是好的(但请参见有关配置的注释1)。
如果Git未检测到重命名,则可能需要调整重命名检测阈值和/或增加git应考虑的文件数量。其中第一个是-X选项中的rename-threshold值(rename-threshold首次出现在git 1.7.4中)。有关详细信息,请参见文档
1您可以将merge.renameLimit设置为要考虑的文件数,在重命名检测方面。如果您没有设置它,则当前默认值为1000个文件(但默认值随时间而变化)。此外,如果您没有设置它,则合并使用diff.renameLimit,因此您可以仅设置这两个值,并且diff和merge都使用这两个值。文件重命名检测的工作方式有些复杂,但通过示例足够简单描述。假设Git正在比较提交12345和提交67890,在12345中有路径名为AB/CD的文件;但在67890中有路径名为B/gronkB/CD的文件。这意味着路径A已经不存在,但新路径B/gronk已经出现。Git将记住这样的路径(高达重命名限制值),并将比较12345:A67890:B/gronk的内容。如果文件“足够相似”,Git将宣布12345:A被重命名为67890:B/gronk
我不确定Git是如何决定一个文件是50%、75%或其他相似/不同的。尽管通常的diff输出是面向行的,但我看到相似度指数基于“块”而不是行。

-2

你需要使用git mv而不是仅仅使用mv来移动文件。

由于git会对内容进行快照,它并不关心文件名(文件名存储在idx文件中作为元数据)。

如果你只是简单地移动文件,git将无法“理解”你想要移动它,并将把它视为一个新文件。

你需要撤销你的更改,然后使用:

git mv <old path> <new path>

现在在git状态中,您将看到文件的移动而不是删除一个文件并创建一个新文件。


4
这是不正确的,或者至少是不完整的:当比较两个树或比较一个树和索引时,Git会基于其内部diff代码提供的标志来“事后”发现重命名。git status 命令始终设置“检查重命名”,但 git diffgit show 使用 -M--find-renames--no-renames 和你的配置设置 (diff.renamesdiff.renamelimit) 来控制重命名检测机制。如果您已经重命名了一个文件,那么使用 git rm --cached 删除旧路径,并添加新路径,就可以获得与使用 git mv 相同的效果。 - torek
我没有手动移动文件。我正在尝试将上游仓库与我的合并。它已经在上游仓库中移动了。 - Sreekanth Pothanis

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接