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/

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 = "!"

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. 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 "" "$@"

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 over the formatted patches. The logic in 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: <>
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!