Skip pack push for branches fully subsumed by trunk · Entire
Skip pack push for branches fully subsumed by trunk
fc37c09→main· Soph·2mo ago·2 files·+126 added/-0 removed
When trunk is planned first, its ancestry set already tells us which branches contain no new commits — their tip is already reachable from trunk, so trunk's batches have delivered every object those branches need. Previously those branches still ran the full checkpoint machinery: a commit-graph fetch (usually near-empty), a pack fetch (usually near-empty), a temp-ref push, a cutover push, and a temp-ref delete.
With this change, the subsumed case is detected in planBatches before the commit-graph fetch, and the resulting plannedBatch carries a subsumed flag instead of checkpoints. executeBatched handles that flag with a single ref-create PushCommand that points at the source hash — no fetch, no pack, no temp ref, no cutover dance.
Correctness rests on trunkStopSet containing every commit reachable from the trunk tip, not just the first-parent chain. collectCommitHashes iterates all CommitObjects in the tree:0 fetch result, so merges and their ancestors are included. A branch tip is therefore only marked subsumed when its entire history is already covered by trunk's batches.
Added TestExecuteBatchedSubsumedBranchSkipsPack verifies that for a feature branch pointing at an older commit on trunk's chain, the planner emits zero commit-graph fetches and zero pack fetches for that branch, and the executor issues only a single ref-create via PushCommands.
Webhook-count note: GitHub fires one push event per ref update, so the subsumed branch still generates one webhook when its ref is created. This change cuts the per-branch HTTP round-trips and object transfer for that branch, not the webhook event itself. Operators concerned about webhook volume during bulk migrations should still disable target webhooks for the duration of the run.
Co-Authored-By: Claude Opus 4.6 (1M context) noreply@anthropic.com
Sessions
4cb744e14612View transcript
Changes
2
internal/strategy/bootstrap
Mbootstrap.go+44
Mbootstrap_test.go+82
78 unmodified lines
79
80
81
82
83
84
85
86
87
88
89
90
134 unmodified lines
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
204 unmodified lines
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
78 unmodified lines
planner.BootstrapBatch
chain []plumbing.Hash // full first-parent chain (root→tip) for subdividing on push failure
// subsumed is true when the branch tip is already reachable from the
// trunk (planned first), so every object is already on the target after
// trunk's batches. Execution skips the commit-graph fetch, the pack
// fetch, the temp ref, and the pack push — emitting only a single ref
// create command.
subsumed bool
}
// Execute runs the bootstrap strategy (one-shot or batched).
134 unmodified lines
completedRefs := planner.CopyRefHashMap(p.TargetRefs)
for _, batch := range batches {
if batch.subsumed {
cmds := []gitproto.PushCommand{{
Name: batch.Plan.TargetRef,
Old: plumbing.ZeroHash,
New: batch.Plan.SourceHash,
}}
if err := p.TargetPusher.PushCommands(ctx, cmds); err != nil {
return result, fmt.Errorf("create subsumed branch ref for %s: %w", batch.Plan.TargetRef, err)
}
completedRefs[batch.Plan.TargetRef] = batch.Plan.SourceHash
result.BatchCount++
p.log("bootstrap batch subsumed branch finalized",
"branch", batch.Plan.TargetRef.String(),
"source_hash", planner.ShortHash(batch.Plan.SourceHash))
continue
}
result.PlannedBatchCount += len(batch.Checkpoints)
result.TempRefs = append(result.TempRefs, batch.TempRef.String())
p.log("bootstrap batch branch plan",
204 unmodified lines
)
for i, ref := range ordered {
// Branches whose tip is already reachable from trunk's ancestry need
// no pack transfer — trunk's batches already delivered every object.
// Emit a subsumed batch that the executor handles with a single ref
// create command.
if i != trunkIdx && trunkStopSet != nil {
if _, subsumed := trunkStopSet[ref.SourceHash]; subsumed {
p.log("bootstrap batch branch subsumed by trunk",
"branch", ref.TargetRef.String(),
"source_hash", planner.ShortHash(ref.SourceHash))
out = append(out, plannedBatch{
BootstrapBatch: planner.BootstrapBatch{
Plan: planner.BranchPlan{
Branch: ref.Label, SourceRef: ref.SourceRef,
TargetRef: ref.TargetRef, SourceHash: ref.SourceHash,
Kind: ref.Kind, Action: planner.ActionCreate,
},
},
subsumed: true,
})
continue
}
}
var (
haves []plumbing.Hash
stopAt map[plumbing.Hash]struct{}
Minternal/strategy/bootstrap/bootstrap.go+44
450 unmodified lines
}
}
func TestExecuteBatchedSubsumedBranchSkipsPack(t *testing.T) {
mainRef := plumbing.NewBranchReferenceName("main")
featureRef := plumbing.NewBranchReferenceName("feature")
// Linear chain: hashes[0] -> hashes[1] -> hashes[2]. main tip = hashes[2],
// feature tip = hashes[0]. feature is entirely within main's ancestry, so
// trunk-first planning should mark it subsumed and emit zero pack pushes
// for it.
hashes := makeLinearCommitChain(t, 3)
mainHash := hashes[2]
featureHash := hashes[0]
var (
graphFetches int
packFetches int
pushPackCalls int
pushCommandsBatches [][]gitproto.PushCommand
)
_, err := Execute(context.Background(), Params{
SourceService: fakeBootstrapSource{
fetchCommitGraph: func(_ context.Context, store storer.Storer, _ *gitproto.Conn, ref gitproto.DesiredRef, _ []plumbing.Hash) error {
graphFetches++
if ref.SourceRef != mainRef {
t.Errorf("unexpected commit-graph fetch for %s; subsumed branch should have been skipped", ref.SourceRef)
}
writeLinearCommitChain(t, store, 3)
return nil
},
fetchPack: func(_ context.Context, _ *gitproto.Conn, desired map[plumbing.ReferenceName]gitproto.DesiredRef, _ map[plumbing.ReferenceName]plumbing.Hash) (io.ReadCloser, error) {
packFetches++
if _, ok := desired[featureRef]; ok {
t.Errorf("unexpected pack fetch including feature ref: %+v", desired)
}
return io.NopCloser(bytes.NewReader([]byte("PACK"))), nil
},
},
TargetPusher: fakeBootstrapPusher{
pushPack: func(_ context.Context, _ []gitproto.PushCommand, pack io.ReadCloser) error {
pushPackCalls++
_ = pack.Close()
return nil
},
pushCommands: func(_ context.Context, cmds []gitproto.PushCommand) error {
pushCommandsBatches = append(pushCommandsBatches, append([]gitproto.PushCommand(nil), cmds...))
return nil
},
},
DesiredRefs: map[plumbing.ReferenceName]planner.DesiredRef{
mainRef: {SourceRef: mainRef, TargetRef: mainRef, SourceHash: mainHash, Kind: planner.RefKindBranch, Label: "main"},
featureRef: {SourceRef: featureRef, TargetRef: featureRef, SourceHash: featureHash, Kind: planner.RefKindBranch, Label: "feature"},
},
TargetRefs: map[plumbing.ReferenceName]plumbing.Hash{},
SourceHeadTarget: mainRef,
TargetMaxPack: 1024 * 1024,
}, "empty target")
if err != nil {
t.Fatalf("Execute: %v", err)
}
if graphFetches != 1 {
t.Errorf("fetchCommitGraph called %d times, want 1 (trunk only)", graphFetches)
}
if packFetches != 1 {
t.Errorf("fetchPack called %d times, want 1 (trunk only)", packFetches)
}
if pushPackCalls != 1 {
t.Errorf("PushPack called %d times, want 1 (trunk only)", pushPackCalls)
}
var foundFeatureCreate bool
for _, cmds := range pushCommandsBatches {
for _, cmd := range cmds {
if cmd.Name == featureRef && cmd.New == featureHash && cmd.Old == plumbing.ZeroHash && !cmd.Delete {
foundFeatureCreate = true
}
}
}
if !foundFeatureCreate {
t.Fatalf("expected ref-create command for feature at %s; got %v", featureHash, pushCommandsBatches)
}
}
type fakeBootstrapSource struct {
fetchPack func(context.Context, *gitproto.Conn, map[plumbing.ReferenceName]gitproto.DesiredRef, map[plumbing.ReferenceName]plumbing.Hash) (io.ReadCloser, error)
fetchCommitGraph func(context.Context, storer.Storer, *gitproto.Conn, gitproto.DesiredRef, []plumbing.Hash) error
}`