如何在Git分支中搜索文件或目录?

434
在 Git 中,我如何通过路径在多个分支中搜索文件或目录?
我在一个分支中写了一些东西,但我不记得是哪一个分支。现在我需要找到它。
澄清:我正在寻找我在其中一个分支上创建的文件。我想通过路径找到它,而不是通过其内容,因为我不记得其内容是什么。

我不清楚这个问题。这个文件是在现在已经删除的分支中吗?这个文件被删除了吗? - Abizern
7个回答

589

git log + git branch可以帮你找到它:

% git log --all -- somefile

commit 55d2069a092e07c56a6b4d321509ba7620664c63
Author: Dustin Sallings <dustin@spy.net>
Date:   Tue Dec 16 14:16:22 2008 -0800

    added somefile


% git branch -a --contains 55d2069
  otherbranch

还支持通配符匹配:

% git log --all -- '**/my_file.png'

单引号是必要的(至少在使用Bash shell时),这样shell就会原封不动地将glob模式传递给git,而不是扩展它(就像Unix的find一样)。


4
如果你知道 somefile 的确切路径,那么这个方法就能起作用:如果你需要在路径/文件名中进行正则表达式搜索,那么你可以使用 ididak 的答案。 - ShreevatsaR
84
也支持通配符:git log --all -- **/my_file.png - webmat
5
我曾用这个命令解决了一个稍微不同的问题。我想找到我提交到特定分支的所有*.sql文件。因此,我使用了git log --grep='branch' --author='me' -- *.sql,效果非常好。git版本是1.7.11.1。 - PREEB
1
请注意,gitk也支持通配符。非常好的答案@webmat!如果您想查看文件的删除/创建等操作,可以使用git log --all --stat -- **/my_file.png命令,这样您就不必猜测是否从已删除该文件的提交中检出它。 - eacousineau
1
对于那些好奇的人(并且能够看到这条评论!):--all => "假装所有在refs/目录下的引用都被列在命令行中作为<commit>"。 - Snowcrash
显示剩余8条评论

80

可以使用git ls-tree命令来帮助查询。要在所有已有的分支中进行搜索:

for branch in `git for-each-ref --format="%(refname)" refs/heads`; do
  echo $branch :; git ls-tree -r --name-only $branch | grep '<foo>'
done

这样做的好处是您还可以使用正则表达式搜索文件名。


3
以下是一些希望有所帮助的评论: (a)您可能需要在“git ls-tree”命令中添加“-r”,这样即使文件在子目录中,该命令也能找到它。 (b)第一行的一个更简洁的替代方案可能是使用“git for-each-ref”命令,例如“for branch in git for-each-ref --format="%(refname)" refs/heads; do”。 (c)使用“git ls-tree --name-only”命令可以使输出更整洁。 (d)在回答中指出这种方法优于Dustin的解决方案的优点可能是值得的,即您不需要确切地知道文件名 - 您可以通过正则表达式匹配路径的任何部分进行搜索。 - Mark Longair
12
我已为此编写了一个脚本,因此您可以运行“gitfind.sh <regex>”进行搜索;代码摘要在https://gist.github.com/62d981890eccb48a99dc 里。 - Handyman5
6
请注意,这将仅搜索本地分支。要搜索远程跟踪分支,请使用refs/remotes而不是refs/heads。要搜索所有内容(本地分支、远程跟踪分支和标签),只需使用refs/即可。 - sleske

27

尽管ididak的回复非常酷,而且Handyman5提供了一个使用它的脚本,但我发现使用那种方法有点受限。

有时您需要搜索可能随时间出现/消失的内容,那么为什么不针对所有提交进行搜索呢?此外,有时您需要详细响应,而其他时候只需要匹配提交。以下是这些选项的两个版本。将这些脚本放在您的路径上:

git-find-file

for branch in $(git rev-list --all)
do
  if (git ls-tree -r --name-only $branch | grep --quiet "$1")
  then
     echo $branch
  fi
done
git-find-file-verbose
for branch in $(git rev-list --all)
do
  git ls-tree -r --name-only $branch | grep "$1" | sed 's/^/'$branch': /'
done

现在你可以做到

$ git find-file <regex>
sha1
sha2

$ git find-file-verbose <regex>
sha1: path/to/<regex>/searched
sha1: path/to/another/<regex>/in/same/sha
sha2: path/to/other/<regex>/in/other/sha

使用getopt命令,您可以修改该脚本以交替搜索所有提交,引用,refs/heads,详细信息等。

$ git find-file <regex>
$ git find-file --verbose <regex>
$ git find-file --verbose --decorated --color <regex>

可以查看https://github.com/albfan/git-find-file,了解一种可能的实现方式。


你的意思是“现在你可以使用git-find-file <regex>”吗?我已经把它搞定了,谢谢! - Elijah Lynn
2
我个人认为使用$(git branch | cut -c 3-)比$(git rev-list --all)更有用。我不关心找到一堆提交,我关心的是命名分支。 - Campadrenalin
看到所有这些烦恼,我认为值得为此创建一个仓库。https://github.com/albfan/git-find-file。我已经开了一些问题,请随意提出更多或发送PR。 - albfan
@ElijahLynn 如果你想使用 git find-file,你可以将它添加为 git 别名,只需运行 git config --global alias.find-file '!git-find-file' 即可。 - lumbric
1
@lumbric 在路径上安装脚本可以轻松完成,这是 Git 的一个特性。 - albfan
显示剩余4条评论

16

命令行

您可以使用 gitk --all 命令,并搜索"touching paths"和您感兴趣的路径名的提交记录。

用户界面

UI字段

(感谢:@MikeW的建议。)


3
如所述,请使用gitk --all命令,然后在视图|新视图中启用所有分支。然后设置您的搜索条件:文件名(带通配符)在倒数第二个字段中。最后:确定。 - MikeW

12

复制并粘贴此内容以使用 git find-file SEARCHPATTERN

打印所有搜索的分支:

git config --global alias.find-file '!for branch in `git for-each-ref --format="%(refname)" refs/heads`; do echo "${branch}:"; git ls-tree -r --name-only $branch | nl -bn -w3 | grep "$1"; done; :'

仅打印带有结果的分支:

git config --global alias.find-file '!for branch in $(git for-each-ref --format="%(refname)" refs/heads); do if git ls-tree -r --name-only $branch | grep "$1" > /dev/null; then  echo "${branch}:"; git ls-tree -r --name-only $branch | nl -bn -w3 | grep "$1"; fi; done; :'

这些命令将直接将一些最小化的shell脚本添加到您的~/.gitconfig中,作为全局的git别名。global git alias


它只在主分支中搜索。 - Nasif Imtiaz Ohi
它在所有本地分支中搜索。 - Leonardo Herrera
2
我该如何让它搜索所有本地和远程分支? - rgvcorley
“我该如何让它搜索所有本地和远程分支?”
首先使用以下命令拉取所有远程分支: git branch -r | grep -v '\->' | while read remote; do git branch --track "${remote#origin/}" "$remote"; done git fetch --all git pull --all
- Rob Tow

4
这个命令用于查找引入了指定路径的提交:
git log --source --all --diff-filter=A --name-only -- '**/my_file.png'

-3

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接