41

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

我不在乎更改的评论,所以我想差异比较忽略所有匹配的行^\s*\**$,因为这些都是注释(/**/的一部分)。

我找不到任何方法来告诉你差异比较忽略特定行。

我已经尝试设置一个textconv属性,使Git在比较文件之前将文件传递给sed,这样sed就可以删除有问题的行—问题是git diff—名称状态实际上并不区分文件,只是比较哈希值,当然所有的哈希值都改变了。

有办法做到这一点吗?

5
  • 胡乱猜测。。。你试过了吗git diff--名称状态--文本转换? 或者也许git diff—仅名称? 评论 2013年5月13日16:55
  • 是的,我只使用了名称,但它会返回(如我所说)每个文件,因为每个文件的注释都已更改--textconv不起作用,因为正如我在帖子中所说,git在没有生成完整diff时会忽略它。 评论 2013年5月13日17:04
  • 1
    的可能副本忽略git-diff中与字符串匹配的更改 评论 2015年6月23日14:08
  • 1
    @richvdh我认为这些问题非常相似,可以认为是重复的,但它们有不同的正确答案,而且这个问题有其他问题没有的额外答案,所以我认为保留这两个问题是有价值的。 评论 2015年6月23日15:23
  • 2
    相关:Git 2.30(2021年第1季度)将提议git diff-I<正则表达式>. 评论 2020年11月9日20:16

8个答案8

重置为默认值
23

这是一个很适合我的解决方案git(log|diff)-G<正则表达式>选项。

它基本上使用了与前面答案中相同的解决方案,但特别是针对以*或a#,有时在*…但仍需要允许#ifdef(如果定义),#包括等变化。

向前看和向后看似乎不受-G公司选项?一般来说,我在使用*也是。+不过,似乎工作得很好。

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

多行注释版本

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

基本上,SVN钩子现在修改进出的每个文件,并修改每个文件上的多行注释块。现在,我可以将我的更改与SVN进行比较,而无需SVN在评论中添加的FYI信息。

从技术上讲,这将允许使用Python和Bash注释,如#TODO公司在diff中显示,如果除法运算符从C++中的新行开始,则可以忽略:

a=b/c;

还有关于-G公司在Git中似乎非常缺乏,因此此处的信息应该有帮助:

git diff-G<正则表达式>

-G<正则表达式>

查找修补程序文本中包含匹配的添加/删除行的差异<正则表达式>.

为了说明-S<正则表达式>--选择正则表达式-G<正则表达式>,考虑在同一文件中使用以下diff进行提交:

+返回!regexec(regexp,two->ptr,1,&regmatch,0);...-命中=!regexec(regexp,mf2.ptr,1,&regmatch,0);

While期间git log-G“regexec\(regexp)”将显示此承诺,git log-S“regexec\(regexp)”--选择正则表达式不会(因为该字符串的出现次数没有改变)。

请参阅鹤嘴锄报关进口gitdiffcore公司(7)了解更多信息。

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

  • -G公司使用基本正则表达式。
  • 不支持?,*,!,{,}正则表达式语法。
  • 与分组()OR-ing小组与|.
  • 通配符,例如\秒,\W公司支持等。
  • 长眼睛和长眼睛是支持。
  • 起点和终点线锚^$工作。
  • 该功能从Git 1.7.4开始提供。

排除的文件与排除的差异

请注意-G公司选项筛选将进行差异化的文件。

但如果一个文件得到“diffed”,那么之前“excluded/include”的那些行将全部的在差异中显示。

示例

仅显示文件差异,至少有一行提到foo公司.

git diff-G'foo'

显示除以#

git diff-G“^[^#]”

显示有差异的文件固定装置TODO公司

git diff-G`(FIXME)|(TODO)`

另请参见git日志-G,吉特格里普,git日志-S,--pickaxe-regex(选择正则表达式),以及--鹤嘴锄

-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(选择&(DIFF_PICKAXE_REGEX | DIFF_PIC KAXE_KIND_G)){int cflags=REG_EXTENDED | REG_NEWLINE;if(DIFF_OPT_TST(o,PICKAXE_IGNORE_CASE))cflags |=REG_ICASE;regcomp或die(&regex,指针,cflags);regexp=&regex;//在regcomor_die函数中regcomp(regex、needle、cflags);

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

注册_扩展解释时使用POSIX扩展正则表达式语法正则表达式。如果未设置,POSIX基本正则表达式语法为已使用。

// ...

注册_新线Match-any-character运算符与换行符不匹配。不包含换行符的非匹配列表([^…])不会匹配换行符。匹配行外运算符(^)与空字符串匹配紧跟在换行符之后,无论是否使用eflagsregexec()的执行标志,包含REG_NOTBOL。匹配行运算符($)匹配空字符串在换行符之前,无论eflags是否包含REG_NOTEOL。
10
  • 看起来它类似于“简单正则表达式”。en.wikibooks.org/wiki/Regular_Expressions/…
    – 菲亚特
    评论 2017年4月24日12:52
  • 这不可能完全正确,因为它接受一些非简单语法,例如+(我刚测试过)。 评论 2017年4月24日13:18
  • 请参阅我答案末尾的更新。我还没有成功测试“POSIX扩展正则表达式”。我的实证测试表明,它的效果并不完全相同。
    – 菲亚特
    评论 2017年4月24日13:51
  • @phyatt-这不起作用:git diff-G“^[^#]”。它仍然显示以开头的行#. 评论 2019年8月24日5:54
  • @MartinVegter如果文件至少有一个其他差异,语法仍会显示。如果文件只有注释差异,则结果中将排除该文件。
    – 菲亚特
    评论 2019年8月24日12:17
15
git diff-G<正则表达式>

并指定一个正则表达式匹配您的版本号行。

11

我发现它最容易使用git差异工具要启动外部差异工具:

git difftool-y-x“diff-I'<regex>'”
1
  • git中有限的regexp支持使其成为一个很好的选项,谢谢! 评论 2023年10月6日4:49
4

我找到了解决办法。我可以使用此命令:

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

显示在提交之间更改了多行的文件,这将删除只更改了注释中版本号的文件。

2

对“git diff”输出使用“grep”,

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

可以单独计算注释行的更改。(A)

使用“git diff--stat”输出,

git diff-w--统计

可以计算所有行更改。(B)

要获得非注释源代码行更改(NCSL)计数,请从(B)中减去(A)。

说明:

在“git-diff”输出中(其中忽略空白更改),

  • 注意以“+”或“-”开头的行,这表示修改后的行。
  • 后面可以有可选的空白字符。”\s*’
  • 然后查找注释行模式“/*”(或)仅“*”(或者)“//”。
  • 由于grep中提供了“-c”选项,因此只需打印计数即可。删除“-c”选项以仅在差异中查看注释。

注:由于以下假设,注释行计数可能会出现小错误,因此结果应作为大致数字。

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

  • 2.)更改行的Git约定:如果修改了一行,Git会将其视为删除了特定行,并在其中插入了一个新行,看起来可能有两行发生了更改,而实际上只有一行发生了修改。

    在下面的示例中,“FOO”的新定义看起来像是一个双线更改。$git差异--stat-w abc.h...-#定义FOO 7+#定义FOO 105...1个文件已更改,1个插入(+),1个删除(-)$
  • 3.)与模式不匹配的有效注释行(或)与模式匹配的有效源代码行可能会导致计算错误。

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

+ /*+等等+ *+ */

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

+printf(“\n%p”,+*ptr);
1

对于大多数语言,要正确执行,必须解析原始源文件/AST公司,并以此方式排除注释。

一个原因是多行注释的开头可能没有包含在diff中。另一个原因就是语言解析不是小事一桩,而且通常会有一些事情会使天真的解析器出错。

我本来打算为Python这样做,但字符串黑客已经足够满足我的需要了。

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

#!/usr/bin/env-python导入系统进口再进口导入配置分析器从fnmatch导入从unidiff导入PatchSetEXTS=[“py”]类Opts:#pylint:disable=too-few-public-methodsdebug=错误排除=[]定义filtered_hunks(fil):path_re=“.*[.](%s)$”%“|”.join(EXTS)对于PatchSet(fil)中的补丁:如果不匹配(path_re,path.path):持续排除=假如果Opts.exclude:如果Opts.debug:打印(“>”,patch.path,“=~”,Opts.exclude)对于Opts.exclude中的ex:如果fnmatch(patch.path,ex):排除=真如果排除在外:持续对于大块补丁:屈服块类类型:#pylint:disable=too-few-public-methods线路=“.”COMMENT=“#”DOCSTRING=“d”白色=“w”定义分类线(fil):对于filtered_hunks(fil)中的hunk:classify_hunk(hunk)产量定义分类线(lval):“”“对单个python行进行分类,注意注释、在docstring启动/停止和pure-whitespace中所做的最大努力。”“”lval=lval.rstrip(“\n\r”)remaining_lval=等级typ=典型。线路如果re匹配(r“^*$”,lval):return类型。白色,无,“”如果重新匹配(r“^*#”,lval):typ=典型。评论remaining_lval=“”其他:slug=重新匹配(r“^*(\”“\”“|'')(.*)”,等级)如果段塞:remaining_lval=段塞[2]slug=slug[1]return类型。DOCSTRING,slug,剩余_值return typ,无,剩余_lval定义classify_hunk(hunk):“”“对python diff-hunk的行进行分类,尝试记录注释和文档字符串。忽略上下文行。不保证检测到文档字符串(大文档字符串中间的更改不会启动。)使用AST可以解决这个问题,但这似乎有些过头了,不能在diff-only上完成。"""p=“”上一个类型=0pslug=无对于大块线条:lval=行值lval=lval.rstrip(“\n\r”)typ=典型。线路naive_typ,slug,remaining_lval=分类线(lval)如果p和p[-1]==“\\”:typ=上一个类型其他:如果prev_typ!=类型。DOCSTRING和naive_typ==类型。备注:类型=原始类型elif naive_typ==类型。文件字符串:如果prev_typ==类型。DOCSTRING和pslug==slug:#线的其余部分可能有东西类型,_,_=分类线(剩余值)其他:typ=类型。DOCSTRING公司pslug=段塞elif prev_typ==类型。文件字符串:#continue在此上下文/hunk中找到docstringtyp=典型。DOCSTRING公司p=等级prev_typ=典型如果类型==类型。文件字符串:如果重新匹配(r“(%s)*$”%pslug,remaining_lval):prev_typ=类型。线路如果line.is_context:持续产量类型,lval定义count_lines(fil):“”“总计更改的python代码行数,试图去除注释和文档字符串。删除/添加均计算在内。可能会错过一些事情,不要依赖精确的计数。"""计数=0对于分类行(fil)中的(typ,line):如果Opts.debug:打印(典型值,行)如果类型==类型。线路:计数+=1返回计数定义main():ops.debug=sys.argv中的“--debug”Opts.exclude=[]sys.argv中的use_ovrc=“--covrc”如果use_covrc:config=配置分析器。配置分析器()配置读取(“.coveragerc”)cfg={s:dict(config.items(s))for s in config.sections()}exclude=cfg.get(“报告”,{}).get(“省略”,[])Opts.exclude=[f.strip()用于exclude.split(“\n”)中的f对于范围内的i(len(sys.argv)):如果sys.argv[i]==“--排除”:选项排除追加(sys.argv[i+1])如果Opts.debug和Opts.exclude:打印(“--排除”,选项排除)打印(count_lines(sys.stdin))示例=“”diff—git a/cryptvfs.py b/cryptvs.py索引c68429cf6..ee90ecea8 100755---a/cryptvfs.py(密码)+++b/cryptvfs.py@@ -2,5 +2,17 @@从src.main导入proc_entry-如果__name__==“__main__”:-进程条目(_)+++Foo类:+“”“一些文档字符串+    """+#一些评论+通过++类栏:+“”“一些文档字符串+    """+#一些评论+定义方法():+第1+1行'''定义strio:导入io返回io.StringIO定义test_basic():断言count_lines(strio(示例))==10定义测试主(capsys):sys.argv=[]sys.stdin=strio(示例)主()cap=capsys.readuter()打印(大写)断言cap.out==“10\n”定义test_debug(capsys):sys.argv=[“--调试”]sys.stdin=strio(示例)主()cap=capsys.readuter()打印(大写)断言类型。DOCSTRING+cap.out中的“”“some DOCSTRING”定义test_exclude(capsys):sys.argv=[“--exclude”,“cryptvfs.py”]sys.stdin=strio(示例)主()cap=capsys.readuter()打印(大写)断言cap.out==“0\n”定义test_covrc(capsys):sys.argv=[“--covrc”]sys.stdin=strio(示例)主()cap=capsys.readuter()打印(大写)断言cap.out==“10\n”如果__name__==“__main__”:主()

那个密码可以进行简单的修改以生成文件名,而不是计数。

当然,它可能会错误地将部分文档字符串计算为“代码”(这不是为了覆盖率等)。

0

可能是这样的Bash脚本:

#!/垃圾桶/垃圾桶git diff—读取FPATH时仅显示名称“$@”|;LINES_COUNT=`git diff--textconv“$FPATH”“$@”|sed'/^[1-]\s\+[1-]\s\+.*/d'|wc-l`如果[$LINES_COUNT-gt 0];然后echo-e“$LINES_COUNT\t$FPATH”fi(菲涅耳)完成|排序-n
0

我使用梅尔德作为忽略注释的工具,通过设置其选项,然后将Meld用作“difftool”:

git difftool--工具=meld-y

你的答案

单击“发布您的答案”,表示您同意我们的服务条款并确认您已阅读我们的隐私政策.

不是你想要的答案吗?浏览标记的其他问题问你自己的问题.