如何在任何分支中找到引入某个字符串的Git提交?

553

我希望能够查找在任何分支中的任何提交中引入的特定字符串,我该如何做?我找到了一些东西(我为Win32修改了它),但是git whatchanged似乎没有查看不同分支(忽略py3k块,它只是一个msys/win的换行符修复)。

git whatchanged -- <file> | \
grep "^commit " | \
python -c "exec(\"import sys,msvcrt,os\nmsvcrt.setmode(sys.stdout.fileno(), os.O_BINARY)\nfor l in sys.stdin: print(l.split()[1])\")" | \
xargs -i% git show origin % -- <file>

如果你的解决方案比较慢,其实并不重要。


7个回答

979

你可以这样做:

git log -S <search string> --source --all
为了找到所有添加或删除“固定字符串”search string的提交。参数--all意味着从每个分支开始,--source表示显示导致找到该提交的这些分支。通常有用的是添加-p以显示每个提交将引入的补丁。
自1.7.4版本以来的git还具有类似的-G选项,它接受正则表达式。这实际上具有不同(而更明显)的语义,Junio Hamano在这篇博客文章中解释了。 正如thameera在评论中指出的那样,如果搜索词包含空格或其他特殊字符,则需要在其周围加上引号,例如:
git log -S 'hello world' --source --all
git log -S "dude, where's my car?" --source --all

这里有一个使用-G查找function foo() {出现次数的示例:

git log -G "^(\s)*function foo[(][)](\s)*{$" --source --all

34
卓越表现加1分。指向-S是一回事,但更好的做法是解释清楚。另外,我喜欢使用--decorate来查看分支的来源。 - sehe
9
感谢您的好评。值得注意的是,“--decorate”只会在每个分支的末尾提交时添加分支名称。实际上,我并不经常使用“--source”或“--decorate”,而是使用“git branch -a --contains <commit-hash>”来查找包含我感兴趣的提交的分支。 - Mark Longair
8
加上“-p”选项可以查看行内差异,此外,FWIW。 - rogerdpack
1
@MarkLongair它没有显示合并中所做的更改。有什么建议可以展示这些更改吗? - Pahlevi Fikri Auliya
4
只有当我移除-S和搜索项之间的空格时,这对我才有效,例如:git log -S"dude, where's my car?" --source --all。@ribamar在下面的一个答案中也写到了这一点,但可能会被这篇排名靠前的回答所掩盖。 - bug313
显示剩余7条评论

115

--reverse 也很有帮助,因为你想要找到做出变更的第一个提交记录:

git log --all -p --reverse --source -S 'needle'

这样旧的提交记录将会先显示。


有没有办法在找到第一个匹配项后停止命令? - Cornelius Roemer
@CorneliusRoemer 或许是 git log -n1 - Ciro Santilli OurBigBook.com
@CiroSantilliOurBigBook.com 不行,似乎无法与 --reverse 一起使用。只显示最新的提交。 - undefined

31
胡闹着用相同的答案:
$ git config --global alias.find '!git log --color -p -S '
  • !是必需的,因为其他方式,git无法正确地将参数传递给-S。请参阅此回应
  • --color-p有助于准确显示“whatchanged”

现在你可以这样做

$ git find <whatever>

或者

$ git find <whatever> --all
$ git find <whatever> master develop

23

26
只是要澄清一下,如果你要查找的提交在HEAD中,那么方法是可行的,但这个问题特别要求在整个存储库中横跨所有分支进行查找。 - Mark Longair

9
git log -S"string_to_search" # options like --source --reverse --all etc

注意不要在S和"string_to_search"之间使用空格。在某些设置中(如git 1.7.1),你会收到类似的错误信息:
fatal: ambiguous argument 'string_to_search': unknown revision or path not in the working tree.
Use '--' to separate paths from revisions

6
不确定为什么接受的答案在我的环境中不起作用,最后我运行了下面的命令来得到我所需要的内容。
git log --pretty=format:"%h - %an, %ar : %s"|grep "STRING"

6
虽然这并没有直接回答你的问题,但我认为这可能是你未来的一个好解决方案。我看到了我的一部分代码,它很糟糕。不知道是谁写的或者什么时候写的。我可以从文件中看到所有的更改,但很明显这段代码已经从其他文件移到了这个文件中。我想找出是谁最初添加了它。
为此,我使用了Git bisect,它让我很快地找到了罪犯。
我运行了git bisect start,然后运行了git bisect bad,因为检出的修订版有问题。由于我不知道问题发生的时间,我将第一个提交作为“好”的目标,git bisect good <initial sha>
然后我只需在代码库中继续搜索坏代码。当我找到它时,我运行git bisect bad,如果它不在那里:git bisect good
在大约11步之后,我覆盖了大约1000个提交,并找到了引入问题的确切提交。非常棒。

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