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

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
}`