我可以使用Git在存储库中搜索匹配的文件名吗?

时间:2008-11-10 10:31:13

标签: git

说我在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命令执行此操作,但我希望避免扫描所有子目录以查找文件名实例。

6 个答案:

答案 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

所示