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


323

在Git中,如何通过多个分支中的路径搜索文件或目录?

我已经在分支中写了一些东西,但我不记得是哪个。现在我需要找到它。

澄清:我正在寻找我在其中一个分支上创建的文件。我想通过路径而不是内容来查找它,因为我不记得内容是什么。


我不清楚这个问题。该文件是否在现在已删除的分支中?文件被删除了吗?
阿比森

Answers:


444

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而不更改git,而不是扩展它(就像Unix一样find)。


2
如果您知道确切的路径,somefile则此方法有效:例如,如果您需要在路径/文件名上进行正则表达式搜索,则可以使用ididak的答案。
ShreevatsaR 2012年

70
也支持git log --all -- **/my_file.png
浮动

3
我用这个来解决一个稍微不同的问题。我试图找到我提交给特定分支的所有* .sql文件。所以我习惯了git log --grep='branch' --author='me' -- *.sql。像魅力一样工作。git版本1.7.11.1
thepriebe 2012年

1
请注意,它也gitk支持通配符。@webmat是一个很好的答案!如果要查看在哪里删除/创建了/ etc,可以使用git log --all --stat -- **/my_file.png,这样就不必猜测是否要从删除了它的提交中检出它。
eacousineau

1
@webmat:我很乐意将有关globing的信息添加到答案中。感谢您提及!
sleske 2014年

65

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)它可能是值得在你的答案指出,有这样的一个优势达斯汀的解决方案,即你不需要确切地知道文件名-您可以通过正则表达式匹配的路径的任何部分搜索
马克Longair

9
我将其包装在脚本中,以便您可以运行“ gitfind.sh <regex>”;要点是gist.github.com/62d981890eccb48a99dc
Handyman5

3
请注意,这只会搜索本地分支机构。要搜索远程跟踪分支,请使用refs/remotes代替refs/heads。要搜索所有内容(本地分支,远程跟踪分支和标签),只需使用refs/
sleske

19

尽管ididak的响应非常酷,并且Handyman5提供了一个脚本来使用它,但我发现使用该方法有些局限。

有时您需要搜索随时间推移可能出现/消失的内容,那么为什么不搜索所有提交呢?除此之外,有时您需要冗长的答复,而其他时候仅提交匹配项。这是这些选项的两个版本。将这些脚本放在您的路径上:

git查找文件

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可以修改该脚本以交替搜索所有提交,引用,引用/标题,冗长等。

$ 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>”了吗?我知道了,谢谢!
伊利亚·林恩2014年

1
我个人发现使用$(git branch | cut -c 3-)代替$(git rev-list --all)更为有用。我不在乎查找一堆提交,我在乎命名分支。
Campadrenalin

我还更改了脚本以使用$(git branch | cut -c 3-),因为所有提交的循环都太慢了。
i4h 2015年

看到所有的大惊小怪,我值得为此创建一个仓库。github.com/albfan/git-find-file。我有一些问题,可以随时提出更多建议或发送公关。
albfan 2015年

1
@lumbric在路径上的安装脚本可以直接使用,它具有git功能
albfan

10

您可以使用gitk --all并搜索“触摸路径”提交和您感兴趣的路径名。


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

8

复制并粘贴以使用 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别名


它仅在主分支中搜索
Nasif Imtiaz Ohi,

它搜索所有本地分支机构
Leonardo Herrera

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.