两个目录中相同文件的Git Diff总是导致;更名为;
git diff--无索引--无前缀--摘要-U4000目录1目录2 这与预期的一样,因为它返回两个目录之间所有文件的差异。添加的文件按预期输出,删除的文件也会产生预期的差异输出 但是,由于diff将文件路径作为文件名的一部分考虑在内,因此两个不同目录中具有相同名称的文件会导致diff输出带有重命名标志,而不是更改两个目录中相同文件的Git Diff总是导致;更名为;,git,version-control,diff,git-branch,Git,Version Control,Diff,Git Branch,git diff--无索引--无前缀--摘要-U4000目录1目录2 这与预期的一样,因为它返回两个目录之间所有文件的差异。添加的文件按预期输出,删除的文件也会产生预期的差异输出 但是,由于diff将文件路径作为文件名的一部分考虑在内,因此两个不同目录中具有相同名称的文件会导致diff输出带有重命名标志,而不是更改 有没有办法告诉git不要考虑diff中的完整文件路径,而只查看文件名,就好像文件来自同一个目录一样 git有没有办法知道不同目录中同一文件的副本是否被重命名?我不知道该怎么做,除非它
这里有许多问题,它们的答案交织在一起。让我们从重命名和复制检测开始,然后转到分支 重命名检测 但是,由于diff将文件路径作为文件名的一部分考虑在内,因此两个不同目录中具有相同名称的文件会导致diff输出带有重命名标志,而不是更改 这是不对的。(以下文字旨在说明第1项和第2项。) 尽管您使用的是
--no index
(大概是为了让Git在存储库之外的目录上工作),Git的diff代码在所有情况下的行为都是相同的。为了区分(比较)两个树中的两个文件,Git必须首先确定文件标识。也就是说,有两组文件:位于“左侧”或源目录树(第一个目录名)中的文件,以及位于“右侧”或目标目录树(第二个目录名)中的文件。左侧的某些文件与右侧的某些文件相同。左侧的一些文件是没有相应右侧文件的不同文件,即它们已被删除。最后,右侧的一些文件是新的,即它们已创建
“相同文件”的文件不必具有相同的路径名。在本例中,这些文件已重命名
下面是它的详细工作原理。请注意,在使用git diff--no index dir1 dir2
时,“完整路径名”有所修改:“完整路径名”是去掉dir1
和dir2
前缀后剩下的内容
在比较左侧树和右侧树时,具有相同完整路径名的文件通常会自动视为“同一文件”。我们将所有这些文件放入一个“要更改的文件”队列中,没有一个文件会显示为被重命名。注意这里的“正常”一词,我们稍后会回到这里
这就剩下了两个文件列表:
- 存在于左侧但不存在于右侧的路径:源而不存在目标
- 存在于右侧但不存在于左侧的路径:无源的目标
git diff
这样做:设置--no renames
标志以禁用重命名检测
或者,Git可以继续使用更智能的算法:设置--find renames
和/或-M
标志来完成此操作。在Git版本2.9及更高版本中,默认情况下启用重命名检测
现在,Git如何确定源文件与目标文件具有相同的标识?他们有不同的道路;左侧的a/b/c.txt
对应于哪个右侧文件?它可能是d/e/f.bin
,或者d/e/f.txt
,或者a/b/rename.txt
,等等。实际的算法相对简单,过去没有将最终名称组件生效(我不确定现在是否生效,Git正在不断发展):
- 如果有内容完全匹配的源文件和目标文件,请将它们配对。因为Git散列内容,所以这种比较非常快。我们可以通过查看左侧的
a/b/c.txt的散列ID将其与右侧的每个文件进行比较,只需查看它们的所有散列ID即可。因此,我们首先运行所有源文件,找到匹配的目标文件,将新的对放入diff队列,并将它们从两个列表中拉出
- 对于所有剩余的源文件和目标文件,运行一个高效但不适合于
输出的算法来计算“文件相似性”。源文件至少与某个目标文件类似,会导致配对,并且该文件对将被删除。默认阈值为50%:如果启用了重命名检测而未选择特定阈值,则此时仍在列表中且50%相似的两个文件将配对git diff
- 将删除或创建所有剩余文件
git diff
继续区分配对的相同标识文件,并告诉我们删除的文件将被删除,新创建的文件将被创建。如果相同标识文件的两个路径名不同,git diff
表示该文件已重命名
任意文件配对代码非常昂贵(即使同名配对代码非常便宜),因此Git对进入这些配对源和目标列表的名称数量有限制。该限制是通过git config diff.renameLimit配置的。多年来,默认值一直在攀升,现在是数千个文件。您可以将其设置为0
(零),使Git使用自己的内部代码
...--o--o--o <-- branch1
\
o--o--o <-- branch2
$ git diff branch1 branch2
$ git diff 1234567 89abcde
...--o--o <-- tip1
\
o--o <-- tip2, tip3