如何从 git grep 搜索中排除某些目录/文件
Posted
技术标签:
【中文标题】如何从 git grep 搜索中排除某些目录/文件【英文标题】:How to exclude certain directories/files from git grep search 【发布时间】:2012-05-12 11:33:57 【问题描述】:在使用git grep
搜索 git 存储库时,有没有办法排除某些路径/目录/文件?类似于普通grep
命令中的--exclude
选项?
我需要使用git grep
,因为直接使用grep
在大型git 存储库上运行速度太慢。
【问题讨论】:
在 bash 上执行此操作可能是一种解决方法:***.com/questions/216995/… 此功能是在 1.9.0 中添加的 see my answer below 【参考方案1】:在 git 1.9.0 中,“魔法词”exclude
被添加到 pathspec
s。所以如果你想在每个文件中搜索foobar
,除了那些匹配*.java
的文件,你可以这样做:
git grep foobar -- ':(exclude)*.java'
或者使用!
“短格式”排除:
git grep foobar -- ':!*.java'
请注意,在 v2.12 之前的 git 版本中,当使用排除 pathspec
时,您必须至少有一个“包含”pathspec
。在上面的示例中,您还想在--
之后的某个位置添加./*
(递归地包括当前目录下的所有内容)。在 git v2.13 中,这个限制被解除,git grep foobar -- ':!*.java'
在没有 ./*
的情况下也可以工作。
在git-scm.com(或只是git help glossary
)pathspec
中允许的所有“魔法词”都有一个很好的参考。
【讨论】:
git grep clock.gettime -- './*' ':!arch/**' ':!drivers/**'
排除多个完整目录。我不认为它会阻止递归。
为了经常使用,您可以使用排除项创建一个 git 别名:git config alias.mygrep '!git grep "$@" -- "$GIT_PREFIX/*" ":!*.java*" #'
。然后只需git mygrep foobar
。 (使用别名shell # trick 和current dir。)
@elonderin 此解决方案与匹配文件的报告方式无关。但我只是从子目录中尝试了git grep
和git ls-files
,并且都报告了相对于当前目录的文件名(即使您使用':(top)'
包含路径规范)。这两个命令都有 --full-name
选项来报告相对于根的名称,但默认情况下是关闭的。
我不使用 git 别名,所以我做了一个 bash 函数,但可能 git 别名更好gist.github.com/cmdcolin/04e2378b60f4457a41904c659368066f
我使用的是 git 2.19,比上面发布的更简单的语法就是:git grep foobar ':!*.java'【参考方案2】:
更新:对于 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
参数,但这仅适用于未跟踪的文件。
【讨论】:
谢谢! Git grep 比 ack & co 快得多,但不能排除任意路径有点太不方便了 :) 不幸的是我的仓库有很多文件。当我尝试@kynan 的方法时,我得到:“-bash: /usr/bin/git: Argument list too long” 这应该解决 Benissimo 的“参数列表太长”问题和我的 bash 解释的文件名字符(如 [])或存储库中包含空格的文件名的问题:git ls-files | grep -v | xargs -d '\n' git grep -- Check onlynone 的答案,现在可能完全在(现代版本的)git 中做到这一点。 为什么投反对票?这个答案仍然适用于 1.9 之前的 git 版本。我添加了一个关于 onlyone 答案的注释。【参考方案3】:这是不可能的,但has been discussed recently。链接中建议的解决方法:
你可以把
*.dll
放到.gitignore 文件然后git grep --exclude-standard
。
编辑见onlynone's answer,因为 git 1.9.0 是可能的。
【讨论】:
这曾经是真的,但现在不再是这样了,现在在 git 中是可能的。看看下面的真正答案应该是什么:***.com/a/30084612/1391445【参考方案4】:您可以通过在存储库中创建属性文件来将文件或目录标记为二进制文件,例如
$ 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]
【讨论】:
这实际上是一个很好的答案。 我发现dir-i-wanted-to-ignore/**/* binary
成功了。
最佳答案。也可以通过使用.gitattributes
而不是本地.git/info/attributes
来提交到repo。【参考方案5】:
以@kynan 的示例为基础,我制作了这个脚本并将其作为gg
放在我的路径(~/bin/
)中。它确实使用了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://***.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
根据this 应该可以将事物命名为git-gg
并能够将其作为常规git 命令调用,例如:
$ git gg searchstring
但我无法让它工作。我在~/bin/
中创建了脚本,并在/usr/lib/git-core/
中创建了git-gg
符号链接。
注2
该命令不能成为常规的sh
git-alias,因为它将在 repo 的根目录中调用。这不是我想要的!
【讨论】:
以上是关于如何从 git grep 搜索中排除某些目录/文件的主要内容,如果未能解决你的问题,请参考以下文章