From d9c06ff4bad0a402d0bcc08c0c3fe985149cfe52 Mon Sep 17 00:00:00 2001 From: Stefan Haubold Date: Tue, 16 Jun 2026 19:29:39 +0200 Subject: [PATCH] 0.7.0 Entire-Checkpoint: d7d18da5063a --- CHANGELOG.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index af99d786..a150decc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,15 +5,17 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/), and this project adheres to [Semantic Versioning](https://semver.org/). -## [Unreleased] +## [0.7.0] - 2026-06-16 ### Added -- Typed push-rejection errors on the public API. `Sync`/`Replicate` now report a `*RefRejectedError` (carrying the rejected `Ref` and the raw server `Reason`) for per-ref receive-pack `ng` statuses, reachable with `errors.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-lease` lease miss (`stale info`) — additionally satisfy `errors.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. The `ForceWithLease` lease-failure escalation (raised even under `BestEffort`) also satisfies `errors.Is(err, ErrTargetRefMoved)`, though it is not itself a `*RefRejectedError` — prefer `errors.Is` over `errors.As` when you only need the cause. The error message and the underlying value-typed `packp.CommandStatusErr` are preserved unchanged (reach it with a value `errors.As` target), so existing checks keep working. +- Typed push-rejection errors on the public API. `Sync`/`Replicate` now report a `*RefRejectedError` (carrying the rejected `Ref` and the raw server `Reason`) for per-ref receive-pack `ng` statuses, reachable with `errors.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-lease` lease miss (`stale info`) — additionally satisfy `errors.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. The `ForceWithLease` lease-failure escalation (raised even under `BestEffort`) also satisfies `errors.Is(err, ErrTargetRefMoved)`, though it is not itself a `*RefRejectedError` — prefer `errors.Is` over `errors.As` when you only need the cause. The error message and the underlying value-typed `packp.CommandStatusErr` are preserved unchanged (reach it with a value `errors.As` target), so existing checks keep working ([#71](https://github.com/entireio/git-sync/pull/71)) ### Fixed -- Concurrent target-ref rejections are now actually classified — `errors.Is(err, ErrTargetRefMoved)` and `errors.As(err, *RefRejectedError)` match on the real push path. go-git returns `packp.CommandStatusErr` **by value** from `ReportStatus.Error()`, but `asRefRejectedError` / `annotateLeaseFailure` used a `*packp.CommandStatusErr` (pointer) `errors.As` target, which never matches a value in the chain — so every live receive-pack `ng` status passed through unclassified and `ErrTargetRefMoved` was never reported. Both now use a value target, and a regression test drives a real `ReportStatus.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)` and `errors.As(err, *RefRejectedError)` match on the real push path. go-git returns `packp.CommandStatusErr` **by value** from `ReportStatus.Error()`, but `asRefRejectedError` / `annotateLeaseFailure` used a `*packp.CommandStatusErr` (pointer) `errors.As` target, which never matches a value in the chain — so every live receive-pack `ng` status passed through unclassified and `ErrTargetRefMoved` was never reported. Both now use a value target, and a regression test drives a real `ReportStatus.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](https://github.com/entireio/git-sync/pull/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](https://github.com/entireio/git-sync/pull/74)) +- Large or slow bootstrap relays that outlast the target's `git-receive-pack` deadline (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 bare `http 408` and 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](https://github.com/entireio/git-sync/pull/75)) ## [0.6.0] - 2026-06-03