我fork了一个仓库并更改了文件A。现在,上游仓库中的文件A已经移动到子目录中。我正在尝试将上游仓库合并到我的分支中。
Git认为文件A已被删除,同时在新的子目录中创建了一个新的文件(这可能是因为他们上游如何移动该文件)。
我想以最小的影响将我的修改内容合并到该文件的新位置,并保留提交历史等信息。请问有什么方法可以做到这一点吗?
git merge
本身的情况)来“事后”检测重命名。(Linus Torvalds认为这是一种特性,例如请参见此SO问题。)git merge
将启用合并检测,并使用默认的相似度指数50%运行git的内部差异,除非您进行其他配置。1同样,git diff
也有一些可配置的默认值。如果您在合并基础和上游之间手动运行git diff --find-renames -M50%
,那么您可能是好的(但请参见有关配置的注释1)。-X
选项中的rename-threshold
值(rename-threshold
首次出现在git 1.7.4中)。有关详细信息,请参见文档。
merge.renameLimit
设置为要考虑的文件数,在重命名检测方面。如果您没有设置它,则当前默认值为1000个文件(但默认值随时间而变化)。此外,如果您没有设置它,则合并使用diff.renameLimit
,因此您可以仅设置这两个值,并且diff和merge都使用这两个值。文件重命名检测的工作方式有些复杂,但通过示例足够简单描述。假设Git正在比较提交12345
和提交67890
,在12345
中有路径名为A
、B/C
和D
的文件;但在67890
中有路径名为B/gronk
、B/C
和D
的文件。这意味着路径A
已经不存在,但新路径B/gronk
已经出现。Git将记住这样的路径(高达重命名限制值),并将比较12345:A
和67890:B/gronk
的内容。如果文件“足够相似”,Git将宣布12345:A
被重命名为67890:B/gronk
。你需要使用git mv
而不是仅仅使用mv
来移动文件。
由于git
会对内容进行快照,它并不关心文件名(文件名存储在idx文件中作为元数据)。
如果你只是简单地移动文件,git将无法“理解”你想要移动它,并将把它视为一个新文件。
你需要撤销你的更改,然后使用:
git mv <old path> <new path>
现在在git状态中,您将看到文件的移动而不是删除一个文件并创建一个新文件。
git status
命令始终设置“检查重命名”,但 git diff
和 git show
使用 -M
、--find-renames
、--no-renames
和你的配置设置 (diff.renames
和 diff.renamelimit
) 来控制重命名检测机制。如果您已经重命名了一个文件,那么使用 git rm --cached
删除旧路径,并添加新路径,就可以获得与使用 git mv
相同的效果。 - torek
git merge origin/master
(或者您的上游分支叫什么),会发生什么? - knittl