如何“责怪”已删除的行?


506

git blame非常适合于修改和添加的行,但是如何找到特定的先前提交中存在的行最终被删除的时间。我在想bisect,但我希望有一些方便的东西。

(在您问:在这种情况下,我只是做了一个,git log -p然后搜索了代码行,(a)一些白痴刚刚删除了上一次提交中的关键行,(b)我就是那个白痴。)


4
有一个后续的答案,澄清了一个问题,即git log -S<string> /path/to/file希望在合并(冲突)期间也要显示-c-cc同时显示删除内容
cfi

3
应该是-c--cc。@Steen:正确,谢谢指出!愚蠢的监督。希望我可以编辑评论。添加一个新的,然后删除我的,然后删除您的我太麻烦了:)
cfi

4
我希望git blame可以选择显示删除的行(可能带有删除线或红色文本)以及删除它们的修订版本。
Craig McQueen

那很难写吗?我对Git的内部知识了解不多。
马尔沃里奥

Answers:


635

如果您知道该行的内容,则这是以下情况的理想用例:

git log -S <string> path/to/file

它显示了您引入或删除该字符串实例的提交。还有-G<regex>使用正则表达式执行相同操作的!请查看man git-log并搜索-G-S选项,或镐(这些功能的友好名称)以获取更多信息。

-S实际上,该选项还在手册git-blame页的标题中的“描述”部分中进行了提及,在此提供了使用的示例git log -S...


辉煌...正是我在+1这项移植工作中需要的东西
jkp 2011年

37
在使用Git一年以上之后,仍然让我感到惊讶的是,Git 总是在某处有一个命令/选项来解决我的几乎所有使用情况。感谢您分享此内容,这正是我现在需要的!
Pascal Bourque

22
此方法以前对我有用,但现在我看到了一种情况,即找不到删除行的提交。原来有问题的行在合并提交中被删除了-这可以解释失败吗?(git blame --reverse方法虽然找到了。)
antinome 2013年

9
@antinome要显示来自合并的提交,请-c另外使用该选项。
yunzen 2014年

2
我在联机帮助页上的“ -s”上执行了ctrl + f,却一无所获。您在页面的哪个位置看到了它?我正在使用git 1.8.5.2
临时用户名,

134

我想你真正想要的是

git blame --reverse START..END filename

联机帮助页

向前走历史,而不向后走历史。与其显示行所在的修订,不显示行所在的最后一个修订。这需要进行一系列修订,例如START..END,其中的归咎路径存在于START中。

使用git blame reverse,您可以找到该行出现的最后一个提交。您仍然需要获取后面的提交。

您可以使用以下命令显示反转的git日志。显示的第一个提交将是该行的最后一次显示,而下一次提交将是更改或删除该行的时间。

git log --reverse --ancestry-path COMMIT^..master

14
如果从添加行的分支到缺少行的分支有多个合并(或者在其他任何情况下,从START到END的世系中有多个路径),git blame --reverse则将按时间顺序显示合并之前的修订最后,而不是初始合并之前的修订版本,在该版本中,决定不采用该行。有什么方法可以找到该行停止存在的最早修订版本,而不是最新版本?
rakslice

2
@rakslice,因为您可以使用blame --reverse --first-parent,这要好一些。
max630 '17

17

只是为了完成Cascabel的答案

git log --full-history -S <string> path/to/file

我遇到了与此处提到的问题相同的问题,事实证明该行丢失了,因为分支的合并提交已还原,然后又合并回了其中,从而有效地删除了该行。该--full-history标志可防止跳过那些提交。


9

git blame --reverse可以使您接近删除行的位置。但是它实际上并不指向删除行的修订版本。它指向的最后一个修订版本,其中线是目前。然后,如果以下修订是普通提交,那么您很幸运,并且已删除了修订。OTOH,如果以下修订版是merge commit,那么事情可能会变得有些疯狂。

作为创建difflame的一部分,我解决了这个问题,因此,如果您已经在包装盒中安装了Python,并且愿意尝试一下,那就不要再等待了,让我知道它的运行方式。

https://github.com/eantoranz/difflame


0

对于隐藏在合并提交中的更改

合并提交会自动从Git日志输出中隐藏其更改。无论镐头反指责没有发现变化。因此,我想要的行已添加,后来又删除了,我想找到将其删除的合并。文件git log -p -- path/file历史记录仅显示已添加。这是我找到它的最佳方法:

git log -p -U9999 -- path/file

搜索更改,然后向后搜索“ ^ commit”-第一个“ ^ commit”是文件最后一行所在的提交。第二个“ ^ commit”消失之后。第二个提交可能是删除它的那个。本-U9999是为了显示整个文件内容(每个文件被更改时间后),假设你的文件都是最高9999线。

通过蛮力查找任何相关的合并(将每个可能的合并提交与第一个父合并进行比较,以大量提交为准)

git log --merges --pretty=format:"git diff %h^...%h | grep target_text" HEAD ^$(git merge-base A B) | sh -v 2>&1 | less

(我尝试过更多地限制修订过滤器,但是我遇到了问题,不建议这样做。我要查找的添加/删除更改是在不同的分支上进行的,这些分支在不同的时间被合并,并且A ... B不包括当更改实际上合并到主线中时。)

显示具有这两个提交的Git树(并删除了许多复杂的Git历史记录):

git log --graph --oneline A B ^$(git merge-base A B) (A是上面的第一个提交,B是上面的第二个提交)

显示A历史和B历史减去A和B历史。

备用版本(似乎比常规的Git历史树更线性地显示路径-但是我更喜欢常规的git历史树):

git log --graph --oneline A...B

三个而不是两个点-三个点表示“ r1 r2-不是$(git merge-base --all r1 r2)。这是可从r1(左侧)或r2(右侧)之一访问的提交集合方面),但不能两者兼而有之。” -来源:“ man gitrevisions”

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.