Mailing-list contributions
Projects such as Git or the Linux kernel take changes by email. You format your topic branch with a cover letter, -s for sign-off and --to/--cc, then send it with git send-email.
Git · Command
git format-patch turns a range of commits into email-ready patch files, one per non-merge commit, in UNIX mbox style. It keeps the author, date and commit message, so the recipient can rebuild the same commits with git am or send them with git send-email.
Last updated
You pick the commits in one of two ways. A single commit <since> means every commit on the current branch that is not reachable from it, and a revision range means exactly the commits in that range. Each patch has three parts: a header (a From <sha> line with a fixed fake date, plus author, date and a Subject taken from the commit title), the rest of the commit message, and a --- separator followed by the diffstat and diff against the parent. Files are named NNNN-title.patch and go in the current directory, or in the directory given by -o. With --stdout everything is written to standard output as one mbox stream.
git format-patch [-k] [(-o|--output-directory) <dir> | --stdout] [--thread[=<style>]] [-s] [-n | -N] [--cover-letter] [--subject-prefix=<prefix>] [--rfc[=<rfc>]] [-v <n>] [--to=<email>] [--cc=<email>] [--interdiff=<previous>] [--range-diff=<previous>] [--base=<commit>] [<common-diff-options>] [<since> | <revision-range>]| Name | Type | Description |
|---|---|---|
<since> | <revision-range> | revision | Which commits to format. A single commit means everything on the current branch since that commit. A range such as A..B means the commits in that range. |
-<n> | integer | Format only the topmost n commits. For example, -1 <commit> formats just that one commit. |
-o, --output-directory=<dir> | path | Directory to write the patch files to. It overrides format.outputDirectory, and missing directories are created. |
--stdout | flag | Write all patches to standard output in mbox format instead of one file per commit. |
--cover-letter | flag | Also write a 0000 cover-letter file with the branch description, the commit list and the overall diffstat. |
-v, --reroll-count=<n> | string | Marks the series as iteration n. It adds vN- to the filenames and appends vN to the subject prefix. |
--subject-prefix=<prefix> / --rfc[=<rfc>] | string | Use your own subject prefix instead of [PATCH], or put RFC (or another word) in front of it. |
--thread[=shallow|deep] | string | Adds Message-ID, In-Reply-To and References headers so the mails form a thread. Off by default. |
--base[=<commit>|auto] | revision | Records which base tree the series applies on top of. |
-s, --signoff | flag | Adds a Signed-off-by trailer using your committer identity. |
Writes one .patch file per selected non-merge commit, plus an optional cover letter, and prints the generated filenames to standard output. With --stdout it writes one mbox stream to standard output instead.
#!/usr/bin/env bash
set -euo pipefail
# v1: every commit on the current branch that is not in origin/main
git format-patch -o outgoing/ --cover-letter --base=origin/main origin/main
# -> outgoing/0000-cover-letter.patch, 0001-....patch, ...
# v2 after review: compare with the old tip, kept as branch topic-v1
git format-patch -v2 -o outgoing/ --cover-letter \
--range-diff=topic-v1 --base=origin/main origin/main
# -> outgoing/v2-0000-cover-letter.patch, v2-0001-....patch, ...
# Only the latest commit, as an mbox stream
git format-patch -1 --stdout HEAD > latest.patch
# On another clone: recreate the commit with author and message intact
git am latest.patchThe script makes a first and a second version of a series (the second includes a range-diff), then exports one commit and rebuilds it elsewhere with git am.
Projects such as Git or the Linux kernel take changes by email. You format your topic branch with a cover letter, -s for sign-off and --to/--cc, then send it with git send-email.
Two repositories can't reach each other over the network. You copy patch files across, and git am recreates the commits with their original authors and messages.
After review feedback you rebase and send v3 with -v3 and --range-diff=<old-tip>, so reviewers only need to look at what changed.
You export a release branch's commits to numbered .patch files, for example with --numbered-files or --suffix=.txt, to attach to a ticket or keep for compliance.
git diff gives you only the code changes. format-patch writes one mail-style file per commit that also holds the author, the author date and the full commit message, with the diff after a --- line. git am can then rebuild the exact commits, keeping authorship and history, instead of leaving uncommitted changes.
Follow-up: What happens to merge commits in the range? They are skipped, because format-patch only handles non-merge commits. A history that contains merges has to be made linear, or shared another way such as git bundle or a pull request.
Run format-patch with -v3, which puts v3- in front of the filenames and gives subjects like [PATCH v3 n/m]. Add --cover-letter and --range-diff=<v2-tip> or --interdiff=<v2-tip> so the comparison with v2 is included. You can also use --in-reply-to=<message-id> so v3 stays in the earlier thread.
Follow-up: Why does --creation-factor default to 999 here and not 60 as in git range-diff? Because rerolls are expected to resemble the old series, the higher value makes the tool more willing to pair old and new commits.
It is a fixed, made-up mbox separator date. It makes the file look like a UNIX mailbox while letting tools such as file(1) tell that it came from format-patch and is not a real mailbox. The real author date is in the Date: header.
Follow-up: How can you hide the commit hash on that line, for example to get reproducible output? Pass --zero-commit, which writes an all-zero hash in place of the real one.
git amgit send-emailgit applygit range-diffgit request-pullgit notesgit diffgitrevisions