按文件名过滤的git diff

32

我希望通过文件名过滤git diff的结果。

具体而言,我想获得所有名为“AssemblyInfo.cs”的文件的差异,但这些文件可以位于git存储库中的任何位置。

如果使用Cygwin上的git可能会有所不同。

6个回答

40

最简单的方法就是使用通配符:

git diff -- '*AssemblyInfo.cs'

至少在我的 Git v1.8.4、bash 3.2 和 zsh 5.7 上运行正常。


2
你不能这样限制路径。 - user1133275
2
它确实可以工作,但你需要使用 git diff -- '*AssemblyInfo.cs' 来避免 shell 尝试展开。 - chx
5
这应该被接受作为答案。那些使用“find”或“grep”的答案速度慢、笨重且容易在更复杂的用例中出错。 - ijoseph
1
如何在这种情况下添加多个过滤器,添加逗号分隔的字符串无效。我试图过滤以 .sql 和 .vw 结尾的文件,并忽略其余的文件。 - rainu
1
@rainu git diff -- '*.sql*' '*.ws' @rainu git diff -- '*.sql*' '*.ws' - Alexandre Castro
有没有简单的方法来获取反向?所有不匹配模式的文件? - trebor

19

git diff命令的文件参数需要用--分隔 - 请尝试以下操作:

find . -name <pattern> | xargs git diff --

xargs 确保正确处理空格、制表符、换行符等。

您可以使用--name-status参数来对git diff进行调试。您也可以尝试:

git diff --name-only | grep <pattern>

[编辑] 尝试:

git diff --name-status -- `find . -name '<pattern>'`
ebg@taiyo(98)$ git diff --name-status -- `find . -name '*.scm'`
M       scheme/base/boolean.scm
M       surf/compiler/common.scm
M       surf/compiler/compile.scm
M       surf/compiler/expand.scm

这似乎与git diff相同,但省略了最后一个文件。 - Zantier
也许最后一个文件没有改变。请使用我上面的建议进行调试。如果还不清楚,请在原问题中发布我的调试建议的输出。 - GoZoner
git diff --name-only | grep AssemblyInfo.cs 确实会给出正确的文件名,正如我所期望的那样,但我需要完整的差异输出。 find . -name AssemblyInfo.cs | xargs git diff --find . -name AssemblyInfo.cs | xargs git diff --name-status -- 都会给出一些不是“AssemblyInfo.cs”的文件(例如.sql 文件)。 - Zantier
我也遇到了编辑的同样问题。现在我已经解决了,还添加了我的答案。 - Zantier
2
正确的“StackOverflow”方法是说“谢谢Gozoner,基于你的答案我已经解决了问题”,然后用勾号奖励我。而不是发布自己的答案。 - GoZoner
2
抱歉,我太失礼了!感谢您的帮助。这是最终为我解决问题的解决方案:find . -name "AssemblyInfo.cs" -print0 | xargs -0 git diff -- - Zantier

6

可能最简单的选择是使用:

git diff "*/*AssemlyInfo.cs"

适用于git 2.20.1版本


5
应该使用 "**/*AssemblyInfo.cs" 来搜索整个代码库中的文件,而不仅是在一级嵌套目录下。一旦进行了这个更正,它就是最佳答案,并且应该被接受作为答案。 - papillon

0

你可以使用pipeline

find . -name AssemblyInfo.cs | git diff

使用find命令筛选所有名为"AssemblyInfo.cs"的文件,然后将输出作为参数传递给git diff命令。

1
这似乎没有过滤差异。我只是进行了行计数以进行检查:$ git diff | wc -l 1110 $ find . -name AssemblyInfo.cs | git diff | wc -l 1110 - Zantier
@Zantier,find . -name AssemblyInfo.cs 的输出是什么? - pktangyue
find . -name AssemblyInfo.cs 正常工作,可以给出所有 "AssemblyInfo.cs" 文件的路径。 - Zantier
@Zantier,我不知道你为什么要添加 wc -l 1110,以及 1110 是什么意思? - pktangyue
对不起,我是StackOverflow的新手,不知道我不能把它放在单独的一行上。这是命令的输出。两个命令都有1110行。 - Zantier

0
find . -iregex AssemblyInfo\.cs -exec git diff {} +

你可以用你的正则表达式替换 AssemblyInfo\.cs

0

虽然GoZoner提供的答案对于一些(几百个?)文件有效,但它会执行多次git diff(在xargs的情况下),或者失败(在git diff … -- `find …`的情况下),如果有大量文件需要进行差异比较,则可能会出现问题或不会出现问题,这取决于您的用例。

一个可能的解决方案是创建一个仅包含感兴趣的文件更改的提交,并对提交进行差异比较。基于关于取消暂存匹配某些模式的文件的答案,我想出了这个解决方案:

git co <new_branch> --detach
git reset --soft <old_branch>

现在,git status --porcelain | grep <pattern> 显示应该进行比较的所有文件。通过向 grep 传递 -v,即 git status --porcelain | grep -v <pattern>,可以列出所有其他文件。这些文件需要重置为 <old_branch> 的状态:
# Remove the destination of renamed and copied files not matching <pattern>
git status --porcelain | grep -v <pattern> | grep '^R \|^C ' | sed 's/.* -> //' | xargs git rm -f --
# Remove added files not matching <pattern>
git status --porcelain | grep -v <pattern> | grep '^A ' | cut -c 4- | xargs git rm -f --
# Restore deleted files not matching <pattern>
git status --porcelain | grep -v <pattern> | grep '^M \|^D ' | cut -c 4- | xargs git checkout HEAD --

(请注意,在这种情况下使用xargs不是问题,因为多次调用git rmgit checkout是可以的。)

现在索引(和工作副本)仅包含与<pattern>匹配的文件的更改。接下来要做的是提交这些更改:

git commit -m "Changes between <old_branch> and <new_branch> in files matching <pattern>"

就是这样!现在我们可以像往常一样使用 git diff

git diff HEAD^..HEAD

您可以使用任何您喜欢的选项或参数。

注意:此解决方案未经广泛测试,可能在具有特殊字符或其他特殊情况的文件上失败... 欢迎提出改进解决方案的建议;-)


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接