如何对移动/重命名的文件进行 git diff?

Posted

技术标签:

【中文标题】如何对移动/重命名的文件进行 git diff?【英文标题】:How to do a git diff on moved/renamed file? 【发布时间】:2011-08-09 11:35:54 【问题描述】:

我使用git mv 移动了一个文件。现在我想对新文件进行比较,以将其与旧文件(旧的,现在不存在的名称)进行比较。

我该怎么做?

【问题讨论】:

很快(git 2.9,2016 年 6 月),一个简单的 git diff -- yourRenamedFile 就足够了。见my answer below 【参考方案1】:

只需运行git diff,不带任何参数,或git diff -- newfilename。 git 足够聪明,可以比较正确的文件/内容(即重命名前的原始内容与重命名后的更改内容)

【讨论】:

git 在大多数情况下绝对不够聪明。只需 git mv 单个文件,然后将暂存状态与另一个相同的分支进行比较,将产生“所有内容都已删除并重新创建”差异,除非使用 -M【参考方案2】:

除了knittl wrote,你可以随时使用:

git diff HEAD:./oldfilename newfilename

其中HEAD:./oldfilename 表示上次提交中的旧文件名(在 HEAD 中),相对于当前目录。

如果你没有足够新的 git,你将不得不使用:

git diff HEAD:path/to/oldfilename newfilename

【讨论】:

谢谢。您还可以指定特定的提交而不是 head,即git diff 39fa7c77e85c51d43ea0cf30d33aec8721812e9e:./oldfilename newfilename 如果不清楚,您还可以指定分支名称或任何其他参考,例如:git diff branch:old/filen.name newfilename 第一种形式适用于我,如果您将cd 加入目录并且不要在commit:path 对之前添加--。 Git 似乎对这里的语法很挑剔。 @dhardy <commit-ish>:<pathname> 语法是一个对象标识符,类似于 Git;在--之后,Git 只需要文件名。 这种语法对我有用,其中 -M 只是将整个文件显示为已更改 - git version 2.30.1 (Apple Git-130)。无论有没有前导./,它都可以工作。 - 谢谢。【参考方案3】:

无论出于何种原因,使用 HEAD:./oldfilename(或绝对路径)对我不起作用,但 HEAD:oldfilename 对我有用(感谢 cmn):

git diff HEAD:oldfilename newfilename
git diff 2a80f45:oldfilename f65f3b3:newfilename

HTH

【讨论】:

也许你的 git 太老了,看不懂HEAD:./oldfilename 这是最通用的答案。如果文件编辑过多,-M 似乎不起作用。【参考方案4】:

你需要使用 -M 让 git 在 diffing 时自动检测移动的文件。仅使用 knittl 提到的 git diff 对我不起作用。

很简单:git diff -M 应该这样做。

这个开关的文档是:

-M[<n>], --find-renames[=<n>]
       Detect renames. If n is specified, it is a threshold on the similarity index 
       (i.e. amount of addition/deletions compared to the file’s size). For example, 
       -M90% means git should consider a delete/add pair to be a rename if more than
       90% of the file hasn’t changed.

【讨论】:

救命稻草!我的 git diff 现在好多了。 1) 始终使用此选项是否安全? 2) 我可以将此选项作为默认行为添加到我的~/.gitconfig 吗? 请注意,重命名检测仅在新旧文件都出现在git diff 处理的文件集合中时才有效。在单个(重命名)文件上运行 git diff -M 不会报告重命名。 这对我不起作用,但git log --follow -- file_after_move.txt 效果很好。它显示了整个历史,包括搬家之前。有任何想法吗?我正在运行git version 2.11.0.windows.1 用于检测副本的-C 选项非常有用且类似。我将它与-M 一起使用,以查看我将一个文件重构为两个文件的差异(两个名称都不匹配原始文件)。【参考方案5】:

使用 git 2.9(2016 年 6 月),您不必再添加 -Mgit diff 默认使用-M

参见Matthieu Moy (moy)@commit 5404c11、commit 9501d19、commit a9276a6、commit f07fc9e、commit 62df1e6(2016 年 2 月 25 日)。(由Junio C Hamano -- gitster -- 合并到commit 5d2a30d, 2016 年 4 月 3 日)

diff:默认激活diff.renames

重命名检测是一个非常方便的功能,新用户不应该 必须深入研究文档才能从中受益。

激活重命名检测的潜在反对意见是它 有时会失败,有时会很慢。但是重命名检测是 在“git status”和“git merge”等几种情况下已经默认激活,因此激活diff.renames不会从根本上改变 情况。当重命名检测失败时,它现在一直失败 在“git diff”和“git status”之间。

此设置不影响管道命令,因此编写良好 脚本不会受到影响。

The new tests for this feature are here.

【讨论】:

【参考方案6】:

git diff -M 像其他人所说的那样激活重命名检测(正如@VonC 指出的那样,它默认从 git 2.9 激活)。但是如果你有一个大的变更集,不精确的重命名检测可能仍然会再次被关闭。 Git 将显示如下警告,在您正在查看的差异中很容易错过:

warning: inexact rename detection was skipped due to too many files.
warning: you may want to set your diff.renameLimit variable to at least 450 and retry the command.

在这种情况下,请按照 git 的建议设置配置选项,例如

git config diff.renamelimit 450

然后重新运行你的 diff 命令。

【讨论】:

以上是关于如何对移动/重命名的文件进行 git diff?的主要内容,如果未能解决你的问题,请参考以下文章

git diff 重命名文件

Linux下对文件夹和文件重命名、移动和删除

git:重命名文件并更改文件内容

如何使 git-diff 和 git log 忽略新文件和已删除文件?

git 检测您的 Java 项目中的重命名/移动效果不佳 - 该怎么办?

Git squash 重命名文件的提交(保留历史记录)