b4でLinux MLのパッチを当てる

先日のOpen Source Summit Japan 2020でb4というツールを紹介するセッション[^session]があったのですが、便利そうだったので試してみました。

[^session]: https://ossalsjp20.sched.com/event/f2PO/new-tools-improve-patch-submission-review-and-other-processes-frank-rowand-sony です。発表スライドもあります。

# 何をするものか
b4は[lore.kernel.orgのLinux MLアーカイブ](https://lore.kernel.org/lists.html)からgit amに適した形でパッチをダウンロードしたり、返信を含むスレッド全体をmbox形式でダウンロードできるツールです。他にもパッチの操作に関する機能がいくつかあります。公式ページは[ここ](https://git.kernel.org/pub/scm/utils/b4/b4.git/about/)のようです。

なおLinux MLのアーカイブサイトはいつかありますが、loreは比較的最近登場したkernel.org公式のアーカイブサイトです。因みに名前の由来はスタートレックのようです(何もわからない...)。

# 使い方
## インストール
まずpipでインストールします。

```bash
$ pip install b4
```

ヘルプは普通に"-h"をつければ見れます。"man b4"でmam pageも見れます:

```bash
$ b4 --version
0.6.1

$ b4 -h
usage: b4 [-h] [--version] [-d] [-q] {mbox,am,attest,pr,ty,diff} ...

A tool to work with public-inbox patches

positional arguments:
  {mbox,am,attest,pr,ty,diff}
                        sub-command help
    mbox                Download a thread as an mbox file
    am                  Create an mbox file that is ready to git-am
    attest              Create cryptographic attestation for a set of patches
    pr                  Fetch a pull request found in a message ID
    ty                  Generate thanks email when something gets merged/applied
    diff                Show a range-diff to previous series revision

optional arguments:
  -h, --help            show this help message and exit
  --version             show program's version number and exit
  -d, --debug           Add more debugging info to the output (default: False)
  -q, --quiet           Output critical information only (default: False)
```

"b4 am -h"などとすると各コマンドの詳細ヘルプも見れます。

## パッチを当てる

幾つか機能がありますが、一番はパッチを当てることだと思うのでやってみます。

まずloreのアーカイブからダウンロードしたいパッチのメッセージIDをコピーします。メッセージIDはloreではURLの一部になっている英数字の羅列の部分です (例えばなんとなく目に付いた[このパッチ](https://lore.kernel.org/lkml/CAK8P3a1p8yKMKXB1cUpy-5PjehJGPX0SPNEx4VsMmqgOeR6fZg@mail.gmail.com/T/#mb857873097de233dc0be42eb62573df8ac58585e)の例だと、"CAK8[中略].com"までがメッセージIDです)。なお複数パッチから構成されている場合はどのパッチのメッセージIDでも問題ありません。またアーカイブはサブシステムごとに分かれていますが、どのサブシステムでも使えます。

"b4 am"コマンドではメッセージIDを指定してパッチ全体をダウンロードします:

```bash
$ b4 am <msgid>
```
version名や日付、送信者名、カバーレターのタイトルなどが含まれた"~.cover"と"~.mbx"の2つのファイルが作成されますが、.coverがカバーレターの内容、.mbxがパッチの内容です。なおデフォルトでは単にパッチをダウンロードしてくれるだけではなく、パッチに対する返信に基づいて自動でAcked-byやReviewed-byのタグをコミットメッセージに付与してくれます。

そして.mbxのファイルはそのままgit amできます:

```bash
git am <b4で作成した.mbxファイル>
```

ファイルを作りたくなければ"-o -"オプションを追加してb4の出力をstdoutに出して、git amにパイプすれば良いです:

```bash
b4 am <msgid> -o - | git am
```

("-o -"をつけると自動的にカバーレターはダウンロードされなくなるのでそのままパイプできます)


なお"am"のかわりに"mbox"コマンドを使う場合、パッチだけではなく返信メッセージも含めて1つのmbox形式でまとめてダウンロードできます。

* 2022年追記
b4 version 0.9から"shazam"というコマンドが追加されており、上のコマンドの代わりに利用できます:

```bash
b4 shazam <msgid> # <msgid>のパッチをダウンロードして現在のブランチに当てる ('b4 am <msgid> -o - | git am'と同等)
```

## 気になる機能

ヘルプを見ていると色々なオプションがあることがわかります。

### 最新のパッチを取得
"b4 am"に-cをつけると新しいバージョンのパッチが出ている場合、指定されたメッセージIDのパッチではなく、最新バージョンのパッチをダウンロードします:

```bash
$ b4 am -c <msgid>
```

(カバーレターの名前で同じパッチかどうかを判定しているようなので、当然ながらカバーレターのタイトルが変わると正しくバージョンを認識できません)

### 前回のバージョンとのrange diffを表示

"b4 diff"コマンドでは前回のパッチとのrange diffを表示してくれます:

```bash
$ b4 diff -g <path/to/linux/git/tree> <msgid>
```

ログを見る限り、1) 前回のパッチと今回のパッチの両方をダウンロードし, 2) それぞれをgit amして[^gitam], 3) git range-diffでパッチ間のdiffを表示, ということを自動でやってくれるようです。これは便利です。

(こちらもタイトルが変わっていたりすると無理な場合があるようです)

[^gitam]: temporaryなworktreeを作ってそこにamして、ヒストリーだけ保存させているようです


# おわりに
とりあえず単にパッチを当てる作業に使う分には問題がないと思います。いろいろと機能があるので細かい点については要検証です。またb4はかなり積極的に開発されているようなので(確かOSSJのセッションを聞いた時はv0.5.4だったのですが、今見ると0.6.1になっています)、何か気になる点があれば作者にフィードバックをするのが良さそうです。私も引き続き使って見ようと思います。