"git blame" 是什么?

496

我看到了很多关于如何使用git blame的问题,但是我并不真正理解它们。

在GitHub界面的文件顶部,我看到一个Blame按钮。点击它后,它会显示一些差异和用户名在左侧栏上。这表示什么?

除了GitHub之外,为什么要使用git blame?


120
如果“blame”这个词听起来过于指责,那么你可以安装这个脚本,使用git praise代替:) https://github.com/ansman/git-praise - Jon Kiparsky
21
它既不该受到责备也不应受到赞扬;它本质上是主观的,应该是客观的。 - pdvries
130
“git客观确定贡献者”这个说法不太顺口。” - Ritwik Bose
79
@RitwikBoseжҲ–д»…д»…жҳҜgit whoзҡ„ж„ҸжҖқжҳҜиҜўй—®еҪ“еүҚжӯЈеңЁдҪҝз”ЁGitзүҲжң¬жҺ§еҲ¶зі»з»ҹзҡ„з”ЁжҲ·жҳҜи°ҒгҖӮ - aktivb
28
对于那些认为“责备”是一个不好的选择的人,请回想一下git的起源 - zelusp
显示剩余5条评论
6个回答

345

来自于git-blame:

用修改每一行的修订版本的信息对给定文件进行注释。可选地,从给定修订版本开始进行注释。

当指定一次或多次时,-L将注释限制为请求的行。

例子:

johndoe@server.com:~# git blame .htaccess
...
^e1fb2d7 (John Doe 2015-07-03 06:30:25 -0300  4) allow from all
^72fgsdl (Arthur King 2015-07-03 06:34:12 -0300  5)
^e1fb2d7 (John Doe 2015-07-03 06:30:25 -0300  6) <IfModule mod_rewrite.c>
^72fgsdl (Arthur King 2015-07-03 06:34:12 -0300  7)     RewriteEngine On
...
请注意,git blame无法按照时间顺序显示每行修改的历史记录,它只会显示在文档中最后一个提交至HEAD时更改该行的人员信息。
换句话说,要查看文档行的完整历史记录/日志,您需要在您的git log中的每个提交上运行git blame path/to/file

5
那么这只是为了让最后一个人看到吗? - Rıfat Erdem Sahin
4
可以,它允许您查看最后更改该行的人。 - Mark
@Mark 当我们在IDE上进行注释时,它内部会执行git blame命令吗? - Nagarajan Shanmuganathan
3
是的,如果你使用git,那么这就是在幕后发生的事情。 - Mark

337

这是为了找出哪位同事写了具体的代码或者破坏了项目,从而让你能够指责他们 :)


165
这个命令听起来好像是你要通过运行它来责怪某人。至少在我在这篇文章中了解这个命令之前是这样听起来的。 - Francisco C.
19
你需要的是这个:https://github.com/jayphelps/git-blame-someone-else。 - DustWolf
28
也许只是措词问题,但“git blame”听起来好像会有某种持久的影响,类似于“git commit”,而实际上它只是告诉你由谁进行了什么更改。这个命令带有“责备”的负面含义,让人感觉应该避开它,从而引发像这样寻求澄清的问题。 - Francisco C.
48
显然,它应该被称为“git praise”。 - pfnuesel
4
鉴于Linus发现Git这个词的定义很有趣,因此他认为自己就是Git,于是给这个系统命名。因此,“Blame”可能被理解为非常适合的名称。 - volvox
显示剩余3条评论

108

来自GitHub

blame命令是Git的一个功能,旨在帮助您确定谁修改了文件。

尽管名字听起来有点负面,但git blame实际上相当无害;它的主要功能是指出谁更改了文件中的哪些行以及原因。它可以是一个有用的工具,用于识别代码中的变化。

基本上,git-blame被用来显示文件的每一行最后修改的修订版本和作者。就像查看文件开发历史。


2
这对我来说似乎有些冗余,你可以在提交之间查看差异并从提交日志中识别用户。如果我理解得没错,它比提交历史记录具有更少的持久性。也许我漏掉了什么,但这似乎像是通过公开羞辱来执行编码标准。 - user1431356
10
我猜这个命令的名字是来自于Linus特有的幽默感 :) 它的意图并不是要羞辱任何人 :) 只是一个有趣(或者不是)的选择作为一个有用命令的名称 :) - Mladen B.
3
@user1431356 - 关键是你想要影响特定行的第一个日志行。否则,你需要在日志中搜索特定的字符串。(这确实是一种可行的方法-查看"git log -S"的手册页面。) - azernik
4
“Blame”这个标题在Git出现之前就已经存在了很多年。只需看看svn的实现即可(http://svnbook.red-bean.com/en/1.8/svn.ref.svn.c.blame.html)。这不是Linus Torvalds赋予的名称。 - JackAce
3
哈哈...更像是Linus的个性,而且确实是用来羞辱某人的。 我猜命令的名字是Linus特有的幽默感 :) 它并不是用来羞辱任何人的 :) - Sinaesthetic

53

git blame命令用于查看哪个提交负责了最近对一个文件的更改。还可以查看每行代码的作者和提交信息。

git blame 文件名(查看所有代码行中的更改所负责的提交)

git blame 文件名 -L 0,10(查看从第 "0" 行到第 "10" 行之间的更改所负责的提交)

虽然还有很多其他的选项可以使用,但通常这些命令已经足够帮助我们完成任务。


14

Git blame命令用于逐行检查文件内容,查看每一行的最后修改时间和修改者。

如果代码中有 bug,可以使用 git blame 命令来查看是谁造成了问题,然后你就可以责怪他了。Git blame 就像是“得到谴责(get blame)”。

如果你需要了解某一行代码的历史记录,请使用 git log -S"这里放代码"。它比 git blame 要简单。

git log vs git blame


5

git blame 命令会为每一行代码添加信息,这些信息来自于最后修改该行代码的版本。从 Git 2.22(2019 年第二季度)开始,由于在 "git blame" 命令中进行了性能修复,特别是在线性历史记录(这是我们应该优化的常态)中,它将更加快速。

请参见 提交 f892014(2019 年 4 月 2 日),作者为 David Kastrup (fedelibre)(由 Junio C Hamano -- gitster --提交 4d8c4da 中合并,2019 年 4 月 25 日)

blame.c: 尽可能不要轻易丢弃原始 blob

当父 blob 已经有排队等待 blame 的块时,将该 blob 丢弃在 blame 步骤的末尾会导致它立即重新加载,这将在处理线性历史记录时增加 I/O 和解包的数量。

在内存中保留这样的父 blob 似乎是一个合理的优化,应该主要在处理来自旧分支的合并时承担额外的内存压力。


在 Git 2.41 (2023 年第二季度) 之前,"git blame --contents=<file> --``"(man) 被禁止,但现在它通过引导到 <rev> 的历史记录,在 <file> 内容中找到行的起源。

请查看提交 1a3119e(2023年3月24日)由Jacob Keller (jacob-keller)提交。
(由Junio C Hamano -- gitster --合并于提交62df03c,2023年4月4日)

blame:允许--contents与非HEAD提交一起使用

签署者:Jacob Keller

The --contents option can be used with git blame(man) to blame the file as if it had the contents from the specified file.
This is akin to copying the contents into the working tree and then running git blame.
This option has been supported since 1cfe773 (git-blame: no rev means start from the working tree file., 2007-01-30, Git v1.5.0-rc4 -- merge) ("git-blame: no rev means start from the working tree file.")

The --contents option always blames the file as if it was based on the current HEAD commit.
If you try to pass a revision while using --contents, you get the following error:

fatal: cannot use --contents with final commit object name

This is because the blame process generates a fake working tree commit which always uses the HEAD object as its sole parent.

Enhance fake_working_tree_commit to take the object ID to use for the parent instead of always using the HEAD object.
Then, always generate a fake commit when we have contents provided, even if we have a final object.
Remove the check to disallow --contents and a final revision.

Note that the behavior of generating a fake working commit is still skipped when a revision is provided but --contents is not provided.
Generating such a commit in that case would combine the currently checked out file contents with the provided revision, which breaks normal blame behavior and produces unexpected results.

This enables use of --contents with an arbitrary revision, rather than forcing the use of the local HEAD commit.
This makes the --contents option significantly more flexible, as it is no longer required to check out the working tree to the desired commit before using --contents.

blame-options现在在其手册页面中包括:

假装被注释的文件有一个提交,其中包含来自命名文件的内容和父级为<rev>,当未指定<rev>时默认为HEAD。
您可以指定'-'使命令从标准输入读取文件内容。

git blame现在在其手册页面中包括:

[--contents <file>] [<rev> | --reverse <rev>..<rev>] [--]<file>


在 Git 2.41(2023 年第二季度)中,由 "git blame"(man) 输出的内容将一行归因于由 --contents 选项指定的文件和工作树文件中的不同。

请参见603d0fd提交(2023年4月24日),提交者为Jacob Keller (jacob-keller)
该代码已于2023年5月2日由Junio C Hamano -- gitster合并至cf85f4b提交

blame:使用不同的作者名称为由--contents生成的虚假提交

建议者:Junio C Hamano
建议者:Glen Choo
签署者:Jacob Keller

当使用--contents选项与git blame(man)一起使用时,如果文件的内容有些行无法被归咎于被责备的历史记录,用户将看到一个“尚未提交”的作者。
这类似于在没有修订的情况下责备工作树内容时blame处理的方式。

这有点令人困惑,因为这些数据不是工作副本,虽然从技术上讲它们“尚未提交”,但它们也来自外部文件。
将此作者名称替换为“外部文件(--contents)”,以更好地区分这些行与实际工作副本行。

blame-options现在包括在其手册页面中:

使用指定文件中的内容进行注释,如果指定了<rev>,则从该版本开始,否则从HEAD开始。
您可以指定“-”使命令从标准输入读取文件内容。

Git发布说明 < GitHub博客上的Git更改日志 << 通过VonC的活动订阅获取Git更改日志 - Guildenstern
1
@Guildenstern 谢谢您的反馈 :) 这是我跟踪 Git 的功能的方式,一步步地了解最新的情况。 - VonC

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