非常教程

Git参考手册

调试 | Debugging

git blame

名称

git-blame - 显示修改和作者最后修改了文件的每一行

概要

git blame [-c] [-b] [-l] [--root] [-t] [-f] [-n] [-s] [-e] [-p] [-w] [--incremental]
            [-L <range>] [-S <revs-file>] [-M] [-C] [-C] [-C] [--since=<date>]
            [--progress] [--abbrev=<n>] [<rev> | --contents <file> | --reverse <rev>..<rev>]
            [--] <file>

描述

使用上次修改该行的修订版中的信息为给定文件中的每一行注释。或者,从给定修订开始注释。

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

行的起源会自动沿着整个文件重命名(目前没有选项可以将重命名 - 关闭)。要追踪从一个文件移动到另一个文件的行,或者遵循从其他文件复制并粘贴的行等,请参阅-C-M选项。

报告没有告诉你任何有关已删除或替换的行; 您需要使用git diff以下段落中简要提及的工具或“pickaxe”接口。

除了支持文件注释之外,Git 还支持搜索开发历史记录,以了解更改中发生代码段的时间。这使得追踪代码片段何时被添加到文件,在文件之间移动或复制,并最终被删除或替换成为可能。它通过在 diff 中搜索文本字符串来工作。搜索blame_usage以下内容的镐接口的一个小例子:

$ git log --pretty=oneline -S'blame_usage'
5040f17eba15504bad66b14a645bddd9b015ebb7 blame -S <ancestry-file>
ea4c7f9bf69e781dd0cd88d2bccb2bf5cc15c9a7 git-blame: Make the output

选项

-b

显示边界提交的空白 SHA-1。这也可以通过blame.blankboundary配置选项来控制。

--root

不要将根提交视为边界。这也可以通过blame.showRoot配置选项来控制。

--show-stats

在责备输出结尾包含更多统计数据。

-L <start>,<end> -L :<funcname>

仅注释给定的线范围。可以多次指定。重叠范围是允许的。

<开始>和<结束>是可选的。“-L <开始>”或“-L <开始>”跨越从<开始>到文件结束。“-L,<end>”从文件开始到<结束>。

<开始>和<结束>可以采取以下形式之一:

  • 数字 如果<开始>或<结束>是一个数字,它将指定一个绝对行号(行数从1开始)。
  • / regex / 此表单将使用与给定的 POSIX 正则表达式匹配的第一行。如果<start>是一个正则表达式,它将从前一个-L范围的末尾(如果有的话)开始搜索,否则从文件起始处开始搜索。如果<start>是“^ / regex /”,它将从文件开头搜索。如果<end>是一个正则表达式,它将从<start>给出的行开始搜索。
  • + offset 或 -offset 这仅对<end>有效,并将在<start>给出的行之前或之后指定行数。

如果给出“:<funcname>”来代替<start>和<end>,它是一个正则表达式,表示从匹配<funcname>的第一个funcname行到下一个funcname行的范围。“:<funcname>”从上一个-L范围的末尾(如果有)搜索,否则从文件开头搜索。“^:<funcname>”从文件开头搜索。

-l

显示长时间(默认:关闭)。

-t

显示原始时间戳(默认值:关闭)。

-S <revs-file>

使用 revs-file 中的修订版而不是调用 git-rev-list [1]。

--reverse <rev>..<rev>

前进而不是后退。它不是显示一行出现的修订,而是显示一行存在的最后修订。这需要一系列的修订,如 START..END,在 START 中存在责任路径。git blame --reverse STARTgit blame --reverse START..HEAD为了方便。

-p --porcelain

以设计用于机器消耗的格式显示。

--line-porcelain

显示 porcelain瓷格式,但输出每行的提交信息,而不仅仅是第一次引用提交。意味着 - 瓷器。

--incremental

以设计用于机器消耗的格式逐步显示结果。

--encoding=<encoding>

指定用于输出作者姓名和提交摘要的编码。将其设置为none使责备输出未转换的数据。有关更多信息,请参阅有关 git-log [1]手册页中编码的讨论。

--contents <file>

当未指定<rev>时,该命令注释从工作树副本向后开始的更改。该标志使命令假装工作树副本具有指定文件的内容(指定-使命令从标准输入中读取)。

--date <format>

指定用于输出日期的格式。如果未提供--date,则使用 blame.date 配置变量的值。如果 blame.date 配置变量也未设置,则使用 iso 格式。有关支持的值,请参阅 git-log [1]上的--date 选项的讨论。

--no-progress

当连接到终端时,默认情况下标准错误流会报告进度状态。即使没有附加到终端,该标志也可以进行进度报告。不能--progress--porcelain或者 --incrementa一起使用l

-M<num>

检测文件中移动或复制的行。当提交移动或复制一行代码块时(例如,原始文件有A然后B提交将其更改为B然后A),传统blame算法只会注意到一半的移动,并且通常会将被移动的行(即B)交给父母,并将责任分配给向下移动(即A)到子女提交的行。有了这个选项,通过运行额外的检查通道,这两组线都被归咎于父母。

<num>是可选的,但它是 Git 必须检测的字母数字字符数的下限,以便在文件中移动/复制,以便将这些行与父提交相关联。默认值是20。

-C<num>

除了-M检测从同一提交中修改的其他文件移动或复制的行之外。当您重新组织您的程序并在各个文件之间移动代码时,这非常有用。当该选项被赋予两次时,该命令会另外在创建该文件的提交中查找来自其他文件的副本。当该选项被赋予三次时,该命令还会在任何提交中查找来自其他文件的副本。

<num>是可选的,但它是 Git 必须检测的字母数字字符数的下限,作为文件之间的移动/复制,以便将这些行与父提交相关联。默认值是40.如果有多个-C选项,最后的<num>参数-C将生效。

-h

显示帮助信息。

-c

使用与 git-annotate [1]相同的输出模式(默认值:关闭)。

--score-debug

包含与文件之间的行移动有关的调试信息(请参阅参考资料-C)和文件中移动的行(请参阅参考资料-M)。列出的第一个数字是分数。这是检测为在文件之间或文件内移动的字母数字字符的数量。这必须高于某个阈值git blame才能考虑这些代码行已被移动。

-f --show-name

在原始提交中显示文件名。默认情况下,如果由于重命名检测而出现来自具有不同名称的文件的任何行,则会显示文件名。

-n --show-number

在原始提交中显示行号(默认值:关闭)。

-s

从输出中抑制作者姓名和时间戳。

-e --show-email

显示作者电子邮件而不是作者姓名(默认:关闭)。这也可以通过blame.showEmail配置选项来控制。

-w

比较父母的版本和孩子的时候,忽略空格以找到行的来源。

--abbrev=<n>

使用默认的 7 + 1 十六进制数字作为缩写对象名称,而不是使用<n> +1个数字。请注意,1列用于插入符号来标记边界提交。

--indent-heuristic --no-indent-heuristic

这些是为了帮助调试和调整实验启发式(默认情况下是关闭的),这些启发式技术改变了差异边界以使修补程序更易于阅读。

porcelain(瓷器)的格式

在这种格式下,每一行在一个标题后输出; 最低标题的第一行有:

  • 该行提交的40字节 SHA-1归因于;
  • 原始文件中行的行号;
  • 最终文件中行的行号;
  • 在从一个不同于上一个提交的提交开始一组行的行中,该行中的行数。在随后的行中,该字段不存在。

对于每个提交,此标题行后面至少有一次以下信息:

  • 作者姓名(“作者”),电子邮件(“作者邮件”),时间(“作者时间”)和时区(“author-tz”); 提交者也是如此。
  • 行被归于的提交中的文件名。
  • 提交日志消息的第一行(“摘要”)。

实际行的内容在上面的标题之后输出,以 TAB 为前缀。这是为了稍后允许添加更多的标题元素。

porcelain(瓷器)格式通常会抑制已经看到的提交信息。例如,两条指向同一提交的行都会显示,但该提交的详细信息只会显示一次。这样更有效率,但可能需要读者保留更多的状态。该--line-porcelain选项可用于输出每行的完整提交信息,从而允许更简单(但效率较低)的用法,如:

# count the number of lines attributed to each author
git blame --line-porcelain file |
sed -n 's/^author //p' |
sort | uniq -c | sort -rn

指定范围

不同于git blamegit annotate在旧版本的 git 的,注释的程度可以被限制到两个线范围和修订的范围。将-L注释限制为一系列行的选项可以多次指定。

当你有兴趣为foo文件寻找40-60行的起源时,你可以使用-L像这样的选项(它们的意思是相同的 - 都要求从第40行开始的21行):

git blame -L 40,60 foo
git blame -L 40,+21 foo

你也可以使用正则表达式来指定行范围:

git blame -L '/^sub hello {/,/^}$/' foo

这将注释限制在hello子例程的主体中。

如果您对版本v2.6.18以前的更改不感兴趣,或者更改时间超过3周,则可以使用类似于git rev-list以下内容的版本范围说明符:

git blame v2.6.18.. -- foo
git blame --since=3.weeks -- foo

使用修订范围说明符来限制注释时,自范围边界(上图中的提交v2.6.18或最近提交超过3周)以来未更改的行被指定为该范围边界承诺。

一种特别有用的方法是查看添加的文件是否具有通过从现有文件进行复制和粘贴创建的行。有时候这表明开发人员马虎,没有正确重构代码。您可以首先找到引入该文件的提交:

git log --diff-filter=A --pretty=short -- foo

然后使用commit^!符号注释提交与其父母之间的更改:

git blame -C -C -f $commit^! -- foo

增量输出

使用--incremental选项调用时,该命令会在结果生成时输出结果。输出通常会首先讨论最近提交时触及的行(即行将被乱序注释),并被交互式查看者使用。

输出格式与 Porcelain 格式类似,但不包含正在注释的文件中的实际行。

  • 每个blame条目总是以一行:<40-byte hex sha1> <sourceline> <resultline> <num_lines>

Line numbers count from 1.

  1. 当一次提交首次出现在流中时,它会在每行开始处描述额外提交信息(作者,电子邮件,提交者,日期,摘要等等)中打印出各种其他信息。 )。
  2. 与 Porcelain 格式不同,文件名信息总是给出并终止条目:“filename”<whitespace-quoted-filename-goes-here>

因此解析某些面向行和面向字的解析器(对于大多数脚本语言而言这应该是很自然的)真的很容易。

 Note

对于进行解析的人来说:为了使其更加健壮,只要忽略第一个和最后一个(“<sha1>”和“文件名”行)之间不识别标记词(或关心那个特定词)的任何行,在“扩展信息”的开头。这样,如果有任何增加的信息(如提交编码或扩展提交评论),责备观众不会在意。

映射作者

如果文件.mailmap存在于存储库的顶层,或者位于 mailmap.file 或 mailmap.blob 配置选项所指向的位置,则它用于将作者和提交者名称以及电子邮件地址映射到规范的实名和电子邮件地址。

在简单的形式中,文件中的每一行由作者的标准真实姓名,空格以及在提交中使用的电子邮件地址(用<and >括起来)映射到名称。例如:

Proper Name <commit@email.xx>

更复杂的形式是:

<proper@email.xx> <commit@email.xx>

它允许 mailmap 只替换提交的电子邮件部分,并且:

Proper Name <proper@email.xx> <commit@email.xx>

它允许 mailmap 替换与指定的提交电子邮件地址匹配的提交的名称和电子邮件,以及:

Proper Name <proper@email.xx> Commit Name <commit@email.xx>

它允许 mailmap 替换与指定的提交名称和电子邮件地址相匹配的提交的名称和电子邮件。

示例1:您的历史记录包含两位作者 Jane 和 Joe 的提交,他们的名字以几种形式出现在存储库中:

Joe Developer <joe@example.com>
Joe R. Developer <joe@example.com>
Jane Doe <jane@example.com>
Jane Doe <jane@laptop.(none)>
Jane D. <jane@desktop.(none)>

现在假设乔想让他的中间名得到最初的使用,而珍则更喜欢将她的姓氏完整地拼出来。一个合适的.mailmap文件应该是这样的:

Jane Doe         <jane@desktop.(none)>
Joe R. Developer <joe@example.com>

注意如何不需要输入<jane@laptop.(none)>,因为该作者的真实姓名已经是正确的。

示例2:您的存储库包含以下作者的提交:

nick1 <bugs@company.xx>
nick2 <bugs@company.xx>
nick2 <nick2@company.xx>
santa <me@company.xx>
claus <me@company.xx>
CTO <cto@coompany.xx>

那么你可能需要一个如下所示的.mailmap文件:

<cto@company.xx>                       <cto@coompany.xx>
Some Dude <some@dude.xx>         nick1 <bugs@company.xx>
Other Author <other@author.xx>   nick2 <bugs@company.xx>
Other Author <other@author.xx>         <nick2@company.xx>
Santa Claus <santa.claus@northpole.xx> <me@company.xx>

将散列#用于自己的行中或电子邮件地址之后的注释。