I am mostly writing this as a self memo for how to use git-send-email
, and by
extension git-format-patch
and git-am
, to share patches, patchsets, and
apply them.
Me and my friends like to do these overly elaborate things to share code, what we jokingly call "fossbro roleplaying", so hopefully it can help them, and you as well!
"Wait what's all that about?"
These commands let you create patches that represent a commit (with all of its metadata, save for cryptographic signature), share them automatically over email, and, once someone downloads the contents of your email, apply those commits to a tree.
Preliminary Settings
TL;DR: These are the settings you want to tweak. Mine would be:
git config --global sendemail.smtpencryption tls
git config --global sendemail.smtpserver smtp.vulpinecitrus.info
git config --global sendemail.smtpuser <user>
git config --global sendemail.smtpserverport 587
git config --global sendemail.from <my email>
These settings replace CLI parameters you can otherwise provide when sending
email with git send-email
.
Exporting with format-patch
The git-format-patch
commands turns a commit or set of commits into files that
can be straightforwardly sent as email.
The only real positional argument provides the range or set of commits to format. That can be quite hard to wrap your head around but here's a quick rundown:
Argument | Meaning |
---|---|
<ref> | All commits from <ref> to HEAD |
A..B | All commits in the range from A (excluded) to B (included) |
-n | Last n commits from HEAD |
Note that because git
is the way it is, and because, when you think about it,
it makes sense: when your range includes a divergence, you might pull all of the
divergent commit from it. It's just how git
works. In the end, you will get
all the commits you need, but they will be linearized, so the application order
might be a bit wonky or cause merge errors.
Everything else is just optional arguments. Here are those I think would be the most useful:
--rfc
: your patch or patchset is a request for comments-v <n>
: mark this as version<n>
of your patchset--cover-letter
: generate a file that represents the cover letter, or the big description you send to explain the whole point of your patchset; by default it contains diff stats, and such--thread=<style>
: the thread style controls how your commits follow each other. Ashallow
style means all subsequent email are a reply to the first one (typically the cover letter). That is the standard on LKLMs.--in-reply-to=<message-id>
: oddly enough, I have already had to send a patch as a reply to a human-made series of email. This may be useful for that purpose.
Sending with send-email
This is the big complex part. Technically, git-send-email
is a big Perl script
that wraps around calls to your mail sender. As such, you may find some missing
dependencies such as perl-authen-sasl
on Arch Linux.
The send-email
command takes your files and sends them as email. Easy. Except
it does a lot of things for you and is very fuzzy in terms of available options.
For example, it takes all emails from the Signed-off-by:
and such lines in
your commits, and adds them as Cc:
lines in the email sent unless you tell it
not to.
Here are the options I generally use:
--to=<email>
: a newTo:
line--cc=
: a newCc:
line--bcc=
: a newBcc:
line--compose
: if you did not generate and edit a cover letter, write it now--no-signed-off-by-cc
: this removes the automated gathering of emails in theSigned-off-by:
lines toCc:
--suppress-cc=<choice>
: suppress automatically foundCc:
, you can see the man page for all choices--dry-run
: do everything but send the actual email; the information sent to the SMTP server is shown in the standard output for debugging purposes
There is actually an interesting overlap between send-email
and
format-patch
. You can actually configure most of everything you want for the
content of your email messages via either command, depending on your choice. For
example, had I not chosen threading style in format-patch
, I could have
specified it in send-email
using --[no-]chain-reply-to
.
Applying with am
If you find yourself the (un?)fortunate recipient of a patchset that you fancy
adding to your project, you can simply download your email to files (or,
honestly, just copy the visible content from your email browser), and run
git am
on them. Ideally, you want to apply them in order, and over the
correct commit. The details for how to coordinate with your collaborators for
that to happen is left at your own discretion.
Interestingly, you can use -S
with am
to sign the objects created. The
signature from the original committer in their own repository cannot be
maintained, because you create the actual binary git
objects tied to that
commit in the actual repository yourself, so you must sign and certify that
the content you create that commit with is valid. You are the first person
liable if something wrong is introduced (and others are on the line if there are
Signed-off-by:
lines).
As as interesting side note, many places will let you download .patch
files
that have the correct format to be an email and a git
patch. For example:
- GitHub lets you do so for individual commits by adding
.patch
at the end of the URL, and similarly with pull requests (except the patch contains all individual patches for the PR's commits) - GitLab does the exact same thing for both commits and merge requests
- Gitea/Forgejo also lets you do the same on both commits and PRs
As a result, you will often find yourself using git am
on things that are not
purely email.
As an addendum, I can point you to another tutorial by Matheus Tavares.