Skip to content

fix(release): fetch the one tag, not every tag - #194

Merged
kevintseng merged 1 commit into
mainfrom
fix/finish-release-narrow-tag-fetch
Aug 23, 2026
Merged

fix(release): fetch the one tag, not every tag#194
kevintseng merged 1 commit into
mainfrom
fix/finish-release-narrow-tag-fetch

Conversation

@kevintseng

@kevintseng kevintseng commented Aug 23, 2026

Copy link
Copy Markdown
Contributor

release:finish ended by running git fetch --tags origin to bring the tag it had just created into the local checkout. That form asks for every tag origin has and exits non-zero if any single one cannot be written — so an unrelated divergence anywhere in the repository's history makes the step look failed.

The divergence, measured across all 73 tags

range vs origin
v2.2.0v2.9.2 agree
v2.10.1v4.1.7 (25 tags) + benchmark/longmemeval-public-r1 diverge — 26 refs
v4.2.0v4.6.2 agree

The cause is measured, not inferred. origin's v4.1.7 tree lacks four internal documents that the local v4.1.7 tree still carries — that is a history rewrite. (Their names are deliberately not repeated in the diff: putting them back into a public file would undo part of what the rewrite was for.) Those refs will not converge, so every release has printed could not `git fetch --tags origin` immediately after that same fetch wrote the new tag successfully — visible in the v4.6.2 release output, where * [new tag] v4.6.2 -> v4.6.2 sits in the middle of 26 ! [rejected] lines.

Measured

Same checkout, same moment, during the v4.6.2 release:

git fetch --tags origin                              → exit=1, 26 rejected
git fetch origin refs/tags/v4.6.2:refs/tags/v4.6.2   → exit=0, * [new tag] v4.6.2

The narrow form was proven by deleting the local v4.6.2 and fetching it back: same sha 58294705. git show-ref --tags afterwards was byte-identical to a capture taken before the experiment.

What is deliberately unchanged

The line after the fetch, which asks git tag --list whether the tag is actually present rather than treating the fetch's own report as the answer. That is why this false alarm was never load-bearing — the script verified the thing, not the proxy.

Also not --tags --force: forcing would silently rewrite 26 local refs as a side effect of cutting a release, which is a larger action than the one being asked for.

The pin

A sixth wiring assertion in tests/release-preconditions.test.ts, alongside the five that were already there for the stated reason that this script's happy path cannot be run without cutting a real release.

It is scoped to the fetch: git ls-remote --tags origin earlier in the same file is a different call with the same flag and is correct — listing every remote tag is exactly what the precondition check needs. The first version of this test banned the string outright and went red on it; that failure is why the assertion is scoped.

Break-tested both ways, source restored and confirmed by sha256:

delete the refspec         → 1 failed | 30 passed   (positive half)
re-insert --tags on fetch  → 1 failed | 30 passed   (negative half)

The negative half is broken by inserting the forbidden token, not by deleting the refspec — a not.toMatch also passes when the thing it forbids has become impossible to express.

Verification

npx vitest run tests/release-preconditions.test.ts   exit=0  — 31 passed
npm run lint                                         exit=0
npm run typecheck                                    exit=0
npm run verify:release                               exit=0  (C1/C3/C4/C5/C6/C7 all new=0)

`release:finish` ended by running `git fetch --tags origin` to bring the
tag it had just created into the local checkout. That form asks for every
tag `origin` has and exits non-zero if any single one cannot be written,
so an unrelated divergence anywhere in the repository's history makes the
step look failed.

This repository has 26 of them. Measured across all 73 tags: the version
tags from v2.10.1 through v4.1.7, plus benchmark/longmemeval-public-r1,
point at different objects locally than on origin, while everything from
v4.2.0 onward agrees. The cause is measured too, not inferred — origin's
v4.1.7 tree lacks four internal documents the local v4.1.7 tree still
carries, which is a history rewrite. Those refs will not converge, so
every release has printed "could not `git fetch --tags origin`"
immediately after that same fetch wrote the new tag successfully.

Measured on the v4.6.2 release, same checkout, same moment:

  git fetch --tags origin                            exit=1, 26 rejected
  git fetch origin refs/tags/v4.6.2:refs/tags/v4.6.2 exit=0, * [new tag]

Restored afterwards and confirmed with `git show-ref --tags` diffed
against a pre-experiment capture — identical.

Not `--tags --force`: that would silently rewrite 26 local refs as a side
effect of cutting a release, which is a larger action than the one being
asked for.

The line that follows is unchanged and was already right: it asks whether
the tag is in fact present rather than treating the fetch's own report as
the answer. That is why the false alarm was never load-bearing — but a
warning that fires on every release is a warning nobody reads.

Pinned by a sixth wiring assertion in tests/release-preconditions.test.ts,
scoped to the fetch because `git ls-remote --tags` is a different call with
the same flag and is correct. Break-tested both ways: deleting the refspec
goes red, and re-inserting `--tags` on the fetch goes red.
@kevintseng
kevintseng force-pushed the fix/finish-release-narrow-tag-fetch branch from b40c3b4 to e55b4a0 Compare August 23, 2026 12:59
@kevintseng
kevintseng merged commit 2e2ed20 into main Aug 23, 2026
13 checks passed
@kevintseng
kevintseng deleted the fix/finish-release-narrow-tag-fetch branch August 23, 2026 13:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant