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

gdrx4gfi  于 2023-06-20  发布在  Git
关注(0)|答案(7)|浏览(125)

就说我有个文件“HelloWorld.pm“在Git仓库的多个子目录中。
我想发出一个命令来查找所有匹配“www.example.com”的文件的完整路径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命令来做这件事,但我希望避免扫描所有的子目录来寻找文件名的示例。

xytpbqjk

xytpbqjk1#

git ls-files会给予你一个仓库(该高速缓存或索引)当前状态下所有文件的列表。您可以传入一个模式以获取与该模式匹配的文件。

git ls-files HelloWorld.pm '**/HelloWorld.pm'

如果你想找到一组文件并通过grep浏览它们的内容,你可以使用git grep

git grep some-string -- HelloWorld.pm '**/HelloWorld.pm'
ep6jt1vc

ep6jt1vc2#

嗯,最初的问题是关于仓库的。一个仓库包含多于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的方式很简单,因此它将匹配filename的部分内容。如果不希望这样,则锚定搜索表达式和/或添加合适的grep选项。
对于深度历史,输出可能太嘈杂,我想到了一个脚本,它将修订列表转换为范围,就像git rev-list可以做的相反。但到目前为止,它仍然是一个想法。

ws51t4hk

ws51t4hk3#

尝试:

git ls-tree -r HEAD | grep HelloWorld.pm
lo8azlld

lo8azlld4#

git ls-files | grep -i HelloWorld.pm

grep -i使grep不区分大小写。

cu6pst1q

cu6pst1q5#

[It我承认,这有点滥用评论,但我还不能发表评论,我想我会改进@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)(或在输出由空字符串$'\0'分隔时使用read -d'')。虽然git rev-list --all保证使用40字节的十六进制字符串(没有空格),但我从不喜欢冒险。现在,我可以轻松地将命令从git rev-list --all更改为生成行的任何命令
我还建议使用内置的BASH机制来注入输入和过滤输出,而不是临时文件。

ulmd4ohb

ulmd4ohb6#

Uwe Geuder(@uwe-geuder)编写的脚本很棒,但真的没有必要将每个ls-tree输出转储到自己的目录中,不进行过滤。
速度更快,使用更少的存储空间:对输出运行grep,然后存储它,如下面的gist所示:

vwhgwdsa

vwhgwdsa7#

@Uwe-Geuder的代码可以做成一行程序

git rev-list --all | xargs -I '{}' git ls-tree --full-tree -r '{}' | grep '.*HelloWorld\.pm$'.

这也解决了硬盘泛洪问题。

相关问题