有没有办法在使用搜索 git 存储库时排除某些路径/目录/文件git grep
?类似于--exclude
普通grep
命令中的选项?
我需要使用git grep
,因为grep
直接使用在大型 git 存储库上运行速度太慢。
在 git 1.9.0 中,“魔法词”exclude
被添加到pathspec
s. foobar
因此,如果您想在除匹配文件之外的每个文件中进行搜索,*.java
您可以执行以下操作:
git grep foobar -- ':(exclude)*.java'
或使用!
“简短形式”排除:
git grep foobar -- ':!*.java'
请注意,在 v2.12 之前的 git 版本中,使用 exclude 时pathspec
,您必须至少有一个 "inclusive" pathspec
。在上面的示例中,您还希望在./*
之后的某个位置添加(递归地包括当前目录下的所有内容)--
。在 git v2.13 中,这个限制被解除并且git grep foobar -- ':!*.java'
没有./*
.
pathspec
在git-scm.com(或只是git help glossary
)中允许的所有“魔术词”都有很好的参考。
更新:对于 git >= 1.9 有对排除模式的原生支持,请参见onlyone's answer。
这可能看起来倒退,但您可以传递与排除模式不匹配的文件列表,git grep
如下所示:
git grep <pattern> -- `git ls-files | grep -v <exclude-pattern>`
grep -v
返回每个不匹配的路径<exclude-pattern>
。请注意,git ls-files
它还带有一个--exclude
参数,但仅适用于未跟踪的文件。
这是不可能的,但最近已经讨论过了。链接中建议的解决方法:
然后您可以放入
*.dll
.gitignore 文件git grep --exclude-standard
。
编辑看到onlynone 的答案,因为 git 1.9.0 是可能的。
您可以通过在存储库中创建属性文件来将文件或目录标记为二进制文件,例如
$ 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]
以@kynan 的示例为基础,我制作了这个脚本并将其放在我的路径(~/bin/
)中 gg
。它确实使用git grep
但避免了一些指定的文件类型。
在我们的 repo 中有很多图像,所以我排除了图像文件,如果我搜索整个 repo,这会将 serchtime 降低到 1/3。但是可以轻松修改脚本以排除其他文件类型或geleralpatterns。
#!/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
但我无法让这个工作。我在 my 中创建了脚本~/bin/
并git-gg
在/usr/lib/git-core/
.
笔记2
该命令不能成为常规的sh
git-alias,因为它将在 repo 的根目录中调用。这不是我想要的!