说我在Git存储库中的多个子目录中有一个文件:“HelloWorld.pm”。
我想发出一个命令来查找匹配“HelloWorld.pm”的所有文件的完整路径:
例如:
/path/to/repository/HelloWorld.pm
/path/to/repository/but/much/deeper/down/HelloWorld.pm
/path/to/repository/please/dont/make/me/search/through/the/lot/HelloWorld.pm
如何使用Git高效查找与给定文件名匹配的所有完整路径?
我意识到我可以使用Linux / Unix find命令执行此操作,但我希望避免扫描所有子目录以查找文件名实例。
答案 0 :(得分:98)
git ls-files
将为您提供存储库中所有文件的列表。您可以传递模式以获取与该模式匹配的文件。
git ls-files '*/HelloWorld.pm'
如果您想查找一组文件并浏览其内容,可以使用git grep
执行此操作:
git grep some-string -- '*/HelloWorld.pm'
答案 1 :(得分:43)
嗯,最初的问题是关于存储库的。存储库包含多于1个提交(至少在一般情况下),但在仅通过一次提交搜索之前给出的答案。
因为我找不到真正搜索整个提交历史的答案,所以我写了一个快速的强制脚本git-find-by-name,它将(几乎)所有提交都考虑在内。
#! /bin/sh
tmpdir=$(mktemp -td git-find.XXXX)
trap "rm -r $tmpdir" EXIT INT TERM
allrevs=$(git rev-list --all)
# well, nearly all revs, we could still check the log if we have
# dangling commits and we could include the index to be perfect...
for rev in $allrevs
do
git ls-tree --full-tree -r $rev >$tmpdir/$rev
done
cd $tmpdir
grep $1 *
也许有一种更优雅的方式。
请注意参数传递给grep的简单方法,因此它将匹配部分文件名。如果不希望锚定搜索表达式和/或添加合适的grep选项。
对于深度历史记录,输出可能太嘈杂,我想到了一个转换的脚本 一个范围内的修订列表,就像git rev-list可以做的那样。但到目前为止,它仍然是一个想法。
答案 2 :(得分:21)
尝试:
git ls-tree -r HEAD | grep HelloWorld.pm
答案 3 :(得分:7)
git ls-files | grep -i HelloWorld.pm
grep -i使grep不区分大小写。
答案 4 :(得分:3)
[这是一个滥用评论,我承认,但我还不能评论,并认为我会改善@ uwe-geuder的回答。]
#!/bin/bash
#
#
# I'm using a fixed string here, not a regular expression, but you can easily
# use a regular expression by altering the call to grep below.
name="$1"
# Verify usage.
if [[ -z "$name" ]]
then
echo "Usage: $(basename "$0") <file name>" 1>&2
exit 100
fi
# Search all revisions; get unique results.
while IFS= read rev
do
# Find $name in $rev's tree and only use its path.
grep -F -- "$name" \
<(git ls-tree --full-tree -r "$rev" | awk '{ print $4 }')
done < \
<(git rev-list --all) \
| sort -u
再一次,+1给@ uwe-geuder一个很好的答案。
如果您对BASH本身感兴趣:
除非你保证for循环中的分词(就像使用像这样的数组:for item in "${array[@]}"
),我强烈建议在命令输出循环时使用while IFS= read var ; do ... ; done < <(command)
over由换行符分隔(或read -d''
当输出由空字符串$'\0'
分隔时)。虽然git rev-list --all
保证使用40字节的十六进制字符串(没有空格),但我从不喜欢冒险。我现在可以轻松地将命令从git rev-list --all
更改为任何生成行的命令
我还建议使用内置的BASH机制来注入输入和过滤输出而不是临时文件。
答案 5 :(得分:1)
Uwe Geuder(@ uwe-geuder)编写的脚本很棒,但实际上没有必要将每个ls-tree输出转储到它自己的目录中,未经过滤。
更快,使用更少的存储:在输出上运行grep然后存储它,如gist
所示