You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The leading + forces the update. A clone that ran doctor --fix therefore overwrites its local refs/notes/commitlore with the remote's on every git fetch, whether or not the two have diverged.
A note is not a cache. The note is the record. Overwriting one destroys a record rather than invalidating a derived file, and nothing reports that it happened.
Reproduction
Two clones of one remote, both with the refspec doctor --fix writes. Bob publishes a record; Alice writes one of her own on a different commit and has not pushed yet. Alice then runs nothing but git fetch:
alice note before fetch: Warn: alice unpublished
alice note after fetch: GONE
bob's note now visible : Warn: from bob
Alice's record is gone from the ref. No prompt, no warning, exit 0.
This needs no unusual sequence — write a record, pull before pushing. backfill, squash inheritance, and any capture that lands in the mirror all produce exactly this state.
Why forced was chosen, and why it is still wrong
A forced refspec makes remote notes appear automatically, which is the behaviour the mirror wants. Unforced gets the same result in the common case: a fast-forward still applies without ceremony. The only time the two differ is when the local ref has commits the remote does not — which is precisely the case where forcing destroys something.
So the cost of unforcing is a visible ! [rejected] on a diverged fetch, and the benefit is that a record is never silently lost. That trade is not close.
Fix
NOTES_REFSPEC drops the +.
doctor detects an already-configured forced notes refspec and reports it; --fix rewrites it.
So any code fetching the mirror to a scratch ref must pass --refmap= to isolate itself, or the configured refspec will move the working ref underneath it.
The defect
src/core/notes.ts:The leading
+forces the update. A clone that randoctor --fixtherefore overwrites its localrefs/notes/commitlorewith the remote's on everygit fetch, whether or not the two have diverged.A note is not a cache. The note is the record. Overwriting one destroys a record rather than invalidating a derived file, and nothing reports that it happened.
Reproduction
Two clones of one remote, both with the refspec
doctor --fixwrites. Bob publishes a record; Alice writes one of her own on a different commit and has not pushed yet. Alice then runs nothing butgit fetch:Alice's record is gone from the ref. No prompt, no warning, exit 0.
This needs no unusual sequence — write a record, pull before pushing.
backfill, squash inheritance, and any capture that lands in the mirror all produce exactly this state.Why forced was chosen, and why it is still wrong
A forced refspec makes remote notes appear automatically, which is the behaviour the mirror wants. Unforced gets the same result in the common case: a fast-forward still applies without ceremony. The only time the two differ is when the local ref has commits the remote does not — which is precisely the case where forcing destroys something.
So the cost of unforcing is a visible
! [rejected]on a diverged fetch, and the benefit is that a record is never silently lost. That trade is not close.Fix
NOTES_REFSPECdrops the+.doctordetects an already-configured forced notes refspec and reports it;--fixrewrites it.commitlore sync(The notes mirror is written locally and never leaves the machine, so a teammate's clone cannot see a record it holds #416) is for, anddoctorshould say so rather than leaving! [rejected]unexplained.Note for #416
git fetch <remote> <refspec>applies the configured refspecs in addition to the one on the command line — measured, not assumed:So any code fetching the mirror to a scratch ref must pass
--refmap=to isolate itself, or the configured refspec will move the working ref underneath it.