skip to content

A maintainer says your emailed Git patch series no longer applies — how do you resend it?

level: seniorimportance: should knowfreq 28%

answer

  1. the base moved, not the patch
  2. reviewers should not reread everything
  3. bump the version in the subject
  4. diff of diffs between rounds
  5. format-patch -v2 with --range-diff

basics

~20 s

Rebase your topic branch onto the current upstream tip, re-run the tests, then regenerate the series with git format-patch using a bumped version prefix and a range-diff against the previous round, and reply in the same mail thread.

solid answer

~40 s

"Does not apply" almost always means the base moved under you, not that the patch is malformed. Fetch upstream, rebase your topic branch onto the new tip, resolve whatever conflicts appear, and re-run the tests at every commit. Then regenerate with `git format-patch -v2 --cover-letter --base=auto --range-diff=<old-tip> origin/main..HEAD`: `-v2` marks the subjects `[PATCH v2 n/m]`, `--base` records the exact commit it applies to, and `--range-diff` embeds a diff-of-diffs so reviewers can see only what changed since v1. Send it with `git send-email --in-reply-to=<message-id>` so it threads under the original discussion. On the maintainer's side, `git am -3` can often rescue a stale patch by three-way merging from the blob hashes in the `index` lines, and `git am --show-current-patch=diff`, `--continue`, `--skip` and `--abort` control a stuck run.

code

bash · 7 lines
bash
git fetch origin
git rebase origin/main            # move the series onto the current tip
git rebase -i --exec 'make test' origin/main   # verify every commit

git format-patch -v2 --cover-letter --base=auto \
    --range-diff=@{u}@{1} origin/main..HEAD -o /tmp/v2
git send-email --in-reply-to='<[email protected]>' /tmp/v2/*.patch

go deeper

for a junior

Know that a patch is a diff against a specific base, so an advancing upstream branch is the usual reason it stops applying, and that the fix is to rebase and export the series again.

for a middle

Explain the reroll mechanics: rebase onto the current tip, retest, regenerate with a bumped version prefix, and what git am -3 is doing with the blob hashes recorded in the patch.

for a senior

Show you optimise for the reviewer: a range-diff against the previous round, a changelog in the cover letter, fixes folded into the right commits, and a threaded resend rather than a fresh submission.

for a principal

Be ready to talk about what your project asks of contributors across rerolls — version discipline, recorded base commits, how long a series may sit before the base drift becomes the maintainer's problem rather than the contributor's.

## Diagnose before you regenerate A patch is a diff against a specific pre-image. `git am` reports that it does not apply when the context lines it expects are no longer in the file. The overwhelmingly common cause is simply time: the upstream branch advanced, someone else touched the same region, or a file moved. Less common causes are a mail client that mangled whitespace or wrapped long lines, and a patch generated against a different branch than the maintainer's. The first thing to establish is *which base* you generated against. If you sent the series with `--base=auto`, the trailer names it and the maintainer can reproduce the failure exactly. Without it, everyone is guessing. ## The contributor's fix: rebase and reroll The repair is to move the series to the base the maintainer actually has. 1. Fetch the upstream branch so you have its current tip. 2. Rebase your topic branch onto that tip and resolve conflicts. This is where you decide whether the upstream change invalidates your approach, not just your context lines — a patch that applies but is now wrong is worse than one that fails. 3. Re-verify the whole series, not the tip: `git rebase -i --exec '<build and test command>' <upstream>` runs the check after each commit. 4. Regenerate: `git format-patch -v2 --cover-letter --base=auto <upstream>..HEAD`. `-v<n>` is the reroll count. It changes the subject to `[PATCH v2 1/4]` and names the files with a `v2-` prefix, so reviewers and archives can distinguish rounds. Keep bumping it for each resend; a v3 that is still labelled v1 wastes everyone's time. ## Showing what changed between rounds A reviewer who read v1 does not want to read v2 from scratch. `git format-patch --range-diff=<previous-tip>` embeds the output of `git range-diff` in the cover letter: a comparison of the two *series*, matching commits up by similarity and showing, per commit, how its diff changed. You can also run `git range-diff v1-tip...v2-tip` standalone to inspect it before sending. This is the single most appreciated courtesy in an email workflow — it turns "reread four patches" into "read eight changed lines". In the cover letter, add a short changelog: what you changed since v1 and which review comment each change answers. Fold those changes into the commits they belong to; do not append "address review comments" commits. ## Threading the resend Send the new round as a reply to the original thread with `git send-email --in-reply-to=<message-id-of-v1-cover-letter>`, and use `--to`/`--cc` to keep the original reviewers. Mailing-list archives and the maintainer's own tooling both key off threading; an unthreaded v2 reads as a new, unreviewed submission. ## The maintainer's side of the same failure When `git am` stops, the maintainer has options before asking for a reroll. `git am -3` (or `--3way`) retries as a three-way merge: `format-patch` records `index <old>..<new>` lines with the abbreviated blob hashes of both sides, so if the pre-image blob exists in the repository, Git can reconstruct the original file state and perform a real merge, producing conflict markers to resolve rather than a flat refusal. Setting `am.threeWay` makes that the default. If the blobs are unknown — typically because the patch was generated from work never published — three-way is impossible and only a reroll helps. While an `am` is stopped, `git am --show-current-patch=diff` prints the offending patch, `git am --continue` resumes after you stage a resolution, `git am --skip` drops just this patch and moves to the next, and `git am --abort` returns the branch to its pre-`am` state. For a whitespace-mangled patch, `git apply --check` and `git apply --whitespace=fix` help diagnose whether the problem is context or corruption. ## What good judgment looks like here Strong candidates do three things: they treat "does not apply" as a base-drift problem and go and *look* at the upstream change rather than blindly re-exporting; they re-run the tests after the rebase because a clean textual apply is not a correct merge; and they make the reviewer's second pass cheap with a version bump, a range-diff and a changelog. Weak candidates force the patch through with a manual edit of the `.patch` file, which silently desynchronises the patch from their local commits.

  • What does git am -3 need in order to work, and when does it fail?
    It needs the pre-image blobs named by the `index` lines in the patch to exist in the receiving repository. If they do, Git reconstructs the original file content and does a real three-way merge, possibly with conflicts. If the patch was made from unpublished objects the maintainer has never seen, there is nothing to merge from and the apply still fails.
  • Why send the new round in the same mail thread rather than as a fresh message?
    Threading keeps the review history together: the archive, the maintainer's patch tracking and other reviewers all follow the thread. An unthreaded resend looks like an unreviewed new submission and often gets triaged as one, losing the context of everything already discussed.
  • Should you ever hand-edit a .patch file to make it apply?
    Almost never. The file would then no longer match your local commits, so your next regeneration silently reintroduces the problem, and nothing you tested corresponds to what you sent. Fix the branch, retest it, and re-export.

saying these in an interview costs you the question

  • Hand-edits the .patch file to force it through
  • Resends without bumping the version prefix
  • Assumes a clean apply means the change is still correct
  • Appends address-review-comments commits instead of rerolling
  • Thinks git am -3 works without the referenced blobs

context