Wire max/batch pack byte flags into sync and replicate · Entire

Wire max/batch pack byte flags into sync and replicate

6a219a1→main·

Soph·3mo ago·4 files·+54 added/-1 removed

Replicate against a fresh target for a repo the size of linux currently fails with "decode report-status: invalid pkt-len found: short pkt-line 4"
because the receive-pack POST body hits a server limit (or times out)
and the target closes the connection before writing a report-status.
The fix is batching, which the bootstrap strategy already supports and
which replicate's bootstrap-fallback already plumbs to the strategy via
Config.BatchMaxPackBytes -- but the flags were only registered on the
bootstrap subcommand. Replicate and sync silently ignored them.

Changes:

Typical usage for a large initial replicate push:

git-sync replicate \
 --batch-max-pack-bytes 268435456 \
 --max-pack-bytes 10737418240 \
...  

splits the push into ~256 MiB batches, each of which the receive-pack server processes and acknowledges before the next starts.

Co-Authored-By: Claude Opus 4.6 (1M context) noreply@anthropic.com

Sessions

08a1fb563aa3View transcript

Changes

4

16 unmodified lines

Changed (stable API, breaking)

MCHANGELOG.md+7
82 unmodified lines
1716 unmodified lines

func TestRun_IntegrationReplicateBootstrapBatchesWhenConfigured(t *testing.T) { // Large bootstrap-relay pushes can overwhelm targets with body-size // limits (e.g. go-git-based receive-pack on raft-backed storage). // Replicate falls back through the bootstrap strategy for empty targets, // and must honor BatchMaxPackBytes so callers can split a huge push // into tractable receive-pack POSTs. Without this plumbing the replicate // CLI flag would be silently ignored. sourceRepo, sourceFS := newSourceRepo(t) makeLargeCommits(t, sourceRepo, sourceFS, 20, 200_000)

targetRepo, err := git.Init(memory.NewStorage()) if err != nil { t.Fatalf("init target repo: %v", err) }

sourceServer := newSmartHTTPRepoServerV2(t, sourceRepo) targetServer := newSmartHTTPRepoServer(t, targetRepo) targetServer.receivePackThinCap = true defer sourceServer.Close() defer targetServer.Close()

result, err := Run(context.Background(), Config{ Source: Endpoint{URL: sourceServer.RepoURL()}, Target: Endpoint{URL: targetServer.RepoURL()}, Mode: modeReplicate, ProtocolMode: protocolModeAuto, BatchMaxPackBytes: 500_000, // force > 1 batch for the generated pack }) if err != nil { t.Fatalf("replicate with batched bootstrap failed: %v", err) } if result.OperationMode != modeReplicate { t.Fatalf("expected operation_mode=replicate, got %q", result.OperationMode) } if !result.Batching || result.BatchCount < 2 { t.Fatalf("expected batched bootstrap inside replicate, got batching=%t batch_count=%d result=%+v", result.Batching, result.BatchCount, result) }

assertHeadsMatch(t, sourceRepo, targetRepo, testBranch) }

func TestRun_IntegrationReplicateBootstrapsEmptyTarget(t *testing.T) { sourceRepo, sourceFS := newSourceRepo(t) makeCommits(t, sourceRepo, sourceFS, 2)