我可以使用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,然后存储它,如此要点所示