如何使git diff忽略注释

时间:2013-05-13 16:52:29

标签: git diff git-diff

我正在尝试生成在特定提交中更改的文件列表。问题是,每个文件在文件顶部的注释中都有版本号 - 并且由于此提交引入了新版本,这意味着每个文件都已更改

我不关心更改的注释,所以我想让git diff忽略所有匹配^\s*\*.*$的行,因为这些都是注释(/ * * /的一部分)。

我找不到任何方法来告诉git diff忽略特定的行。

我已经尝试过设置一个textconv属性,让git在传播文件之前将文件传递给sed,这样sed就可以删除有问题的行 - 这个问题就是git diff --name-status没有实际上是差异文件,只是比较哈希值,当然所有哈希值都已经改变了。

有没有办法做到这一点?

7 个答案:

答案 0 :(得分:11)

这是一个适合我的解决方案。我已经在git (log|diff) -G<regex>选项上写了解决方案和一些其他缺少的文档。

基本上使用与上述相同的解决方案,但专门针对以*#开头的评论,有时候是*之前的空格......但仍需要允许#ifdef#include等更改。

向前看并向后看似乎-G选项似乎不支持,?也不支持,我也遇到了使用*的问题。 +似乎运作良好。

(注意,在Git v2.7.0上测试)

多行注释版

git diff -w -G'(^[^\*# /])|(^#\w)|(^\s+[^\*#/])'
  • -w忽略空格
  • -G仅显示与以下正则表达式匹配的差异线
  • (^[^\*# /])任何不以星号或散列或空格开头的行
  • (^#\w)任何以#开头,后跟字母
  • 的行
  • (^\s+[^\*#/])任何以空格开头后跟注释字符
  • 的行

基本上,svn挂钩会立即修改每个文件,并修改每个文件上的多行注释块。现在,我可以根据svn在评论中删除的fyi信息来区分我对svn的更改。

从技术上讲,这将允许在diff中显示像#TODO这样的python和bash注释,如果在c ++中使用除法运算符在新行上启动,则可以忽略它:

a = b
    / c;

git中-G的文档似乎也很缺乏,所以这里的信息应该会有所帮助:

git diff -G<regex>

  

<强> -G<regex>

     

查找其修补程序文本包含与<regex>匹配的添加/删除行的差异。

     

为了说明-S<regex> --pickaxe-regex-G<regex>之间的区别,
  考虑在同一个文件中使用以下差异进行提交:

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

虽然git log -G"regexec\(regexp"会显示此提交,但是   git log -S"regexec\(regexp" --pickaxe-regex不会   (因为该字符串的出现次数没有改变)。

     

有关详细信息,请参阅gitdiffcore(7)中的 pickaxe 条目。

(注意,在Git v2.7.0上测试)

  • -G使用基本的正则表达式。
  • 不支持?*!{}正则表达式语法。
  • 使用()和OR-ing组进行分组可以使用|
  • 支持诸如\s\W等通配符字符。
  • 前瞻和后视是支持。
  • 开始和结束行锚^$工作。
  • 自Git 1.7.4开始提供功能。

排除的文件v排除的差异

请注意,-G选项会过滤要分散的文件。

但是如果一个文件被“分散”,那么“ all 之前被”排除/包含“的那些行将在差异中显示。

实施例

仅显示至少有一行提及foo的文件差异。

git diff -G'foo'

显示除以#

开头的行以外的所有内容的文件差异
git diff -G'^[^#]'

显示提及FIXMETODO

的差异的文件
git diff -G`(FIXME)|(TODO)`

另请参阅git log -Ggit grepgit log -S--pickaxe-regex--pickaxe-all

更新:-G选项正在使用哪个正则表达式工具?

https://github.com/git/git/search?utf8=%E2%9C%93&q=regcomp&type=

https://github.com/git/git/blob/master/diffcore-pickaxe.c

if (opts & (DIFF_PICKAXE_REGEX | DIFF_PICKAXE_KIND_G)) {
    int cflags = REG_EXTENDED | REG_NEWLINE;
    if (DIFF_OPT_TST(o, PICKAXE_IGNORE_CASE))
        cflags |= REG_ICASE;
    regcomp_or_die(&regex, needle, cflags);
    regexp = &regex;

// and in the regcom_or_die function
regcomp(regex, needle, cflags);

http://man7.org/linux/man-pages/man3/regexec.3.html

   REG_EXTENDED
          Use POSIX Extended Regular Expression syntax when interpreting
          regex.  If not set, POSIX Basic Regular Expression syntax is
          used.

// ...

   REG_NEWLINE
          Match-any-character operators don't match a newline.

          A nonmatching list ([^...])  not containing a newline does not
          match a newline.

          Match-beginning-of-line operator (^) matches the empty string
          immediately after a newline, regardless of whether eflags, the
          execution flags of regexec(), contains REG_NOTBOL.

          Match-end-of-line operator ($) matches the empty string
          immediately before a newline, regardless of whether eflags
          contains REG_NOTEOL.

希望能帮到每个人。

答案 1 :(得分:7)

git diff -G <regex>

并指定与版本号行不匹配的正则表达式。

答案 2 :(得分:6)

我发现使用git difftool启动外部差异最简单:

git difftool -y -x "diff -I '<regex>'"

答案 3 :(得分:2)

找到解决方案。我可以使用这个命令:

git diff --numstat --minimal <commit> <commit> | sed '/^[1-]\s\+[1-]\s\+.*/d'

显示提交之间更改了1行以上的文件,这样可以删除仅更改为注释中版本号的文件。

答案 4 :(得分:0)

也许这样的bash脚本(我没有测试代码,让我知道你是否可以使它工作)

#!/bin/bash
git diff --name-only "$@" | while read FPATH ; do
    LINES_COUNT=`git diff --textconv "$FPATH" "$@" | sed '/^[1-]\s\+[1-]\s\+.*/d' | wc -l`
    if [ $LINES_COUNT -gt 0 ] ; then
        echo -e "$LINES_COUNT\t$FPATH"
    fi
done | sort -n

答案 5 :(得分:0)

在'git diff'输出中使用'grep':

git diff -w | grep -c -E "(^[+-]\s*(\/)?\*)|(^[+-]\s*\/\/)"

单独评论行更改可以计算。 (A)

使用'git diff --stat'输出:

git diff -w --stat

可以计算所有行变化。 (B)

获取非注释源行更改(NCSL)计数,从(B)中减去(A)。

说明: 在'git diff'输出中(忽略空格更改),

  • 注意以'+'或' - '开头的行,这意味着 修改过的。
  • 此后可以有可选的空白字符。 '\ s *'
  • 然后查找注释行模式'/ *'(或)只是'*'(或)'//'。
  • 因为'-c'选项是用grep给出的,只需打印计数即可。删除“-c”选项以在差异中单独查看注释。

注意:由于以下假设,评论行数可能会出现轻微错误,结果应视为大概数字。

  • 1。)源文件基于C语言。 Makefile,Shell脚本文件有不同的约定'#'来表示注释行,如果它们是diffset的一部分,则不会计算注释行。

  • 2。)换行的GIT约定:如果修改了一行,GIT会将其视为删除该特定行并在那里插入一个新行,它可能看起来像是改变了2行,而实际上是线被修改。

    在下面的示例中,“FOO”的新定义看起来像两行更改。

    $ git diff --stat -w abc.h
    ...
    - #define FOO 7
    + #define FOO 105
    ...
    1个文件已更改,1个插入(+),1个删除( - )
    $

  • 3。)与模式不匹配的有效注释行(或)与模式匹配的有效源代码行可能会导致计算错误。

    在下面的示例中,不以'*'开头的“+ blah blah”行不会被检测为注释行。

           + /*   
           +  blah blah  
           + *   
           + */
    

    在下面的示例中,“+ * ptr”行将被计为注释行,因为它以*开头,尽管它是有效的源代码行。

            + printf("\n %p",  
            +         *ptr);  
    

答案 6 :(得分:0)

对于大多数语言,要正确执行此操作,您必须解析原始源文件/ ast,并以这种方式排除注释。

一个原因是,差异可能不会涵盖多行注释的开头。另一个原因是,语言解析并不是一件容易的事,并且常常有一些事情可能会使幼稚的解析器崩溃。

我打算为python做到这一点,但是字符串黑客足以满足我的需求。

对于python,您可以使用自定义过滤器忽略注释和尝试忽略文档字符串,例如:

https://gist.github.com/earonesty/f76dec337ee64c5ae23c2be1557535a4

可以简单地修改该代码以产生文件名,而不是计数。

但是,它当然可以错误地将文档字符串的一部分计为“代码”(不适用于诸如覆盖率等内容)。