Generating kernel patchsets


The Linux kernel famously has an email workflow. Ignoring whether or not it’s a good thing, it is still a fact that it can be tricky to follow the process.

One problem I’ve had for years is wrangling git-format-patch and git-send-email to do the right thing. Any time I’ve wanted to send a patchset, I’ve had to search through my shell history to help remember the right incantations.

Obviously this gets old fast and becomes a constant source of friction.


Automation is clearly the answer. A wrapper script over git is always an option but can become overcomplicated over time. I’d rather try to integrate with git than hide it.

The above is not a new idea; there’ve been plenty of previous writing on this. Basically what the two linked approaches suggest is to hook git-send-email to automatically generate To and Cc headers using scripts/get_maintainer.pl.

Unfortunately there are multiple drawbacks of the above approaches:

  1. They do not correctly generate To and Cc headers for cover letters
  2. It is painful to realize the generation is incorrect halfway through sending a large patchset. Half the emails are already sent – you cannot take them back.

After some experimenting, I offer a slightly improved solution.


The first improvement I’m offering is to generate the headers during git-format-patch time. This allows you to eyeball the results before sending. This also gives you a way to incrementally add more emails.

To that end, I ended up using Git aliases to “create” my own git command: git patchset. The alias is defined as follows:

        patchset = "!linux-patchset.sh"

In other words, all it does is run a script. Note that all arguments after git patchset are forwarded to the script as positional arguments.

linux-patchset.sh is more or less the following:

ROOT=$(git rev-parse --show-toplevel)
OUTDIR="${ROOT}/outgoing/$(git rev-parse --abbrev-ref HEAD)"

git format-patch -o "$OUTDIR" -s --to "" --cc "" "$@"
LINUX_ROOT="$ROOT" linux-address-patchset.py "$OUTDIR"

Basically what this script does is first git-format-patch the patchset and place the output into linux/outgoing. The output location is not that important – I just prefer it there.

Then it runs linux-address-patchset.py over the formatted patches. The logic in linux-address-patchset.py is fairly mechanical and might be subject to change over time. But the basic idea is for each patch file:

The full scripts are available here.


All together, this how my latest patchset was generated:

$ git patchset -v2 --subject-prefix "PATCH bpf-next" bpf-next/master

And if you take a peek at the first two patches:

$ head -n7 outgoing/ip_check_defrag-v2/v2-0000-cover-letter.patch
From 99ddd1e2b35f6133c1f49a0245340e1a8aaaf32f Mon Sep 17 00:00:00 2001
Message-Id: <[email protected]>
From: Daniel Xu <[email protected]>
Date: Mon, 27 Feb 2023 12:40:10 -0700
Subject: [PATCH bpf-next v2 0/8] Support defragmenting IPv(4|6) packets in BPF
To: [email protected],[email protected],[email protected],[email protected],[email protected]
Cc: [email protected]

$ head -n11 outgoing/ip_check_defrag-v2/v2-0001-ip-frags-Return-actual-error-codes-from-ip_check_.patch
From bf4afe3484836972f94c1b7738845ba69d7008f5 Mon Sep 17 00:00:00 2001
Message-Id: <bf4afe3484836972f94c1b7738845ba69d7008f5.1677526810.git.dxu@dxuuu.xyz>
In-Reply-To: <[email protected]>
References: <[email protected]>
From: Daniel Xu <[email protected]>
Date: Tue, 6 Dec 2022 17:47:16 -0700
Subject: [PATCH bpf-next v2 1/8] ip: frags: Return actual error codes from
To: [email protected],[email protected],[email protected],[email protected],[email protected],[email protected]
Cc: [email protected],[email protected],[email protected]

Happy hacking!