SIGN IN SIGN UP

fix(patch): keep the update marker on a no-op commit so a retry finalizes (#9567)

A conflicted `npm patch update` leaves an edit dir and a
`.npm-patch-update.json` marker that the finalizing `npm patch commit`
reads to finish the update — a metadata-only finalize that drops the
renamed-from selector and tolerates the new version not being installed
yet.

`commit()` deleted that marker before checking whether the edit dir
produced a diff. So a first commit that did no net work — the conflict
resolved to the new version verbatim, giving "nothing to commit" —
consumed the marker. A corrected retry then found none, ran a full
reify, and failed `EPATCHUNUSED` (the rebased-to version isn't
installed), leaving both the old and new selector in the manifest. The
same loss happened on any non-finalizing path (e.g. the `EPATCHUNSAFE`
throw).

## Fix

The marker was deleted eagerly only to keep it out of the generated
patch. Instead, keep it and teach `diffDirs` to skip it:

- `diffDirs(originalDir, editedDir, ignore = new Set())` skips a set of
root-relative filenames, like it already skips the root `package.json`.
- `commit()` no longer deletes the marker — it reads/parses it (still
throwing `EPATCHBADMARKER` on bad JSON before any diff), and passes `new
Set([UPDATE_MARKER])` to `diffDirs`.

The marker now survives any non-finalizing path, so a corrected retry
still finalizes. A successful commit removes the whole edit dir (unless
`--keep-edit-dir`), so nothing lingers.

## References

Fixes #9566
Follow-up to #9439 (native dependency patching).
M
Manzoor Wani committed
5ddf6ccce5255d35da217d3e7342dde2bcb478d1
Parent: 1db885c
Committed by GitHub <noreply@github.com> on 6/18/2026, 5:26:42 PM