git diff:忽略某些正则表达式的删除或插入

git diff: ignore deletion or insertion of certain regex

如果添加或删除了以下表达式,我正在尝试使用 git diff 查找特定文件类型的两个版本之间的差异:

(****)

根据 the git diff Documentation,参数 -G 就是我要查找的内容。所以我尝试了以下方法:

git diff -G '\(\*\*\*\*\)' -- *.fileEnding

不幸的是,它不起作用,文件中的所有其他差异也被返回。顺便说一句,我对正则表达式不是很熟悉。

编辑:我认为我的问题需要更具体一些:现在我有以下情况:一个文件有与正则表达式匹配的更改和不匹配的更改。在我的脚本中,我试图做这样的事情(伪代码):

if((git diff -G '\(\*\*\*\*\)' -- *.fileEnding)==(git diff -- *.fileEnding)) print "Only changes in (****)";

如果某些文件仅在 (****) 中有更改而其他文件有不同的更改,则工作正常。但是一旦一个文件同时具有两者就不起作用

TL;DR

Git 的 git diff 不会那样做。

详细解释

文档具有误导性。

-G 参数对 git diff 完全没有任何作用。相反,-G 实际上是 git log 的参数(及其姊妹命令 git rev-list,以及任何调用这些其他命令的命令;但最好只是根据 git log,我想)。

git diffgit log 命令 分享 他们的一些文档(足够合理——他们分享他们的一些代码,特别是差异生成代码git log 用来将任何一个提交与其父项进行比较。

git log 正在 select 提交时,您可以告诉它 select 一些 特定的 提交(在 selection 已经由修订说明符制作)。 -G 论点就是这样一个 selector,非常相似的 -S 论点也是如此。 -S 默认接受字符串,而不是正则表达式;但您可以添加 --pickaxe-regex 以使 -S 采用正则表达式。文档有例子,例子字面上直接引用git log:

-G<regex>

Look for differences whose patch text contains added/removed lines that match <regex>.

To illustrate the difference between -S<regex> --pickaxe-regex and -G<regex>, consider a commit with the following diff in the same file:

+    return !regexec(regexp, two->ptr, 1, &regmatch, 0);
...
-    hit = !regexec(regexp, mf2.ptr, 1, &regmatch, 0);

While git log -G"regexec\(regexp" will show this commit,
git log -S"regexec\(regexp" --pickaxe-regex will not (because the number of occurrences of that string did not change).

git diff 命令不是 git log 命令。

一般来说,git log 的工作方式是向它传递一个起始提交——例如哈希 ID,或者分支或标签名称——然后它:

  • 显示提交,然后
  • 显示该提交的父项,然后
  • 显示父项的父项 ...

等等,一直回到第一次提交(或者当你厌倦了查看并退出寻呼机时)。也就是说,至少对于这些简单的情况,存在一个循环:

while (there is a commit $commit)
    parent = resolve_hash_id($commit + "^")
    show($commit)
    commit = $parent

如果添加 -p,"show" 步骤包括 git diff $parent $commit 的输出。

请注意 git diff 比较 恰好两个 提交(好吧,有一种特殊的差异称为 组合差异 对于合并提交,但 git log 默认情况下不显示它们, git diff 的正常使用也不显示它们)。 git log 的两个提交是父项和子项。如果你 运行 git diff 自己,你可以选择任意两个提交......但是当你这样做时,git diff 完全忽略任何 -G-S 个参数。(它可能应该抱怨它们的存在。)

-G-S的重点是影响[​​=16=]的正常行为。通常,当我们按照 git log 的方式一次查看一个提交时,我们更感兴趣的是 特定更改 特定文件(或一组文件)。我们可以使用 -G-S 告诉 git log: 生成差异,但是如果没有变化,则根本不显示提交. 这样我们就只会看到那些有这些变化的提交。 (添加文件名,例如 git log stop..start -- path/to/file1.txt,也将差异限制在这些文件上。与 -S-G 不同,that 部分 git diff 一起工作吗。)

你能做什么

如果您不知道要进行哪些修订,可以使用git log(或其面向脚本的姊妹命令git rev-list)来筛选候选人。在这里,您可以使用-G。您不必现在就获得差异,但如果您愿意,也可以。如果 -G 不仅让你得到 可能的 候选人,而且实际上让你得到 正确的 候选人,你就完成了,你可以停止这里。

如果您仍然有太多候选者并且需要完整的差异来进一步减少它们,您现在可以 运行 git diff 在第一步获得的哈希 ID 上(git loggit rev-list)。对于这些提交中的每一个,您必须选择与哪个提交进行比较:可能是候选列表中的某个提交,或者可能是在这个特定候选之前或之后的提交。现在您不再拥有 -G 工具:要搜索差异,您将需要一些外部搜索工具,例如 grep。这部分由你来写。

公认的答案是 -G 不适用于 git diff,这是错误的。它绝对是:

git diff -G '\(\*\*\*\*\)'

将在数百个更改的文件中,return 只有具有 (****) 的文件作为其更改之一。

最初的发布者(我认为)承认了这一点,但不想在同一文件中看到其他更改。值得澄清的是 git diff 确实有 -G 并且它可以完成困难的部分(使用 git 2.20.1 测试)。使用 -G 仅显示更改的文件并使用 grep 仅显示这些文件中需要的部分将导致很少的误报:

git diff -G '\(\*\*\*\*\)' -- *yml | grep -n1 '(\*\*\*\*)'

将仅显示文本 (****) 已更改的行,以及一些上下文(足以看出它已更改为什么)。

另请参阅 以了解 -G 与差异的使用。