前言
当我们在做 backport 时,常常会面临这种情况——难以找到一个 commit 的上下文。在 backport 时,我们往往会盯住某一个模块,去查看该模块的 commit history 中有哪些上游更新,从而忽略了某些逻辑上相关而路径上不相关的内容。举个例子:我在尝试上游更新 arch/arm64/lib/
时,查看的是该目录的 commit history ,从而忽略了针对 lib/
或者是 include/linux/
目录修改的前置 commit 。这种忽略轻则导致编译失败,重则导致隐性的不生效。
所以,有没有什么办法能够查看一个 commit 相关的上下文呢?
另外,当我们在做 backport 时,有时还会面临这样一种情况:我明确的想要某个 feature 或者 fix ,但是上游中并没有,那么有没有什么比上游还新的地方,可能有我想要的东西呢?
↑ 为了解决上述问题,隆重请出 Linux Kernel Mailing List (LKML) :
Linux Kernel Mailing List(LKML)是 Linux 内核开发的主要邮件列表,它由 Linus Torvalds 于 1991 年创建,目的是协调 Linux 内核的开发和维护。
LKML 是一个公开的邮件列表,任何人都可以订阅并参与讨论。内核开发人员、Linux 用户、学生、研究人员等等都可以在这个列表上发帖,并且每个帖子都会被发送到订阅列表的所有人手中。订阅者可以回复这些帖子,对其中的问题提出自己的看法或建议,或者对代码进行评审和修复。
在 LKML 上,讨论的主题涉及 Linux 内核的各个方面,包括设计、开发、维护、测试和发布。邮件列表中的讨论非常活跃,许多内核开发者和爱好者都会在这里讨论 Linux 内核的各个方面。
LKML 是 Linux 内核开发的重要组成部分,也是 Linux 社区交流的重要平台之一。在这里,开发者们可以共同探讨 Linux 内核的发展方向和技术细节,使得 Linux 内核不断发展壮大。
(来自 ChatGPT)
↑ 呐,没错,Linux 内核开发的主战场还是在使用老掉牙的邮件系统。
接下来,我们将从 Mailing List 开始,简单的介绍一下该如何优雅的从内核最上游摘取补丁。
Mailing List 如何工作?
众所周知,Mailing List 是可以订阅的,订阅后可以收到大家的讨论邮件。它的订阅方式在网上有许多的介绍,这里就不再赘述了。
现在,让我们来关心一个最基本的问题:邮件,大家都知道,是一个人发给另一个人的,那么为什么我订阅了邮件列表我就可以收到大家的讨论邮件?难道大家在发送邮件时都手动指定了我为收件人吗?
并不是这样的,这个过程是这样实现的:每个人在发送邮件时,需要额外抄送给“邮件列表”,“邮件列表”则会把收到的邮件再转发给它的订阅者,于是这封邮件就被“广播”了出去。
常见的邮件列表可以在这里找到。
不同的邮件列表往往有不同的主题(不同子系统/平台),如果你只关心某些特定的内容,查看/订阅特定的邮件列表即可。
当然,还有一个主邮件列表,叫做 linux-kernel
,其邮件地址为 [email protected]
,它的流量非常大,一天往往有上百封邮件,因此除非你的邮箱容量足够大,否则千万不要订阅 xD 。
以下是一个发送邮件的样例:
git send-email \
[email protected] \
[email protected] \
[email protected] \
path/to/my/mail
这封邮件的主收件人是 [email protected]
,并同时抄送给了邮件列表 [email protected]
和 [email protected]
,于是这俩邮件列表的订阅者也都会收到这封邮件。(可以看到,不是所有邮件列表都是 host by kernel.org 的,也有许多“第三方”的邮件列表)
往往,在发送内核相关邮件时,除了会抄送给主题相关的“特定邮件列表”,也会抄送给“主邮件列表”一份,这也是“主邮件列表”流量巨大的原因之一。
按照我的理解,邮件列表其实是一种抽象的“论坛”组织形式。不同的邮件列表就像论坛中不同的版块,发送给邮件列表的邮件就像论坛中的帖子。既然是论坛,那它也应该要提供组织邮件之间关系的方法,就好比“主题帖”与“回帖”。接下来我们将会浅浅的看一下邮件协议,来理解一下邮件之间的关系是如何进行组织的。
邮件协议
在这里,我想要基于常见的 RFC 5322 规范对邮件头部的部分字段进行介绍,并结合一下 git send-email
命令。
RFC 5322是一份Internet标准,它规定了电子邮件消息的格式和传输规范。该标准在2008年发布,取代了之前的RFC 2822标准。
RFC 5322描述了电子邮件的组成部分、消息头和消息体、邮件地址的格式、日期和时间格式、消息编码和传输规范等方面的细节。它还包括了对一些早期邮件标准的修订和更新,以适应现代电子邮件的需求。
RFC 5322规定了邮件格式的基本要求,包括了邮件头、主题、发件人和收件人等重要信息。邮件头包含了所有关于邮件的元信息,例如主题、发件人、收件人、抄送、密送、日期和时间等。邮件体则包含了实际的邮件内容。
RFC 5322为电子邮件的传输提供了一些规范,例如SMTP(Simple Mail Transfer Protocol)协议,以确保邮件能够在网络上正确地传输。它还指定了如何使用MIME(Multipurpose Internet Mail Extensions)来支持在电子邮件中包含各种类型的附件和多媒体内容。
总之,RFC 5322为电子邮件的格式和传输提供了一个详细的标准,使不同的电子邮件客户端和服务器能够互相兼容,确保电子邮件能够在互联网上稳定、高效地传输。
(来自 ChatGPT)
收件人 和 抄送
首先,我想先说说邮件头部的 To
字段和 Cc
字段,它们分别对应 git send-email
中的 --to
和 --cc
。
在常见的网页版邮箱中,To
对应的是“收件人”,而 Cc
对应的是“抄送”。
这俩字段在实际效果上并没有什么区别,被指定在邮箱都能够收到这封邮件。它们之间的区别更多的是在邮件礼仪上。
To
更多的表示希望收件者能够处理和回应这封邮件;而 Cc
则表示这封邮件并非是针对收件者的,邮件内容仅供参考。
在 To
和 Cc
字段中出现的邮箱,互相都可以看到。也就是说,当你收到一封邮件时,无论你是“收件人”还是“被抄送者”,你都可以看到这封邮件原始的收件人和抄送者有谁。
试想这样一种情况:甲要找乙办事,但是考虑到乙可能不会理他,于是甲就在发送邮件时 Cc 了乙的上级领导丙。于是乙在收到邮件时一看抄送者,“wok 这封邮件我的领导丙也能收到,看来这事不得不认真办”。(←借他人施压)
在 kernel mailing 中,To
一般被设置为直接相关人(比如对应模块的维护者),Cc
则被设置为“可能对此感兴趣的人”以及“邮件列表”。To
和 Cc
都可以有多个,完全没有问题。
唯一标识符
邮件头部还有一个名为 Message-Id
的字段。这个字段是邮件的唯一标识符,每一封邮件的这个字段内容都应该不同。
这个字段由发送方的客户端或是邮件服务器填入,其内容一般是随机字符串或是由时间戳、随机字符以及发送方邮箱地址拼接而成的一长串。
Message-Id
可能长这样:
[email protected]
[email protected]
30646027.20230425162525.6447fef5d41b97.31335891@mail128-83.atl41.mandrillapp.com
又或者干脆完全随机:
6050123042401634172
总之,它对这封邮件起到唯一标识作用,而且需要在邮件被发送时就准备好,因为接收方可以通过这个字段来判断一些意外情况 e.g. 由于网络原因重复收到了相同的邮件。
当然,Message-Id
的作用远大于此,将在下面继续展开。
回复与引用
手动的引用
先不讲邮件协议,先来讲一种约定俗成。
在回复一封邮件时,一般而言我们会在邮件的标题加上 Re:
,并在邮件内容中使用 >>
来引用想要回复的文本。
举个栗子。
原邮件:
标题:我觉得小明做错了
他把 A 错弄成了 B ,并造成了 C 的结果。这一切的责任都应该由他来承担。
回复邮件:
标题:Re: 我觉得小明做错了
>> 他把 A 错弄成了 B
不对,他是把 A 错弄成了 C 。
>> 并造成了 C 的结果
造成的结果是 D。
>> 这一切的责任都应该由他来承担
是小王叫他这么做的,小王也有责任。
回复邮件的回复邮件:
标题:Re: 我觉得小明做错了
>>>> 他把 A 错弄成了 B
>>
>> 不对,他是把 A 错弄成了 C 。
>>
>>>> 并造成了 C 的结果
>>
>> 造成的结果是 D。
>>
>>>> 这一切的责任都应该由他来承担
>>
>> 是小王叫他这么做的,小王也有责任。
我同意你的观点。
总之,就是使用 >>
来引用之前的邮件内容,并针对性的发表你的意见,从而使对方能够更加高效的理解。
这一切是建立在自觉的基础上的,你完全可以不遵守这种格式,甚至可以捣乱去强行引用对方没说过的话(因为引用的内容你完全也可以自己输入)。
而且,在回复时,对方的一句话很有可能会被拆分为多次引用来加强针对性(比如上面的)。
再者,如果有多次来回回复,>>
可能会越堆越高,影响体验,说不定总有一次会被清掉。
说了这么多,我想表达的就是:这种约定俗成是无法被用来可靠的追踪邮件之间的关系的,邮件协议必须提供一种可靠的组织邮件之间关系的方法。
而这正是我接下来想要介绍的内容。
回复与引用字段
于是,邮件的头部中提供了 In-Reply-To
和 References
两个字段,来可靠的追踪邮件之间的关系。
Basically,它们是靠你在发送邮件时手动指定“回复的 Message-Id
”来工作的(一般来说网页版邮箱或者邮件客户端会自动帮你做这件事)。
上面已经说到了,Message-Id
是唯一标识符,那么在回复时通过标识符来指定自己回复的是谁,就非常的可靠了。
举个例子,你收到了一封邮件 A ,假设其 Message-Id
为 aaaaa
。
现在,你想要回复这封邮件,于是你使用 git send-email
发送邮件 B ,指定 --in-reply-to=aaaaa
来表示你回复的是 A 。
假设你所发送的邮件 B 的 Message-Id
为 bbbbb
,那么对方在收到你的回复后,可以使用 --in-reply-to=bbbbb
来回复你的回复。
在上面的来回中,邮件头部的 In-Reply-To
会被设置为 --in-reply-to=
所指定的值,而 References
则会在先前的基础上 append 上新的 In-Reply-To
值,展开看看就是这样:
邮件 A :
Message-ID: <aaaaa>
(回复给 A )
邮件 B :
Message-ID: <bbbbb>
References: <aaaaa>
In-Reply-To: <aaaaa>
(假设对方继续回复 B )
邮件 C :
Message-ID: <ccccc>
References: <aaaaa>
<bbbbb>
In-Reply-To: <bbbbb>
(假设你继续回复 C )
邮件 D :
Message-ID: <ddddd>
References: <aaaaa>
<bbbbb>
<ccccc>
In-Reply-To: <ccccc>
In-Reply-To
总是指定着想要回复的邮件标识符,而 References
则记录着整个邮件来往中涉及到的邮件标识符。
借助这两个字段,我们完全可以可靠的组织邮件,在邮件之间形成一种树状的关系。如果说那个最初的邮件是论坛的“主题帖”的话,我们就可以通过这两个字段轻松的追踪所有的“回帖”,并建立“回帖”之间的关系。具体的东西等下面介绍 lore.kernel.org 的时候再进一步介绍。
其它
邮件的头部还有一些别的有趣的字段,但是由于它们和接下来的内容关系不大,于是就懒得展开解释了。
比如 Received
能够提供邮件传输过程中的接收记录,你可以轻松的知晓这封邮件经过了哪些邮件服务器。
还有比如 Reply-To
和 Mail-Reply-To
能够指定“如果想要回复这封邮件的话,应该回复给谁”,因为有时发件者的邮箱并不接受回复,想要回复需要发到别的邮箱地址。
当然,还有一些非常基础的字段,比如 From
、Date
、Subject
,它们分别标识了邮件的发送者、发送日期和标题。它们都是属于一看就能明白含义的那种,故也没有什么解释的必要了(不过接下来的内容中它们会出现)。
邮件与补丁
接下来,我想要聊聊 git 生成的补丁。
这里所说的补丁,是指使用 git format-patch
命令生成的 .patch
文件。
从历史上来说,这种补丁从设计之初开始就是为了作为邮件发送的,甚至可以说是量身定制的。
我们可以随便生成两个补丁看看:
# 把我的仓库中最新的两条 commit 作为一组补丁进行生成
$ git format-patch -2
0001-oplus_charger-Initialize-works-before-using-them.patch
0002-dsi_panel-Make-sure-the-gpio-is-valid-before-directi.patch
来看看它们的内容(只截取了部分):
......
From: LibXZR <[email protected]>
Date: Sun, 16 Apr 2023 20:45:31 +0800
Subject: [PATCH 1/2] oplus_charger: Initialize works before using them
......
......
From: LibXZR <[email protected]>
Date: Mon, 17 Apr 2023 12:15:05 +0800
Subject: [PATCH 2/2] dsi_panel: Make sure the gpio is valid before direction
input
......
可以看到,补丁的头部字段是和邮件格式相对应的,当把补丁作为邮件发送时,这些字段也会自然而然的成为邮件头部的一部分。
再者,补丁文件本身就是纯文本,不包含任何不可识读的二进制数据,被塞进邮件中一点问题也没有(按照规范,补丁是作为邮件的内容(以及部分头部)来发送的,而不是附件,这很重要,不过 git send-email
会自动帮你处理好这一点)。
其实 git am
除了能够打补丁,还支持打邮件(即包含补丁的原始邮件数据),它会自动处理掉邮件格式中的补丁无关内容,从中提取出真正的补丁然后进行应用(下面会进一步介绍)。
小特性:前缀序号
在上面的例子中能够看到 git format-patch
为生成补丁的标题自动加上了如 [PATCH 1/2]
这样的前缀,这其实是一种便于邮件整理的特性。
补丁往往是一系列的,而且是具有前后依赖关系的,在经过了邮件这一中间介质后,这种顺序可能会是错乱或是丢失的。
(你可能会说,我们生成的补丁文件的文件名不是有 0001
、0002
这样的前缀么?这不是标识着顺序么?那为何要多此一举?别忘了,发送邮件时补丁可不是作为附件的,这里的文件名压根就只是给你自己看的,邮件的接收方可看不到)
于是 git format-patch
会自动在你的 commit message 前面加上这种前缀,表示这是某个补丁序列中的第几个补丁(以及这个序列总共有多少个补丁)。别担心,这个前缀在 git am
时会自动被去掉,没什么不良影响。
小特性:前缀版本
有时候,我们会在改进了自己的补丁后重新发送。在这种情况下,又该如何快速区分哪个补丁更新呢?
emmm ,邮件的 Subject 可是由 commit message 生成的啊,难道我得重新写 commit message 吗?
并不需要,其实你只要在 git format-patch
加上选项 -v
即可。
举个例子:
$ git format-patch -2 -v2
v2-0001-oplus_charger-Initialize-works-before-using-them.patch
v2-0002-dsi_panel-Make-sure-the-gpio-is-valid-before-dire.patch
$ cat v2-0001-oplus_charger-Initialize-works-before-using-them.patch | grep Subject
Subject: [PATCH v2 1/2] oplus_charger: Initialize works before using them
cat v2-0002-dsi_panel-Make-sure-the-gpio-is-valid-before-dire.patch | grep Subject
Subject: [PATCH v2 2/2] dsi_panel: Make sure the gpio is valid before
呐,是不是很方便?
v2 代表第二版补丁,v3 代表第三版,依此类推。当然,这些信息在 git am
时也会自动被去除掉。
小特性:邮件封面
这里的“邮件封面”是对 cover letter 的生硬翻译。
在我们发送一系列的补丁时,总需要总结一下这一系列补丁大概完成了什么样的工作吧?cover letter 起到的就是这样的“总结”作用。
我们可以在 git format-patch
时使用 --cover-letter
选项来让 git 帮我们(部分的)完成这个过程。
$ git format-patch -2 --cover-letter
0000-cover-letter.patch
0001-oplus_charger-Initialize-works-before-using-them.patch
0002-dsi_panel-Make-sure-the-gpio-is-valid-before-directi.patch
生成出来的 cover letter 长这样:
From 86746dbc34d68fd8392064ead51e2ba0b7afc56a Mon Sep 17 00:00:00 2001
From: LibXZR <[email protected]>
Date: Thu, 27 Apr 2023 23:28:57 +0800
Subject: [PATCH 0/2] *** SUBJECT HERE ***
*** BLURB HERE ***
LibXZR (2):
oplus_charger: Initialize works before using them
dsi_panel: Make sure the gpio is valid before direction input
oplus/kernel/charger/oplus_charger.c | 18 ++++++++++--------
techpack/display/msm/dsi/dsi_panel.c | 2 +-
2 files changed, 11 insertions(+), 9 deletions(-)
--
2.34.1
可以看到,其标题的前缀为 [PATCH 0/2]
,即这个补丁的序号为 0 ,同时这个补丁也没有什么实质上的内容。
没错,这是一个补丁,但是是一个空的补丁,其除了 commit message 以外什么都没有。
它里面的 *** SUBJECT HERE ***
和 *** BLURB HERE ***
是让你自己填写标题和内容的地方,就在那里对你的这一系列工作进行一个介绍和总结吧。
嗯,它也是可以通过 git send-email
进行发送的。
小结
在这一部分内容中,我们认识到了 git patch 和邮件之间的血缘关系,也了解到了 git 所提供的邮件标题前缀的一些约定。
接下来,我们将会打开邮件列表,来看看这些东西在实践中是如何被运用的。
lore.kernel.org
lore.kernel.org 是一个邮件列表的归档网站,说白了就是把邮件列表中出现的邮件们保存起来并提供如搜索、关系整理等附加功能。
接下来,我将用一个例子来对 lore 的页面以及 kernel mailing 中的一些规范进行进一步的解释。
这个例子的地址是 https://lore.kernel.org/lkml/[email protected]/ ,你也可以打开这个网址,和我的解释相互对照。
从网址开始
嗯,lore 的页面设计的非常阴间,非常容易让人晕头转向。但是,它的页面是静态的纯文本,因此我们可以简单的通过网址来判断当前处于一个什么样的状态下。
就比如:
这俩,只是在上面地址的基础上简单加上了一个后缀,其页面的内容就有大不同。
这后缀的具体含义将在下面再进一步解释,现在,让我们聚焦于最干净原始地址:
https://lore.kernel.org/lkml/[email protected]/
在这里,前面的 lore.kernel.org
就是这个站的域名,没什么好说的。
再往后,lkml
代表了处于“主邮件列表”中,对于不同的邮件列表,这里的值可能会发生变化,具体可用的邮件列表可以从 lore 的首页点进去然后看一看网址。
再往后,[email protected]
则是这一封邮件的 Message-Id
。
众所周知,Message-Id
是唯一的,因此 lore 可以使用 Message-Id
来轻松的定位邮件。
所以,我们在这个“原始地址”中看到的页面,其绝大部分内容都由这封邮件的内容组成。
看看页面
我们打开上面的,不带后缀的,干净的“原始地址”。
可以看到,页面主要由三大部分组成。
第一部分,邮件的内容:
↑ 这一部分对邮件的内容以及部分头部信息进行了完整的展示。
由于这个链接指向的邮件是一封 conver letter ,故其只有邮件内容,而没有代码的 diff
部分。
点击上图中的 raw
可以打开这封邮件的原始数据,点击 [thread overview]
则可以跳转到第二部分。
第二部分,“帖子概览”:
↑ 这一部分的内容是根据邮件头部的 In-Reply-To
和 References
字段自动生成的,它反映的是一系列邮件之间的关系,以及当前邮件在这一系列关系中的位置。
可能看着有点乱,但是,看到那些日期了吗?日期所对应的每一行都是一封邮件,无论右边的超链接是人名还是邮件标题,它们都是完整的邮件!
至于什么时候只显示人名,什么时候显示完整标题,下面再说。
你只需要点击右侧的超链接,就可以跳转到这封邮件,并查看其内容。
你可以按照论坛的“主题帖”与“回帖”来理解这种关系:
简单来说,你只需要观察缩进即可。没有缩进的是“主题帖”,也就是一封没有指定 In-Reply-To
的邮件。
具有一层缩进的是“一级回帖”,也就是 In-Reply-To
被设置为“主题帖”的邮件。
具有两层缩进的是“二级回帖”,也就是 In-Reply-To
被设置为“一级回帖”的邮件。
依此类推,缩进越多,所对应的回帖级数也越多。
于是,邮件之间的树形关系就被用这种形式展现出来了,简单而优雅。
那么,为什么这些邮件在显示的时候,有时候只显示发送者的名字,有时候又显示邮件的完整标题呢?
据我的观察,它的显示规律大概是这样的:
- 当前所在的邮件,无论如何都会被显示为
发送者名字 [this message]
。 - 回复与评论性质的邮件,一般只显示发送者名字。
- 补丁性质的邮件,一般显示标题。(发送者名字作为非超链接放在旁边)
这种总结只是针对大多数情况,并非是完全准确的,就以上面的例子来说,Theodore Y. Ts'o
所发送的“一级回帖”,是一封评论性质的邮件,但是它的标题被显示了(而且不是完整显示,因为它的标题前面本身还有个 Re:
)。
↑ 我确实不太能够摸清楚它的显隐规则是怎样的,甚至我觉得它的显隐规则是非常 buggy 的。但是这无论是对于查找邮件还是浏览邮件都没有任何影响,你只需要点进去看一看内容就能清楚地知道这封邮件到底是个啥了。
从这里,我想你能够发现一个重要的规范:对于一系列的补丁,cover letter 一般会先被发送来创建一个“主题帖”,而系列中的其它补丁则会作为“一级回帖”来 In-Reply-To
cover letter ,于是这个补丁集就被组织在了一起,查找起来也就方便了许多。 而这,也正是 cover letter 为何会被称为 cover letter 。
把上面的这个例子整理成树形图后,我想应该能够看的更加清楚:
总结:
- 日期的每一行都是一封邮件。
- 看缩进在脑子里构建树形图。
- Cover letter 是主题帖。
- 补丁集是回帖。
- 对 cover letter 的评论可能和补丁集混在同一层(“一级回帖”)。
- 别靠 发送者名字/邮件标题 的显隐来分辨内容,点进去看看才知道到底是啥。
对了,版本不同的补丁(比如 v2 和 v3 ),按照规范是要放在不同的“主题帖”中的。
第三部分,邮件回复
这一部分的内容就相当容易理解了,lore 会自动告诉你如果想要回复这封邮件的话该怎么做。
lore 会自动为你生成 git send-email
命令,并填入相关参数。
平铺的页面
上面的一切,针对的都是不带有后缀的,干净的“原始地址”。
接下来,介绍一下带有特殊后缀的地址,以及 lore 中的跳转操作。
在这里,有俩链接:
它们都可以对这个帖子下的所有内容进行展开,也就是说,把这个“主题帖”下的所有回帖全部铺开显示在一个网页上。
铺开模式有两种:
flat
:只是将全部回帖的内容平铺开,等于在网址后面加上/T
。nested
:平铺开并以缩进的形式展示回帖之间的树状关系,等于在网址后面加上/t
。
嗯,铺开了就更像论坛了是吧 xD 。
无论是在哪种铺开模式下,你都可以通过点击这里的 permalink
来回到不带有后缀的“原始地址”。
从 lore 的列表中打开邮件 / 从谷歌搜索打开邮件时的页面一般都默认带有 /T
的后缀。
由于我不太喜欢这种铺开的模式,因为看着很乱,于是我从谷歌搜索打开的第一件事就是点击 permalink
。
有时候 lore 还会自动在链接后面加上页内定位符,比如 #u
。由于这种东西对页面内容没有影响,只是滚动网页罢了,于是这里就不展开介绍了。
打邮件(不推荐)
所谓的打邮件,其实就是用 git am
打补丁,不过呢,是把邮件当成补丁来打(上面提到过了)。
接下来讲一讲该如何下载和应用整个补丁集。
继续上面的例子,我们可以点击 mbox.gz
把整个帖子下载过来(包括“主题帖”以及其下面的所有“回帖”):
↑ 只要是在这个“主题”中,无论是从哪个邮件下载 mbox.gz
,得到的内容都是一样的,都是整个帖子的内容。
所谓整个帖子的内容,其实就是把帖子中的原始邮件文本全部连接在了一起。
↑ 从之前的分析中可以看到,所谓的补丁集,其实就是“主题帖”(cover letter)的“一级回帖”,此时我们下载了整个帖子,因此整个补丁集就已经被包含在这个邮件文件中了。
在解压缩后,我们可以直接应用这个邮件集合,git 会自动处理掉邮件协议中与补丁不相关的部分。
# 下载邮件集,相当于点击 `mbox.gz` 。
$ wget https://lore.kernel.org/lkml/[email protected]/t.mbox.gz
# 解压缩
$ gunzip t.mbox.gz
# 应用
$ git am t.mbox -3
这里的 -3
是在告诉 git am
要使用三方合并的冲突处理方式,也就是像 git cherry-pick
那样处理冲突。我想,没人喜欢用阴间的 --reject
来处理补丁冲突吧?
接下来,git 将会按顺序应用这个邮件集合中的所有补丁内容。
那个,上面也说过了,cover letter 本质上也是一个补丁,只不过这个补丁的内容是空的。
所以,最先被应用的补丁,会是空的 cover letter ?
没错,是这样的:
$ git am t.mbox -3
Patch is empty.
When you have resolved this problem, run "git am --continue".
If you prefer to skip this patch, run "git am --skip" instead.
To restore the original branch and stop patching, run "git am --abort".
在“打邮件”时,假如你正在应用的是一个补丁集,那遇到这样的情况非常正常,只需要使用 git am --skip
跳过即可。
除了 cover letter 以外,回复和讨论相关的邮件(即没有 diff
内容的邮件)都会被当成空补丁处理,需要手动进行跳过。
哦对了,上面所说的“按顺序应用”,按的并不是 patch 的序号,而是它出现在这个 mbox
文件中的顺序。
这两者的顺序可能是不同的,因此可能会造成意外的问题,这也是我不推荐使用这种方法打补丁的重要原因。
另外,应用单个补丁(而不是整个帖子)也是可行的,你只需要将那个邮件的 raw
文件下载过来即可。
b4 工具
我想,这才是从 lore 拉取补丁的正统方法。
在过去几周中,我一直在开发一个工具,用于从 lore.kernel.org 中获取补丁并执行大多数维护者常见的后处理操作,包括:
- 将补丁重新排列为正确的顺序
- 统计各种后续跟踪信息,例如已审核、已确认等
- 检查是否存在更新的补丁系列修订版本,并自动获取它。
- 这个工具最初被称为 "get-lore-mbox" ,但现在已经成为一个名为 "b4" 的独立项目。你可以在 git.kernel.org 和 pypi 上找到它。
(来自 https://people.kernel.org/monsieuricon/introducing-b4-and-patch-attestation )
这个工具的源码可以在 git.kernel.org 和 pypi 找到。
安装它非常简单,首先安装 python 和 pip ,然后 pip install b4
即可。
这个工具带有许多内核维护向的功能,你可以打开上面的链接自己去具体阅读一下相关文档。在这里,我们只关心如何使用它来从 lore 上拉取和应用补丁。
非常简单:
b4 am -o - "补丁对应的 Message id " | git am -3
上面这一行命令做了以下几件事:
- 从 lore 拉取指定的补丁。
- 将补丁通过管道传递给 git 。
- 在应用补丁时采用三方合并。
你甚至可以把命令封装成一个脚本:
~/bin/pw
#! /usr/bin/bash
b4 am -o - "$1" | git am -3
确保它在 PATH 里,给足权限,然后像 cherry-pick 一样简单的使用,比如:pw [email protected]
。
b4 工具在拉取补丁时会自动完成以下事情:
- 查找所给
Message-Id
对应的“主题帖”。 - 拉取“主题帖”下的所有补丁邮件(非补丁相关邮件会被直接去除掉)。
- 去除邮件协议中的非补丁相关部分。
- 还原补丁的正确顺序。
- ......
总的来说,开箱即用,非常友好。
补丁的搜索
对于 lore 来说,搜索补丁只需要在其首页或对应 mailing list 的搜索框中输入关键词(比如补丁的标题),然后点击 search all inboxes
或 search
即可。
只不过,这个搜索体验实在是不怎么友好,经常会出现一大堆的无关内容。
所以,对于搜索补丁,我还是更倾向于使用谷歌。只要随便一个邮件列表归档网站收录了这个补丁,那么我都可以轻松的获得其 Message-Id
,然后反过来用拼凑网址的方法在 lore 上查看它或者直接使用 b4
工具拉取它。
后记
这篇文章粗略的介绍了 Linux Kernel Mailing List ,并展示了邮件与 git 补丁之间千丝万缕的联系。
现在,可以回答前言中的那个问题了:
有没有什么办法能够查看一个 commit 相关的上下文呢?
只需要使用任意方式搜索它的 commit message ,找到它对应的邮件 Message-Id
,然后利用像 lore 这样的邮件列表归档找到它所属的“主题帖”,自然而然的,上下文相关的补丁也都会展示在你的面前了。
当然,除了 lore ,还有许多界面更加友善的邮件列表归档,比如 https://patchwork.kernel.org/ 。
不过它们收录的补丁似乎远不及 lore 来的齐全,而且界面有点太友善以至于没什么介绍的必要了...
参考资料
- https://en.wikipedia.org/wiki/Conversation_threading
- https://docs.kernel.org/translations/zh_CN/process/submitting-patches.html
- https://en.wikipedia.org/wiki/Email#Internet_Message_Format
- https://lpc.events/event/11/contributions/983/attachments/759/1421/Doing%20more%20with%20lore%20and%20b4.pdf
- https://people.kernel.org/monsieuricon/introducing-b4-and-patch-attestation
- https://adam.younglogic.com/2022/10/apply-linux-kernel-patches-from-lkml/
- https://blog.csdn.net/jianchi88/article/details/124960869
内容非常地详实,牛
非常受用,费心了
很不错,节约了不少学习成本,3Q大佬