|
| 1 | +--- |
| 2 | +date: 2026-08-06 |
| 3 | +repo: pnpm/pnpm |
| 4 | +size: L |
| 5 | +title: "Git resolution, update fixes, and faster installs" |
| 6 | +excerpt: "Major git spec semantics changed, with several perf wins and bug fixes across lockfile updates, resolver behavior, and global interactive update flows." |
| 7 | +commits: 16 |
| 8 | +authors: [zkochan, Ayush442842q, junhaoliao, xianjianlf2, felipeplets, m2na7] |
| 9 | +commit_authors: {"7490284": Ayush442842q, "8ae2e28": Ayush442842q, "14a890d": zkochan, "ffc51c8": zkochan, "ea90e2d": zkochan, "afe0aa9": junhaoliao, "dd0e058": zkochan, "acb28ad": xianjianlf2, "25437e2": zkochan, "f31c7ca": zkochan, "ecd540b": Ayush442842q, "3b85f07": m2na7, "2d10d1f": zkochan, "cba0df1": zkochan, "74577d7": zkochan} |
| 10 | +--- |
| 11 | + |
| 12 | +### **Hosted git specs now resolve via canonical HTTPS** (14a890d) |
| 13 | +GitHub/GitLab/Bitbucket shorthand and URL forms are now treated as repository identities, not transport hints. pnpm records canonical HTTPS or archive tarball resolutions instead of inferring SSH, which avoids lockfiles that only work on the machine that created them. |
| 14 | + |
| 15 | +### **Git resolver now falls back to HTTPS on CI-friendly probes** (8ae2e28) |
| 16 | +A transient SSH-vs-HTTPS probe race could record an SSH URL for a repo that never asked for it, breaking installs on keyless CI runners. The resolver now retries flaky HEAD checks and prefers anonymous HTTPS probing before SSH inference. |
| 17 | + |
| 18 | +### **Patch-only installs no longer force a full re-resolve** (ffc51c8) |
| 19 | +Changes to `patchedDependencies` now rewrite the affected lockfile entries and reuse the already-resolved graph instead of resolving everything again. That makes patch edits much faster, while still falling back to full resolution when a patch touches peer-reachable packages. |
| 20 | + |
| 21 | +### **Ignored optional dependency additions can skip resolution** (f31c7ca) |
| 22 | +Adding new `ignoredOptionalDependencies` patterns can now prune unreachable optionals and their snapshots without a fresh dependency resolution. This speeds up installs when the new ignore rules are monotonic and the lockfile already proves nothing else changes. |
| 23 | + |
| 24 | +### **Inert lockfile setting changes are recorded without re-resolving** (dd0e058) |
| 25 | +Several settings that only matter when peers or workspace links are actually present now update the lockfile in place when they cannot affect the graph. That avoids unnecessary resolution work for settings like `dedupePeers` or `injectWorkspacePackages` on unaffected projects. |
| 26 | + |
| 27 | +### **`pnpm version -r --json` now stays machine-readable** (ecd540b) |
| 28 | +The no-pending-changes path now emits an empty JSON array instead of a human-readable sentence. Pacquet also aligns its applied-release JSON shape with the TypeScript CLI, fixing broken automation around `--json` output. |
| 29 | + |
| 30 | +### **`pnpm update --no-save` respects the kept manifest range** (3b85f07) |
| 31 | +Version bumps without saving now refuse to record versions outside the manifest’s retained range, avoiding lockfiles that contradict `package.json`. The update flow now warns on out-of-range requests and keeps `--latest` bounded by the actual specifier. |
| 32 | + |
| 33 | +### **Interactive global update can select whole package groups** (25437e2) |
| 34 | +`pnpm update --global --interactive` now lets users pick global package groups as atomic units instead of failing as unsupported. The selection is wired through both the Rust and TypeScript paths so only the chosen group hashes are updated. |
| 35 | + |
| 36 | +### **npm held-back warnings now account for release-age filtering** (acb28ad) |
| 37 | +The “held back” warning no longer blames manifests when `minimumReleaseAge` is what blocked a newer version. The baseline pick now applies the same publish-age cutoff as the real resolver, preventing misleading override advice. |
| 38 | + |
| 39 | +### **Empty version ranges are treated as `*`** (f2fa9c) |
| 40 | +An omitted semver range now resolves like “any version” instead of being misclassified as a dist-tag. That fixes installs for packages that publish empty ranges, which previously failed because the resolver looked for an impossible tag. |
| 41 | + |
| 42 | +### **`pnpm version -r --dry-run` now matches the applied plan** (7490284) |
| 43 | +The release preview path is now covered and pinned to the same plan as a real run, so dry-run output can’t drift from the actual version bump behavior. That closes a correctness gap in release tooling. |
| 44 | + |
| 45 | +### **`allowUnusedPatches` is exposed through the NAPI installer API** (cba0df1) |
| 46 | +Embedder-driven installs can now opt into allowing unused patches, matching the CLI’s workspace setting. The flag is threaded through the NAPI config path into the fresh-lockfile verification flow. |
| 47 | + |
| 48 | +### **Global virtual store slot materialization is deduplicated** (74577d7) |
| 49 | +The deps restorer now materializes each shared global-virtual-store slot only once, avoiding races when peer variants collapse to the same hashed directory. This fixes concurrent import failures for mutable `file:` sources that assumed exclusive ownership of a slot. |
| 50 | + |
| 51 | +### Other misc changes |
| 52 | +- Memory reduction for registry metadata caching by reading mirror-file spans on demand (ea90e2d) |
| 53 | +- Cross-realm missing `.pnpmfile` error handling fix (afe0aa9) |
| 54 | +- Security docs updated to state the untrusted-repository trust boundary (2d10d1f) |
| 55 | +- Various test coverage, lockfile, and CI/build updates across resolver, versioning, and update flows |
0 commit comments