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

只要说我有一个文件:“HelloWorld.pm”在一个Git仓库中的多个子目录。

我想发出一个命令来查找匹配“HelloWorld.pm”的所有文件的完整path:

例如:

/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有效地find匹配给定文件名的所有完整path?

我意识到我可以用Linux / Unix的find命令做到这一点,但我希望避免扫描所有子目录寻找文件名的实例。

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

 git ls-files '*/HelloWorld.pm' 

如果你想find一组文件和grep通过它们的内容,你可以用git grep来做到这一点:

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

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

因为我找不到真正search整个提交历史logging的答案,所以我写了一个快速的蛮力脚本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 * 

也许有一个更优雅的方式。

请注意parameter passing给grep的简单方法,所以它会匹配部分文件名。 如果不需要,则锚定您的searchexpression式和/或添加合适的grep选项。

对于深层次的历史logging来说,输出可能太吵了,我想过一个脚本,它将修订列表转换成一个范围,就像git rev-list所能做的那样。 但到目前为止,这仍然是一个想法。

尝试:

 git ls-tree -r HEAD | grep HelloWorld.pm 
 git ls-files | grep -i HelloWorld.pm 

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

[我承认,这有点评论滥用,但我不能评论,并认为我会改善@ 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 

再次,@ @ uwe-geuder +1是一个很好的答案。

如果你对BASH本身感兴趣:

除非你保证for循环中的单词拆分(就像使用像这样的数组: for item in "${array[@]}" ),我强烈推荐使用while IFS= read var ; do ... ; done < <(command) while IFS= read var ; do ... ; done < <(command) 当你正在循环的命令输出被换行符隔开时(或者当输出被空string$'\0'分隔时read -d'' while IFS= read var ; do ... ; done < <(command) )。 虽然git rev-list --all保证使用40字节的hexstring(不含空格),但我从不喜欢冒险。 我现在可以轻松地将命令从git rev-list --all更改为任何生成行的命令

我还build议使用内置的BASH机制来注入input和filter输出,而不是临时文件。

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

速度更快,使用更less的存储:在输出上运行grep,然后存储它,如此要点所示