4

我刚刚经历了重命名/重组和重构功能分支上的大型代码库的痛苦过程。在此过程中,我进行了少量更改的增量签入,以确保 git 识别重命名。但是,现在我将此功能合并回我的开发分支,Git 似乎没有“记住”这些重命名,而是将它们视为删除/添加。设置不同的重命名阈值似乎没有帮助。

git 不应该从以前的提交中知道文件被重命名/移动了吗?

编辑 奇怪的是,如果我将 dev 合并到我的功能分支中,而不是反之亦然,git 似乎可以识别重命名。我最终这样做了,然后将 dev 重置到我的功能分支的顶部。在这种情况下,合并的方向是否重要?

4

2 回答 2

2

git实际上并不跟踪重命名——它依赖于“重命名检测”算法来检测重命名,如Git FAQ中所述:

Git 必须与许多不同的工作流程进行互操作,例如某些更改可能来自补丁,其中重命名信息可能不可用。依赖显式重命名跟踪使得合并两棵完成完全相同的事情的树变得不可能,除了一棵作为补丁(创建/删除),另一棵使用其他启发式方法。

其次,跟踪重命名实际上只是跟踪内容在树中如何移动的一种特殊情况。在某些情况下,您可能对查询何时添加或移动到其他文件感兴趣。通过仅在需要时重新创建此信息的能力,Git 旨在提供一种更灵活的方式来跟踪您的树的变化情况。

但是,这并不意味着 Git 不支持重命名。Git 中的 diff 机制支持自动检测重命名,这是通过 git-diff-* 命令系列的“-M”开关打开的。重命名检测机制由 git-log(1) 和 git-whatchanged(1) 使用,例如,'git log -M' 将提供带有重命名信息的提交历史记录。Git 还支持有限形式的跨重命名合并。分配责备的两个工具 git-blame(1) 和 git-annotate(1) 都使用自动重命名检测代码来跟踪重命名。

作为一个非常特殊的情况,'git log' 版本 1.5.3 及更高版本具有'--follow' 选项,允许您在给定单个路径时跟随重命名。

因此,如果你重构并重命名了一个文件,它与旧文件的相似度将非常小,结果statuslog可能表明该文件被删除然后添加。

即使通过重构,一些选项也可能有助于检测重命名:

  • -M<n>

    检测重命名。如果指定了n,它是相似性指数的阈值(即添加/删除量与文件大小相比)。例如,-M90% 表示如果 90% 以上的文件没有更改,git 应该将删除/添加对视为重命名。

  • -w

    忽略空格数量的变化。这将忽略行尾的空格,并认为一个或多个空格字符的所有其他序列是等效的。

  • -B<n>

    将完整的重写更改分解为一对删除和创建。

-B很有用,因为它可以允许将文件视为重命名源,即使它们已被更改;例如,如果您将 90% 移至foo.cbar.c但将某些功能留在foo.c.

于 2012-09-21T04:54:18.220 回答
0

您可能会违反 git config 设置:merge.renameLimit

此设置默认非常低(与大型代码库相比),如果您合并太多文件,则不会尝试检测重命名,因为担心它会变慢。一个方向的合并很可能超过了限制,而另一个方向没有,因此出现了奇怪的重命名检测行为。

尝试通过以下方式提高限制

git config merge.renameLimit 9999

并重试。

于 2014-09-08T13:43:54.713 回答