使用正则表达式过滤diff

时间:2011-11-21 23:14:32

标签: regex git diff

似乎能够过滤差异非常方便,因此不会显示琐碎的变化。我想写一个正则表达式,它将在该行上运行,然后传递另一个字符串,使用捕获的参数生成规范形式。如果之前和之后的行产生相同的输出,那么它们将从差异中移除。

例如,我正在开发一个PHP代码库,其中大量的数组访问被写为my_array[my_key],如果my_array["my_key"] my_key那么{{1}}常量是{{1}}定义。生成差异是很有用的,其中线上唯一的变化是没有添加一些引号。

我无法一次更改所有内容,因为我们没有足够的资源来测试整个代码库,因此每当我对函数进行更改时都要修复它。我怎样才能做到这一点?还有其他类似的东西,我可以用来实现类似的结果。例如,一个更简单的方法可能是跳过规范形式,只看输入是否转换为输出。顺便说一句,我正在使用Git

8 个答案:

答案 0 :(得分:7)

$ git diff --help

-G<regex>
    Look for differences whose added or removed line matches the given <regex>.

修改

经过一些测试,我有类似

的东西
git diff -b -w --word-diff-regex='.*\[[^"]*\]'

然后我输出如下:

diff --git a/test.php b/test.php
index 62a2de0..b76891f 100644
--- a/test.php
+++ b/test.php
@@ -1,3 +1,5 @@
<?php

{+$my_array[my_key]+} = "test";

?>
diff --git a/test1.php b/test1.php
index 62a2de0..6102fed 100644
--- a/test1.php
+++ b/test1.php
@@ -1,3 +1,5 @@
<?php

some_other_stuff();

?>

也许它会对你有所帮助。我在http://www.rhinocerus.net/forum/lang-lisp/659593-git-word-diff-regex-lisp-source.html找到了它,并且有关此thread

的更多信息

<强> EDIT2

git diff -G'\[[A-Za-z_]*\]' --pickaxe-regex

答案 1 :(得分:6)

Git的diff命令似乎没有任何选项来支持你想要做的事情。但是,您可以使用GIT_EXTERNAL_DIFF environment variable和自定义脚本(或使用首选脚本或编程语言创建的任何可执行文件)来操作补丁。

我假设你在Linux上;如果没有,你可以调整这个概念,以适应您的环境。假设你有一个Git仓库,其中HEAD有一个文件file05,其中包含:

line 26662: $my_array[my_key]

包含以下内容的文件file06

line 19768: $my_array[my_key]
line 19769: $my_array[my_key]
line 19770: $my_array[my_key]
line 19771: $my_array[my_key]
line 19772: $my_array[my_key]
line 19773: $my_array[my_key]
line 19775: $my_array[my_key]
line 19776: $my_array[my_key]

您将file05更改为:

line 26662: $my_array["my_key"]

您将file06更改为:

line 19768: $my_array[my_key]
line 19769: $my_array["my_key"]
line 19770: $my_array[my_key]
line 19771: $my_array[my_key]
line 19772: $my_array[my_key]
line 19773: $my_array[my_key]
line 19775: $my_array[my_key2]
line 19776: $my_array[my_key]

使用以下shell脚本,我们将其称为mydiff.sh并将其放在PATH中的某个位置:

#!/bin/bash
echo "$@"
git diff-files --patch --word-diff=porcelain "${5}" | awk '
/^-./ {rec = FNR; prev = substr($0, 2);}
FNR == rec + 1 && /^+./ {
    ln = substr($0, 2);
    gsub("\\[\"", "[", ln);
    gsub("\"\\]", "]", ln);
    if (prev == ln) {
        print " " ln;
    } else {
        print "-" prev;
        print "+" ln;
    }
}
FNR != rec && FNR != rec + 1 {print;}
'

执行命令:

GIT_EXTERNAL_DIFF=mydiff.sh git --no-pager diff

将输出:

file05 /tmp/r2aBca_file05 d86525edcf5ec0157366ea6c41bc6e4965b3be1e 100644 file05 0000000000000000000000000000000000000000 100644
index d86525e..c2180dc 100644
--- a/file05
+++ b/file05
@@ -1 +1 @@
 line 26662: 
 $my_array[my_key]
~
file06 /tmp/2lgz7J_file06 d84a44f9a9aac6fb82e6ffb94db0eec5c575787d 100644 file06 0000000000000000000000000000000000000000 100644
index d84a44f..bc27446 100644
--- a/file06
+++ b/file06
@@ -1,8 +1,8 @@
 line 19768: $my_array[my_key]
~
 line 19769: 
 $my_array[my_key]
~
 line 19770: $my_array[my_key]
~
 line 19771: $my_array[my_key]
~
 line 19772: $my_array[my_key]
~
 line 19773: $my_array[my_key]
~
 line 19775: 
-$my_array[my_key]
+$my_array[my_key2]
~
 line 19776: $my_array[my_key]
~

此输出未显示file05file06中添加的引号的更改。外部diff脚本基本上使用Git diff-files命令来创建补丁,并通过GNU awk脚本过滤输出来操作它。此示例脚本不处理GIT_EXTERNAL_DIFF中提到的旧文件和新文件的所有不同组合,也不会输出有效的修补程序,但它应该足以让您入门。

您可以使用Perl regular expressionsPython difflib或任何您认为合适的方式来实现符合您需求的外部差异工具。

答案 2 :(得分:3)

grepdiff可用于过滤diff文件中的帅哥。

$ git diff -U1 | grepdiff 'console' --output-matching=hunk

它只显示与给定字符串匹配的帅哥&#34; console&#34;。

答案 3 :(得分:2)

来自我自己的git --help

  

- 字的Diff-正则表达式= <regex>

     

使用<regex>来决定单词是什么,而不是将非空格的运行视为单词。还暗示--word-diff除外              它已经启用了。              <regex>的每个非重叠匹配都被视为一个单词。这些匹配之间的任何内容都被视为空格和              忽略(!)以找到差异。您可能希望将|[^[:space:]]附加到正则表达式以确保              它匹配所有非空白字符。包含换行符的匹配项会在换行符处以静默方式截断(!)。              也可以通过diff驱动程序或配置选项设置正则表达式,请参阅gitattributes(1)或git-config(1)。明确地给它              覆盖任何差异驱动程序或配置设置。差异驱动程序会覆盖配置设置。

答案 4 :(得分:1)

在第一步中规范化输入文件,然后比较规范化的文件。这使您可以最大程度地控制该过程。例如。您可能只想将正则表达式应用于代码的非HTML部分,而不是在字符串内部,而不是在注释内部(或完全忽略注释)。 计算规范化代码的差异是做这些事情的正确方法;在单行上使用正则表达式更容易出错,最多只是一个黑客攻击。

一些差异工具,例如meld允许隐藏“无关紧要”的差异,并附带一组默认模式,例如隐藏仅限空白的更改。我想这就是你想要的。

答案 5 :(得分:0)

我使用的方法结合git diff并在结果上应用正则表达式匹配。在一些测试代码(PERL)中,我知道当测试的结果文件中存储的OutputFingerprint没有改变时,测试是成功的。

首先,我做了一个

my $matches = `git diff -- mytestfile`

然后评估结果:

if($matches =~ /OutputFingerprint/){
  fail();
  return 1;
}else{
  ok();
  return 0;
}

答案 6 :(得分:0)

我提供了一个类似问题的答案here

我制作了一个 git 函数来执行此操作,并将正则表达式作为唯一输入。只需将其输入您的 gitconfig(我使用我的全局 gitconfig)并将其与 git regexadd <regex> 一起使用。

[alias]
        regexadd = "!f() { git diff -U0 \
                | grepdiff -E $1 --output-matching=hunk \
                | git apply --cached --unidiff-zero; }; f"

答案 7 :(得分:-2)

如果目标是最大限度地减少琐碎的差异,您可以考虑我们的SmartDifferencer工具。

这些工具会比较语言语法,而不是布局,因此会忽略许多微不足道的更改(布局,修改后的注释,甚至更改数字的基数),也不会报告。 每个工具都有一个完整的语言解析器;有许多语言的版本,包括PHP。

它不会将示例$ FOO [abc]处理为与$ FOO [“abc”]“语义相同”,因为它们不是。如果abc actaully定义为常量,则$ FOO [“abc”]在语义上不等同。