2008-11-10 95 views
51

只是说我有一个文件:“HelloWorld.pm”在多个子目录一个Git仓库内。我可以使用Git在存储库中搜索匹配的文件名吗?

我想发出一个命令来查找所有的文件匹配“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命令这样做,但我希望能避免扫描寻找文件名的情况下,所有子目录。

回答

19

尝试:

git ls-tree -r HEAD | grep HelloWorld.pm 
+1

或Windows:`git的LS-树-r HEAD | findstr HelloWorld.pm` – 2014-08-13 10:10:06

79

git ls-files会给你在库中的所有文件的列表。您可以传入一个模式来获取匹配该模式的文件。

git ls-files '*/HelloWorld.pm' 

如果你想通过自己的内容,找到一组文件和grep的,你可以做到这一点与git grep

git grep some-string -- '*/HelloWorld.pm' 
+0

ls文件也可以采用一种模式。 – 2011-04-15 20:20:26

+0

@jleedev啊,对。更新了我的答案,以简化它并修复`git grep`中的模式问题。 – 2011-04-15 20:25:42

+0

(烦人,它被称为[pathspec](http://www.kernel.org/pub/software/scm/git/docs/gitglossary.html#def_pathspec)在gitglossary(7),但该术语并不一致地使用) – 2011-04-15 20:34:05

38

嗯,原来的问题是关于资源库。一个存储库包含多个提交(至少在一般情况下),但只有通过一次提交才能搜索到的答案。

因为我无法找到一个答案,真正搜索整个提交历史我写了一个快速蛮力脚本的git-发现按名称需要(几乎)所有提交考虑。

#! /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可以做的事情相反。但到目前为止,这仍然是一个想法。

3

[这是一个有点评论滥用,我承认,但我还不能发表评论,我想我会提高@乌韦 - 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 @乌韦 - geuder为了一个很好的答案。

如果你有兴趣在BASH本身:

除非你在一个(使用一个这样的数组时,如:for item in "${array[@]}")保证字拆分的for循环,我强烈建议使用while IFS= read var ; do ... ; done < <(command)时你遍历命令输出被换行分隔(或read -d''当输出由空字符串$'\0'分隔)。虽然git rev-list --all是保证使用40字节十六进制字符串(无空格),我从来不喜欢冒险。我现在可以轻松地将命令从git rev-list --all更改为任何生成行的命令

我还推荐使用内置的BASH机制来注入输入和过滤器输出而不是临时文件。

7
git ls-files | grep -i HelloWorld.pm 

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

0

Uwe Geuder(@ uwe-geuder)的脚本很棒,但实际上并不需要将每个ls-tree输出转储到它自己的目录中,而不需要过滤。

更快速,使用更少的存储:运行在输出上的grep,然后储存,如本gist

相关问题