如何从 git grep 搜索中排除某些目录/文件

在使用 git grep搜索 git 存储库时,是否有办法排除某些路径/目录/文件?类似于正常 grep命令中的 --exclude选项?

我需要使用 git grep,因为直接使用 grep在大型 git 存储库上运行得太慢了。

54061 次浏览

这是不可能的,但 最近已经讨论过了。建议的解决办法在链接:

您可以将 *.dll放到. gitignore 文件,然后放到 git grep --exclude-standard

编辑参见 只有无人回答,因为 git1.9.0是可能的。

更新: 对于 git > = 1.9,有对排除模式的本机支持,请参见 只有一个答案

这可能看起来是向后的,但是您可以像下面这样将不匹配排除模式的文件列表传递给 git grep:

git grep <pattern> -- `git ls-files | grep -v <exclude-pattern>`

返回与 <exclude-pattern>匹配的每个路径 没有。请注意,git ls-files也有一个 --exclude参数,但这只应用于 无法追踪的文件

以@kynan 为例,我创建了这个脚本,并将其放在路径(~/bin/)中作为 gg。它确实使用了 git grep,但是避免了一些指定的文件类型。

在我们的回购它的很多图像,所以我已经排除了图像文件,这需要搜索时间下降到1/3,如果我搜索整个回购。但是可以很容易地修改脚本以排除其他文件类型或 geleralpattern。

#!/bin/bash
#
# Wrapper of git-grep that excludes certain filetypes.
# NOTE: The filetypes to exclude is hardcoded for my specific needs.
#
# The basic setup of this script is from here:
#   https://stackoverflow.com/a/14226610/42580
# But there is issues with giving extra path information to the script
# therefor I crafted the while-thing that moves path-parts to the other side
# of the '--'.


# Declare the filetypes to ignore here
EXCLUDES="png xcf jpg jpeg pdf ps"


# Rebuild the list of fileendings to a good regexp
EXCLUDES=`echo $EXCLUDES | sed -e 's/ /\\\|/g' -e 's/.*/\\\.\\\(\0\\\)/'`


# Store the stuff that is moved from the arguments.
moved=


# If git-grep returns this "fatal..." then move the last element of the
# arg-list to the list of files to search.
err="fatal: bad flag '--' used after filename"
while [ "$err" = "fatal: bad flag '--' used after filename" ]; do
{
err=$(git grep "$@" -- `git ls-files $moved | grep -iv "$EXCLUDES"` \
2>&1 1>&3-)
} 3>&1


# The rest of the code in this loop is here to move the last argument in
# the arglist to a separate list $moved. I had issues with whitespace in
# the search-string, so this is loosely based on:
#   http://www.linuxjournal.com/content/bash-preserving-whitespace-using-set-and-eval
x=1
items=
for i in "$@"; do
if [ $x -lt $# ]; then
items="$items \"$i\""
else
moved="$i $moved"
fi
x=$(($x+1))
done
eval set -- $items
done
# Show the error if there was any
echo $err

注1

根据 这个,应该可以将事物命名为 git-gg,并且可以将它作为一个常规的 git 命令来调用,比如:

$ git gg searchstring

但我不能让这个工作。我在 ~/bin/中创建了脚本,并在 /usr/lib/git-core/中创建了 git-gg符号链接。

注2

这个命令不能被制作成一个常规的 sh git-alias,因为它将在 repo 的根目录中被调用。这不是我想要的!

在 git1.9.0中,“神奇的单词”exclude被添加到 pathspec中。因此,如果你想在每个文件中搜索 foobar,除了那些匹配 *.java的文件,你可以这样做:

git grep foobar -- ':(exclude)*.java'

或者使用 !“短格式”表示排除:

git grep foobar -- ':!*.java'

注意,在2.12以前的 git 版本中,使用排除 pathspec时,必须至少有一个“包含”pathspec。在上面的例子中,你需要在 --之后添加 ./*(递归地包含工作目录下的所有内容)。在 git v2.13中,取消了这个限制,git grep foobar -- ':!*.java'在没有 ./*的情况下工作。

Git-scm.com(或者仅仅是 git help glossary)的 pathspec中允许的所有“魔术词”都有一个很好的参考。

可以通过在存储库中创建一个属性文件来将文件或目录标记为二进制文件,例如。

$ cat .git/info/attributes
directory/to/ignore/*.* binary
directory/to/ignore/*/*.* binary
another_directory/to/also/ignore/*.* binary

列出的二进制文件中的匹配项没有包含行,例如。

$ git grep "bar"
Binary file directory/to/ignore/filename matches
other_directory/other_filename:      foo << bar - bazz[:whatnot]