简体中文 ▾ 主题 ▾ 最新版本 ▾ git-blame 最后更新于 2.53.0

名称

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>]
	  [--ignore-rev <rev>] [--ignore-revs-file <file>]
	  [--color-lines] [--color-by-age] [--progress] [--abbrev=<n>]
	  [ --contents <file> ] [<rev> | --reverse <rev>..<rev>] [--] <file>

描述

在指定文件的每一行上注释最后修改该行的修订版本信息。可选地,从指定的修订版本开始进行注释。

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

行来源会自动跨越整个文件的重命名进行追踪(目前没有关闭重命名追踪的选项)。要追踪从一个文件移动到另一个文件的行,或者追踪从另一个文件复制粘贴的行等,请参阅 -C-M 选项。

该报告不会告诉你任何关于已被删除或替换的行的信息;你需要使用诸如 git diff 之类的工具,或者下文简要提到的“pickaxe”接口。

除了支持文件注释外,Git 还支持在开发历史中搜索某个代码片段何时出现在变更中。这使得追踪代码片段何时被添加到文件、在文件之间移动或复制,以及最终被删除或替换成为可能。它通过在差异(diff)中搜索文本字符串来实现。下面是一个搜索 blame_usage 的 pickaxe 接口的小例子:

$ 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

在 blame 输出的末尾包含额外的统计信息。

-L <起始>,<结束>
-L :<函数名>

仅对 <起始>,<结束> 指定的行范围或由函数名正则表达式 <函数名> 指定的范围进行注释。可以多次指定。允许重叠的范围。

<起始><结束> 是可选的。-L <起始>-L <起始>, 范围从 <起始> 到文件末尾。-L ,<结束> 范围从文件开头到 <结束>

<start><end> 可以采用以下形式之一

  • <number>

    如果 <start><end> 是一个数字,它指定一个绝对行号(行从 1 开始计数)。

  • /<regex>/

    此形式将使用第一个匹配给定 POSIX <regex> 的行。如果 <start> 是一个正则表达式,它将从上一个 -L 范围的末尾(如果存在)开始搜索,否则从文件开头开始搜索。如果 <start>^/<regex>/,它将从文件开头开始搜索。如果 <end> 是一个正则表达式,它将从 <start> 给定的行开始搜索。

  • +<offset>-<offset>

    这仅对 <end> 有效,并将指定 <start> 给定行之前或之后的行数。

如果用 <start><end> 的位置给出了 :<funcname>,它是一个正则表达式,表示从第一个匹配 <funcname> 的 funcname 行到下一个 funcname 行的范围。:<funcname> 从上一个 -L 范围的末尾(如果存在)开始搜索,否则从文件开头开始搜索。^:<funcname> 从文件开头开始搜索。函数名的确定方式与 git diff 如何处理补丁块头相同(参见 gitattributes[5] 中的“定义自定义块头”)。

-l

显示完整修订版本号(默认:关闭)。

-t

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

-S <修订版本文件>

使用来自 <修订版本文件> 的修订版本,而不是调用 git-rev-list[1]

--reverse <起始>..<结束>

向前追溯历史而非向后。不显示某行出现的版本,而是显示该行最后存在的修订版本。这需要一个修订版本范围,如 <起始>..<结束>,且该路径在 <起始> 中必须存在。为了方便,git blame --reverse <起始> 被视为 git blame --reverse <起始>..HEAD

--first-parent

遇到合并提交时只关注第一个父提交。此选项可用于确定某行何时被引入特定的集成分支,而不是何时被引入整个历史记录。

-p
--porcelain

以专为机器处理设计的格式显示。

--line-porcelain

显示 porcelain 格式,但为每一行输出提交信息,而不只是在第一次引用提交时输出。隐含了 --porcelain

--incremental

以专为机器处理设计的格式增量显示结果。

--encoding=<编码>

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

--contents <文件>

使用来自 <文件> 的内容进行注释,如果指定了 <修订版本> 则从其开始,否则从 HEAD 开始。您可以指定 - 来让命令从标准输入读取文件内容。

--date <格式>

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

--progress
--no-progress

即使没有连接到终端,也在标准错误流上启用进度报告。默认情况下,仅在连接到终端时报告进度状态。您不能将 --progress--porcelain--incremental 同时使用。

-M[<数字>]

检测文件内移动或复制的行。当一个提交移动或复制一个行块时(例如原始文件有 A 然后是 B,而提交将其改为 B 然后是 A),传统的 blame 算法只能注意到一半的移动,通常将向上移动的行(即 B)归于父提交,而将向下移动的行(即 A)归于子提交。使用此选项,通过运行额外的检查轮次,两组行都会被归于父提交。

<数字> 是可选的,它是 Git 必须在文件内检测到的移动/复制的字母数字字符数量的下限,以便将其与父提交关联。默认值为 20。

-C[<数字>]

除了 -M 之外,还检测从在同一提交中修改过的其他文件中移动或复制的行。当您重构程序并在文件之间移动代码时,这很有用。当此选项给出两次时,命令还会额外查找来自创建该文件的提交中其他文件的副本。当此选项给出三次时,命令还会额外查找来自任何提交中其他文件的副本。

<数字> 是可选的,它是 Git 必须在文件之间检测到的移动/复制的字母数字字符数量的下限,以便将其与父提交关联。默认值为 40。如果给出了多个 -C 选项,最后一个 -C<数字> 参数将生效。

--ignore-rev <修订版本>

在分配 blame 时忽略该修订版本所做的更改,就好像更改从未发生过一样。由被忽略的提交更改或添加的行将被归咎于先前更改该行或附近行的提交。此选项可以指定多次以忽略多个修订版本。如果设置了 blame.markIgnoredLines 配置选项,那么由被忽略提交更改并归因于另一个提交的行将在 blame 输出中用 ? 标记。如果设置了 blame.markUnblamableLines 配置选项,那么由被忽略提交触及且我们无法归因于另一个修订版本的行将用 * 标记。在 porcelain 模式下,我们会分别在新行打印 ignoredunblamable

--ignore-revs-file <文件>

忽略 <文件> 中列出的修订版本,其格式必须与 fsck.skipList 相同。此选项可以重复使用,这些文件将在 blame.ignoreRevsFile 配置选项指定的任何文件之后处理。空文件名 "" 将清除之前处理的文件中的修订版本列表。

--color-lines

如果默认格式中的行注释与前一行来自同一个提交,则以不同颜色着色。这使得区分由不同提交引入的代码块更加容易。颜色默认为青色(cyan),可以通过 color.blame.repeatedLines 配置选项进行调整。

--color-by-age

在默认格式中根据行的年龄为行注释着色。color.blame.highlightRecent 配置选项控制每个年龄范围使用的颜色。

-h

显示帮助信息。

-c

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

--score-debug

包含与文件间行移动(参见 -C)和文件内行移动(参见 -M)相关的调试信息。列出的第一个数字是得分。这是被检测为在文件之间或文件内部移动的字母数字字符数。该值必须高于某个阈值,git blame 才会认为这些代码行发生了移动。

-f
--show-name

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

-n
--show-number

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

-s

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

-e
--show-email

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

-w

在比较父版本和子版本以寻找行来源时忽略空白。

--diff-algorithm=(patience|minimal|histogram|myers)

选择一种差异算法。变体如下:

default
myers

基本的贪婪差异算法。目前,这是默认值。

minimal

花费额外时间以确保生成最小的差异。

patience

生成补丁时使用“patience diff”算法。

histogram

此算法扩展了 patience 算法以“支持低出现率的常见元素”。

例如,如果您将 diff.algorithm 变量配置为非默认值,但希望使用默认值,则必须使用 --diff-algorithm=default 选项。

--abbrev=<n>

不使用默认的 7+1 位十六进制数字作为缩写对象名,而是使用 <m>+1 位,其中 <m> 至少为 <n>,但要确保提交对象名是唯一的。注意,有 1 列用于脱字符(caret)以标记边界提交。

默认格式

当既未指定 --porcelain 也未指定 --incremental 选项时,git blame 将为每一行输出注释,包括:

  • 该行来源提交的缩写对象名;

  • 作者标识(默认是作者姓名和日期,除非指定了 -s-e);以及

  • 行号

位于行内容之前。

面向机器(PORCELAIN)格式

在这种格式中,每一行都在一个头部之后输出;头部最少包含第一行,其内容为:

  • 该行所属提交的 40 字节 SHA-1 值;

  • 该行在原始文件中的行号;

  • 该行在最终文件中的行号;

  • 对于开启一组来自与前一行不同提交的行组的那一行,显示该组中的行数。在随后的行中,此字段不存在。

在该头行之后,每个提交至少会跟随以下信息:

  • 作者姓名 (author)、邮箱 (author-mail)、时间 (author-time) 和时区 (author-tz);提交者(committer)信息同理。

  • 该行所属提交中的文件名。

  • 提交日志消息的第一行 (summary)。

实际行的内容在上述头部之后输出,并以一个 制表符(TAB) 为前缀。这是为了允许以后添加更多的头部元素。

Porcelain 格式通常会抑制已经出现过的提交信息。例如,归属于同一个提交的两行都会显示,但该提交的详细信息只显示一次。针对单个特定行的信息将不会被分组,例如标记为 ignored(已忽略)或 unblamable(不可溯源)的修订版本。这样效率更高,但可能需要读取器保留更多状态。可以使用 --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 中的 git blamegit annotate 不同,注释的范围可以限制在行范围和修订版本范围。限制注释到行范围的 -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 格式,但它不包含被注释文件的实际行内容。

  1. 每个 blame 条目总是以如下一行开始:

    <40-byte-hex-sha1> <sourceline> <resultline> <num-lines>

    行号从 1 开始计数。

  2. 提交第一次出现在流中时,会打印关于它的各种其他信息,每行开头有一个单词标签描述额外的提交信息(作者、邮箱、提交者、日期、摘要等)。

  3. 与 Porcelain 格式不同,文件名信息总是会给出并结束该条目:

    filename <whitespace-quoted-filename-goes-here>

    因此对于某些面向行和单词的解析器(这对大多数脚本语言来说应该很自然)来说,解析它真的非常容易。

    注意
    对于解析人员:为了使其更健壮,只需忽略第一行和最后一行(<40字节十六进制SHA1>filename 行)之间任何你无法识别标签单词(或不关心该特定单词)的“扩展信息”行即可。这样,如果以后添加了新信息(如提交编码或扩展提交注释),blame 查看器将不受影响。

作者映射

请参阅 gitmailmap[5]

配置

本节中以下所有内容均从 git-config[1] 文档中选择性地包含。内容与彼处相同:

blame.blankBoundary

git-blame[1] 中为边界提交显示空白的提交对象名。此选项默认为 false。

blame.coloring

这决定了应用于 blame 输出的着色方案。它可以是 repeatedLines(重复行)、highlightRecent(高亮近期)或 none(无,默认值)。

blame.date

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

blame.showEmail

git-blame[1] 中显示作者邮箱而非作者姓名。此选项默认为 false。

blame.showRoot

git-blame[1] 中不将根提交视为边界。此选项默认为 false。

blame.ignoreRevsFile

git-blame[1] 中忽略文件中列出的修订版本,每行一个未缩写的对象名。空白和以 # 开头的注释将被忽略。此选项可以重复多次。空文件名将重置忽略的修订版本列表。此选项将在命令行选项 --ignore-revs-file 之前处理。

blame.markUnblamableLines

git-blame[1] 的输出中,用 * 标记那些由被忽略的修订版本更改且我们无法归因于另一个提交的行。

blame.markIgnoredLines

git-blame[1] 的输出中,用 ? 标记那些由被忽略的修订版本更改且我们已归因于另一个提交的行。

另请参阅

GIT

Git[1] 套件的一部分