0.7.0 · Entire
0.7.0
d9c06ff→main
Sessions
d7d18da5063aView transcript
Changes
[Unreleased]
[0.7.0] - 2026-06-16
Added
- Typed push-rejection errors on the public API.
Sync/Replicatenow report a*RefRejectedError(carrying the rejectedRefand the raw serverReason) for per-ref receive-packngstatuses, reachable witherrors.As. Rejections that are unambiguous concurrent target-ref moves — entire-server's compare-and-swap rejection (remote ref has changed) and git's--force-with-leaselease miss (stale info) — additionally satisfyerrors.Is(err, ErrTargetRefMoved). This lets embedders distinguish a benign racing concurrent push (retryable) from a genuine push failure without substring-matching the free-form error message. Ambiguous markers (non-fast-forward/fetch first) are deliberately excluded from the move classification so a real "needs--force" rejection is not masked. TheForceWithLeaselease-failure escalation (raised even underBestEffort) also satisfieserrors.Is(err, ErrTargetRefMoved), though it is not itself a*RefRejectedError— prefererrors.Isovererrors.Aswhen you only need the cause. The error message and the underlying value-typedpackp.CommandStatusErrare preserved unchanged (reach it with a valueerrors.Astarget), so existing checks keep working. - Typed push-rejection errors on the public API.
Sync/Replicatenow report a*RefRejectedError(carrying the rejectedRefand the raw serverReason) for per-ref receive-packngstatuses, reachable witherrors.As. Rejections that are unambiguous concurrent target-ref moves — entire-server's compare-and-swap rejection (remote ref has changed) and git's--force-with-leaselease miss (stale info) — additionally satisfyerrors.Is(err, ErrTargetRefMoved). This lets embedders distinguish a benign racing concurrent push (retryable) from a genuine push failure without substring-matching the free-form error message. Ambiguous markers (non-fast-forward/fetch first) are deliberately excluded from the move classification so a real "needs--force" rejection is not masked. TheForceWithLeaselease-failure escalation (raised even underBestEffort) also satisfieserrors.Is(err, ErrTargetRefMoved), though it is not itself a*RefRejectedError— prefererrors.Isovererrors.Aswhen you only need the cause. The error message and the underlying value-typedpackp.CommandStatusErrare preserved unchanged (reach it with a valueerrors.Astarget), so existing checks keep working (#71)
Fixed
- Concurrent target-ref rejections are now actually classified —
errors.Is(err, ErrTargetRefMoved)anderrors.As(err, *RefRejectedError)match on the real push path. go-git returnspackp.CommandStatusErrby value fromReportStatus.Error(), butasRefRejectedError/annotateLeaseFailureused a*packp.CommandStatusErr(pointer)errors.Astarget, which never matches a value in the chain — so every live receive-packngstatus passed through unclassified andErrTargetRefMovedwas never reported. Both now use a value target, and a regression test drives a realReportStatus.Error()end to end so a pointer-vs-value relapse fails CI. (Bug in the unreleased typed-rejection feature above — never shipped in a tagged release.) - Concurrent target-ref rejections are now actually classified —
errors.Is(err, ErrTargetRefMoved)anderrors.As(err, *RefRejectedError)match on the real push path. go-git returnspackp.CommandStatusErrby value fromReportStatus.Error(), butasRefRejectedError/annotateLeaseFailureused a*packp.CommandStatusErr(pointer)errors.Astarget, which never matches a value in the chain — so every live receive-packngstatus passed through unclassified andErrTargetRefMovedwas never reported. Both now use a value target, and a regression test drives a realReportStatus.Error()end to end so a pointer-vs-value relapse fails CI. (Bug in the typed-rejection feature above — never shipped in a tagged release.) (#73) - Batched bootstrap no longer dies when finalizing a subsumed branch against a receive-pack that requires a pack for every non-delete command. The pack-less ref-create sent only command pkt-lines, which strict servers rejected with
unpack error: ... read packfile header: EOF(observed mid-run mirroring to entiredb prod, leaving the target half-populated); git-sync now sends a valid empty pack with such creates (#74) - Large or slow bootstrap relays that outlast the target's
git-receive-packdeadline (GitHub HTTP 408, or gateway 504) now fall back to batched bootstrap with checkpoint subdivision instead of hard-failing. Previously only 413 body-limit rejections triggered batching, so relaying a large repo over a slow source link — where the upstream read rate throttles the downstream write past GitHub's receive-pack window — failed with a barehttp 408and no remediation. Timeouts are classified distinctly from size rejections, the auto-batch notice names the cause, and a one-shot failure with no batched fallback (source lacking protocol-v2 fetch-filter support) now carries actionable guidance (#75)