如何在Git和Mercurial仓库中搜索特定字符串的所有提交记录?

307

我有一个包含几个分支和悬空提交的Git存储库。我想在存储库中搜索所有这样的提交,查找特定字符串。

我知道如何获取所有历史提交记录的日志,但这些不包括分支或悬空的blob,只包括HEAD的历史记录。我想要获取它们全部,以找到一个被错放的特定提交。

我还想知道如何在Mercurial中执行此操作,因为我正在考虑切换。


11个回答

339

你可以使用 git log -g 命令查看悬挂提交。

-g, --walk-reflogs
 Instead of walking the commit ancestry chain, walk reflog entries from
 the most recent one to older ones. 

所以,您可以这样做来查找悬挂的提交消息中的特定字符串:

git log -g --grep=search_for_this

或者,如果您想要搜索特定字符串的更改,您可以使用拾取搜索选项"-S":

git log -g -Ssearch_for_this
# this also works but may be slower, it only shows text-added results
git grep search_for_this $(git log -g --pretty=format:%h)

Git 1.7.4将添加-G选项,允许您传递-G<regexp>以查找包含<regexp>的行何时移动,而-S无法实现。 -S仅在包含字符串的总行数改变时通知您(即添加/删除字符串)。

最后,您可以使用gitk可视化悬空提交:

gitk --all $(git log -g --pretty=format:%h)

然后使用其搜索功能查找丢失的文件。所有这些都是基于缺失的提交没有“过期”并且未被垃圾回收的情况下进行的,如果它悬挂了30天并且您到期了reflogs或运行了一个到期命令,则可能会发生这种情况。


4
也许可以使用所谓的“拨片”搜索,即在git日志中使用“-S”选项,而不是在(可能很多)提交上运行“git grep”,这将找到在项目中某处具有“search_for_this”的所有提交。拨片搜索可以找到引入或删除给定字符串的提交,或者更准确地说,找到给定字符串出现次数发生变化的提交。 - Jakub Narębski
5
你可以指定多个分支,或使用 '--all' 选项,例如 'git log --grep="提交信息中的字符串" --all'。 - Jakub Narębski
2
我遇到过一些情况,我的数据库中有提交记录,但是在我的reflog中没有。我不知道这有多常见。我正在尝试不同的hg/git桥接器。我认为这也可能与删除的存储库快照有关。无论如何,这个别名很好地解决了这些问题:!git fsck --unreachable | sed -ne 's/^unreachable commit //p' | xargs git log --no-walk - dubiousjim
要搜索特定作者在所有分支上的所有提交,您可以使用 git log -g --all --pretty=format:"%h - %an, %ar : %s" | grep -i <authorNameHere> - Adriano
1
“-g”选项真的必要吗?使用“git log --grep=search_for_this”不就足够了吗? - Evan Aad
显示剩余3条评论

57
在Mercurial中,您可以使用 hg log --keyword 在提交消息中搜索关键字,使用 hg log --user 来搜索特定用户。有关限制日志的其他方法,请参见 hg help log

37
Josip写道他正在考虑转换到Mercurial,并且他也想知道在那里如何操作。 - Martin Geisler
1
hg log -k 搜索提交用户名和更改集中的文件名(我在 commands.py:log 中看到了这一点),这是我在 hg 中不理解的少数几件事之一。应该有单独的选项来搜索提交消息和文件名。似乎 hg log --template '{desc}\n'|grep 是确定的方法。 - Geoffrey Zheng
@GeoffreyZheng:有方法可以做到这一点。参见“hg help revsets”,尤其是desc()、user()和file()函数。此外,hg log开关也支持大多数的行为。然而,在我的经验中,-k/keyword()通常是搜索内容最有帮助的方式。 - Kevin Horn
如何搜索实际提交的文件内容...差异?我知道这将是一个缓慢的搜索,但我想要深入搜索一个丢失的函数名称。 - Jonathan
1
哦,这里是:hg grep --all <term> - Jonathan

26
除了使用git log -g --grep=<regexp>git grep -e <regexp> $(git log -g --pretty=format:%h)richq答案之外,还可以查看Junio C Hamano撰写的以下博客文章,他是当前Git维护者之一:

总结

git grepgit log --grep都是行定位(line oriented)的,即它们查找与指定模式匹配的行。

您可以使用git log --grep=<foo> --grep=<bar>(或在内部转换为两个--grepgit log --author=<foo> --grep=<bar>)来查找与任一模式相匹配的提交(隐含OR语义)。

由于是面向行的,因此有用的AND语义是使用git log --all-match --grep=<foo> --grep=<bar>来查找具有两个匹配行的提交(commit)

使用 git grep 命令可以结合多个模式(所有模式都必须使用 -e <regexp> 格式)并用 --or(默认)、--and--not() 进行匹配。对于 grep,--all-match 表示文件必须具有与每个备选项匹配的行。


嘿Jakub,能否把那些博客文章的引用/摘要集成到这里?现在看起来像是一个老式的仅链接答案。 - Nathan Tuggy

11

在rq的回答基础上,我发现这一行代码可以满足我的需求:

git grep "search for something" $(git log -g --pretty=format:%h -S"search for something")

这将报告提交ID、文件名以及匹配行,就像这样:

91ba969:testFile:this is a test

有人认为这会是一个不错的选择,可以加入到标准的git grep命令中吗?


6

使用Mercurial时,您需要进行以下操作:

$ hg grep "search for this" [file...]

还有其他选项可以缩小搜索的修订范围。


1
我也喜欢标志 hg grep --all - Jonathan
1
这个操作现在被称为 hg histgrep,请参阅 hg help histgrep - jesusbriales

6
任何需要引用作为参数的命令都将接受git rev-list手册中记录的--all选项,如下所示:
   --all
       Pretend as if all the refs in $GIT_DIR/refs/ are listed on the
       command line as <commit>.

因此,例如 git log -Sstring --all 将显示所有提及 string 并且可以从分支或标记访问的提交(我假设您的悬挂提交至少使用标记命名)。

3
git grep命令中,似乎不需要使用--all参数,而是会将其翻译为/使用为--all-match。在Git 1.7.2.3中存在这个问题,我认为这是一个错误。使用$(git rev-list --all)可以解决这个问题。 - blueyed

2

不了解git,但在Mercurial中,我会将hg log的输出导入到一些sed/perl/whatever脚本中,以搜索您要查找的内容。如果您愿意,可以使用模板或样式自定义hg log的输出,以便更容易地进行搜索。

这将包括存储库中的所有命名分支。据我所知,Mercurial没有类似于悬空blob的东西。


1
我不明白这个答案与指定的问题有什么关系。 - jribeiro
4
这是对Mercurial的问题的回答,原始问题在最后一段询问有关它。 - Kurt Schelfthout

1

在git中有一个命令,我认为查找字符串更容易:

git log --pretty=oneline --grep "string to search"

在Git 2.0.4中有效


1

1
为了提供另一种尚未提及的解决方案,我不得不说,对于我来说使用gitg的图形搜索框是最简单的解决方案。它会选择第一个出现的内容,你可以使用Ctrl-G查找下一个。

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