skip to content

In Git, what does git format-patch produce, and how does a maintainer apply it?

level: middleimportance: must knowfreq 45%

answer

  1. one file per commit, not one diff
  2. it looks like an email
  3. author identity survives the round trip
  4. mbox with From:, Date:, Subject:
  5. format-patch out, git am back in

basics

~20 s

git format-patch writes one mbox-formatted file per commit, containing the message plus the diff and author metadata. A maintainer replays them with git am, which recreates the commits with their original author, date and message rather than just applying a diff.

solid answer

~40 s

`git format-patch origin/main..HEAD` turns each commit in that range into a numbered file like `0001-parser-reject-empty-headers.patch`. Each file is a fake email: `From:` the commit author, `Date:` the author date, a `Subject:` of `[PATCH n/m] <summary>`, the body, then the diff. `--cover-letter` adds a `0000-cover-letter.patch` summarising the series, and `git send-email` mails the files to a list. On the receiving side `git am` reads that mbox and commits each patch, restoring the original author and author date while making the applier the committer. That is the key difference from `git apply`, which only touches the working tree and index and leaves you to write your own commit. If the base has moved, `git am -3` can fall back to a three-way merge using the blob hashes recorded in the patch.

code

bash · 9 lines
bash
# contributor
git format-patch origin/main..HEAD --cover-letter -o /tmp/series --base=auto
# /tmp/series/0000-cover-letter.patch
# /tmp/series/0001-parser-reject-empty-header-names.patch
git send-email [email protected] /tmp/series/*.patch

# maintainer
git am /tmp/series/000*.patch
git log --format='%h %an <%ae> committed by %cn' -2

go deeper

for a junior

Recall the pairing: git format-patch turns commits into email-like files, git am turns them back into commits. Knowing that the message and author travel with the file is enough at this level.

for a middle

Explain the mbox structure — From, Date, Subject with the PATCH prefix, then the diff — and the crucial contrast with git apply, which changes files but creates no commit and keeps no authorship.

for a senior

Demonstrate operating the flow: generating a numbered series with a cover letter, and recovering when am stops mid-series using -3, --continue, --skip and --abort without losing the rest of the patches.

for a principal

Be able to argue when an email-patch workflow still earns its keep — offline review, no account required, archives as the record — against the coordination cost compared with pushing branches to a shared host.

## Why this exists Many long-lived projects — the Linux kernel and Git itself among them — accept contributions as email rather than as pushed branches. The contributor never needs write access anywhere, and review happens in plain text. `git format-patch` and `git am` are the two halves of that pipeline: one turns commits into transportable text, the other turns that text back into commits. ## What format-patch writes `git format-patch <since>..<until>` (commonly `git format-patch origin/main..HEAD`, or `git format-patch -1` for just the tip commit) creates one file per commit in the current directory, or in the directory given by `-o <dir>`. The names are numbered and derived from the subject line: `0001-...patch`, `0002-...patch`. Each file is formatted as a single-message mbox: - `From <hash> Mon Sep 17 00:00:00 2001` — a fixed magic first line that marks the mbox. - `From:` the **author** of the commit, not whoever ran the command. - `Date:` the author date. - `Subject: [PATCH 2/5] <first line of the message>` — the numbering comes from the series size. - The rest of the commit message as the body, then `---`, a diffstat, and the diff itself, ending with the Git version as a signature line. The diff hunks carry `index <old>..<new> <mode>` lines that name the abbreviated blob hashes on both sides. Those hashes are what makes a later three-way apply possible. ## Useful options `--cover-letter` produces an extra `0000-cover-letter.patch` with a placeholder subject and the series diffstat — the place to explain the *why* of the whole series. `-v2` (a reroll count) changes the subject prefix to `[PATCH v2 n/m]` so reviewers can tell revisions apart. `--base=<commit>` records a `base-commit:` trailer so the recipient knows exactly what the series applies to. `--thread` arranges message headers so the series threads in a mail client. `git send-email 0*.patch [email protected]` sends them using the SMTP settings under `sendemail.*`. ## What git am does `git am <files-or-mbox>` walks the messages in order and, for each one: parses the headers to recover author name, email and author date; parses the subject, stripping the `[PATCH n/m]` prefix, to recover the summary line; applies the diff to the index and working tree; and commits. The resulting commit has the **original author and author date**, while the *committer* is whoever ran `am` and the commit date is now. That asymmetry is exactly why author and committer are separate fields in Git's commit object. Because `am` recreates commits, a maintainer can apply a ten-patch series and get ten commits with the contributor's authorship intact, which is what shows up in `git log --format='%an %cn'` and in per-author statistics. ## am versus apply `git apply` is the lower-level tool: it takes a diff, changes the working tree (and the index with `--index`), and stops. No commit, no message, no authorship. `git apply --check` tests whether a patch would apply at all without touching anything. Use `apply` for a raw diff someone pasted; use `am` for anything produced by `format-patch`, because only `am` carries the metadata. ## When it does not apply cleanly If the tree has moved on, `am` refuses with a message saying the patch does not apply and stops mid-series. `git am -3` (`--3way`) retries as a three-way merge using the `index` lines: if the pre-image blobs are present in the repository, Git can reconstruct the original context and merge, possibly leaving conflict markers for you to resolve, after which `git am --continue` proceeds. `git am --skip` drops the current patch, and `git am --abort` restores the branch to where it started. `git am --show-current-patch=diff` prints the patch that is stuck so you can inspect it. ## Interview framing The point of the question is rarely the flags. It is whether you understand that a Git commit is more than a diff — it carries an author identity, an author date and a message — and that `format-patch`/`am` is the pair that preserves all of that across a transport with no network connection to the original repository.

  • After git am, why is the author different from the committer?
    A commit stores both. `git am` restores the author name, email and author date from the patch headers, but the person running the command becomes the committer with a fresh commit date. That is how a maintainer can land someone else's work while history still credits the original author.
  • When would you use git apply instead of git am?
    When you have a bare diff with no message or authorship — a paste, a `git diff` output, or a patch you want to inspect and reshape before committing. `git apply --check` verifies it would apply, and `--index` stages the result. You then write your own commit.
  • What does the --cover-letter option add to a series?
    An extra file numbered 0000 containing a placeholder subject and the diffstat for the whole range. You edit it to explain the motivation, the approach and anything reviewers should look at first; individual patch messages then stay focused on their own change.
  • How does the recipient know which base the series applies to?
    Pass `--base=<commit>` to `git format-patch` and it records a `base-commit:` trailer naming the exact commit the series was generated on top of. Reviewers can then check out that commit and apply the series reproducibly rather than guessing.

saying these in an interview costs you the question

  • Says format-patch output is just a diff file
  • Thinks git am and git apply do the same thing
  • Believes the maintainer becomes the author after git am
  • Assumes patches must be applied by hand with an editor
  • Claims format-patch only works one commit at a time

context