如何在Git存储库中使用'grep'命令搜索文件?

35
我喜欢使用git grep在存储库中搜索所有已检入的文件。它非常好用。但是有没有可能使用它(或其他Git命令)仅用于查找文件(与内容无关)?
目前我是这样做的:
find . | grep middleware

这个方法可以工作,但它并没有使用Git索引,这意味着它会遍历每个找到的文件,并报告与.gitignore匹配的文件。

有没有一些巧妙的技巧?

6个回答

47
也许您想要使用git ls-files命令,该命令会列出索引中的文件?(并自动调整为您当前在git工作目录中的目录)

这是正确的答案。我会使用 git ls-files | grep '你要查找的名称' 来在 git ls-files 返回的大文件列表上进行过滤。(我还将 ls-files 别名为 ls,因为我经常使用它) - I82Much
3
我们可以使用命令“git ls-files“加上“*.sh”或者“git ls-files | grep .sh”来完成。 - Chu-Siang Lai
我一直有一个别名:find = ! git ls-files | grep,但有时我真的想将搜索限制在特定路径中,例如 git find foo bar/baz。你有什么实现方法吗? - JFlo
1
为了回答我自己的问题,这是我想出来的代码:find = ! sh -c 'git ls-files $2 | grep $1' - - JFlo
@JFlo,我在git find中实现了你的要求,请查看此提交,希望能够帮助到你! - mirabilos
显示剩余2条评论

27

我认为git ls-files可以帮你解决问题。

因此:

 git ls-files "*middleware*"

+1。我总是使用“git ls-tree -r HEAD | grep“toSearchFor””。 - Stefan Näwe
这也非常酷,但是使用 git ls-files | grep ... 我可以轻松获得 grep 的强大功能,而且由于默认启用了 grep 的颜色高亮显示,因此显示效果更好。 - Peter Bengtsson
@PeterBengtsson 我写的git find,有人今天不知道什么原因将其投票否决。实际上,它基本上是git ls-files | grep,但使用类似于find的语法(而且它甚至可以委托给find,仍然避免了非git文件)。 - mirabilos

6
你可以考虑在这种情况下使用非git解决方案。 find本身具有比将其结果导入grep更高效的功能,可以满足你的需求。
find . -name 'middleware*'

你需要引用模式,这样 shell 在将其传递给 find 之前不会扩展 *
有一个称为 ack 的强大程序,它比 grep 更好,而我最喜欢使用 ack 的方法之一正是你提到的——在树中查找与模式匹配的文件。但是,ack 使用的是 perl 正则表达式,而不是 shell 文件通配符。
ack -g middleware

如果你想在这些文件中进行搜索,ack 比编写一个 shell 循环来在每个文件中使用 grep 更容易。比较这两种方法,看看哪种更适合你:
for f in $(find . -name 'middleware*')
do
    grep 'pattern in file' $f
done

对抗

ack -G 'middleware' 'pattern in file'

我强烈推荐将ack加入您的工具箱。

太好了!感谢你向我介绍ack!只想指出一下:“-G”选项已被删除。在命令行上使用两个正则表达式被认为过于混乱;为了模拟“-G”的功能,您可以使用新的“-x”选项将文件名从一个ack调用传递到另一个ack调用中。详情请见ack(1)。如果我找到解决方法,我会编辑这个答案。 - askewchan

2

纯git解决方案

git grep内置支持将grep限制为一组文件。 其他答案都使用外部工具来执行实际的grep操作,这是无意义的。

示例来自git grep 手册页面

git grep 'time_t' -- '*.[ch]'

在工作目录及其子目录中查找所有已追踪的 .c 和 .h 文件中的 time_t。从选项描述中可以知道,-- 表示选项结束,其后的参数为限制器;... 表示如果给出,则将搜索限制为与至少一个模式匹配的路径。支持前导路径匹配和 glob(7) 模式。因此,要翻译您的示例(该示例没有包含任何限制搜索的内容,所以我在这里添加了它)。
$ find . -name '*.txt' | grep middleware

你会做:

你会做:

$ git grep middleware -- '*.txt'

1
这并没有回答问题。OP询问的是find命令的git限定版本,就像git grepgrep的git限定版本一样。也就是说,OP想要按名称搜索git跟踪的文件,而不是按内容搜索。 - Woodrow Barlow
'*.[ch]' 是文件名的类似于“查找”的过滤器。请参考“man gitglossary”并搜索pathspec。它可能不等同于find命令,但在这种情况下,一个没有限制的人可以手动输入“find”。 - artless noise

1

现在Git拥有成熟的搜索功能(正如之前的帖子所提到的)。您可以搜索文件名、扩展名、编程语言等。您可以在文件内容中进行搜索......等等。

当您登录GitHub时,可以在屏幕左上方的搜索字段中进行搜索。

有关详细信息,请参见: https://help.github.com/en/articles/searching-code


0

我经常遇到同样的问题,我刚刚去黑客git find - 如果您不使用Debian包,则可以将git-find脚本复制到/usr/lib/git-core/(或类似位置)并享受它。

它可以用于多种模式,其中最简单的是:

git find \*middleware\*        # or
git find '*middleware*'        # which is short for
git find -name '*middleware*'

合并也是可能的(几乎和常规的find一样灵活,只需明确写出-a):

git find \( -name \*.java -o -name \*.js \) -a ! -ipath \*/test/\*

它还有几个选项,其中大部分处理过滤名称或完整(部分,即在当前工作目录下)路径,其中一些不区分大小写(-iname和朋友们),以及两个全局选项,一个用于在 POSIX 基本(默认)和 POSIX 扩展之间切换正则表达式,另一个切换符号链接(默认打开);这样设计是为了仅查找文件(和符号链接),而不是目录或子模块(“gitlinks”)。

如果文件列表不太长(必须通过命令行传递),它还可以将文件列表传递给常规的find(1),从而允许进行诸如…的操作。

git find -- -mtime -100

…以轻微的文件系统成本(find会访问文件系统),但另一方面,几乎所有(不是特定于搜索深度的东西)的find都可以工作,并且您只能在“索引”中操作文件,即已知于git(存在于HEAD提交或git added中)。

但它对未解决的冲突有点挑剔。如果您注意到任何问题,请给我留言(在此处或通过IRC)。

PS:随意游说官方git人员将git-find存储库合并到子树中,我很乐意将其集成到git中(许可证甚至更自由,您只需要一个相当新的(50应该足够)版本的mksh shell,但它是目前最广泛使用的Unix shell,所以没问题)。


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