Resume from stale temp refs by finding their chain position · Entire

Resume from stale temp refs by finding their chain position

e185f44→main·

Soph·3mo ago·1 file·+32 added/-3 removed

When a temp ref from a previous run doesn't match any planned checkpoint, look up its hash in the commit chain. If found, use it as the starting point and re-plan remaining checkpoints from there — preserving the data already pushed by previous batches.

Only delete the temp ref and start fresh when the hash isn't in the chain at all (truly unrelated data, not just a different checkpoint plan).

For the linux case: previous run pushed batches 1-2 (~3 GiB) and left the temp ref at a subdivide midpoint. With different --target-max-pack-bytes, the new plan doesn't include that midpoint as a checkpoint. Instead of re-pushing 3 GiB, we now find the midpoint in the chain (position ~50k of 75k), plan checkpoints for the remaining ~25k commits, and push only what's missing.

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

Sessions

a474315dec7bView transcript

Changes

1

217 unmodified lines

218
219
220
221
222
223
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
265 unmodified lines

511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526

217 unmodified lines

current := batch.ResumeHash
    startIdx, err := planner.BootstrapResumeIndex(batch.Checkpoints, batch.ResumeHash)
    if err != nil {
        // Stale temp ref from a previous run with different parameters.
        // Delete it and start the branch fresh.
    if err != nil && !batch.ResumeHash.IsZero() && len(batch.chain) > 0 {
        // Temp ref doesn't match any planned checkpoint (e.g., the user
        // changed --target-max-pack-bytes between runs). If the hash is
        // in the commit chain, reuse it as the starting point and re-plan
        // remaining checkpoints — preserving already-pushed data.
        if chainIdx := chainPosition(batch.chain, batch.ResumeHash); chainIdx >= 0 {
            remaining := batch.chain[chainIdx+1:]
            if len(remaining) > 0 {
                numBatches := estimateBatchCount(int64(len(remaining)), p.TargetMaxPack)
                batch.Checkpoints = evenCheckpoints(remaining, numBatches)
                p.log("bootstrap batch resuming from stale temp ref",
                    "branch", batch.Plan.TargetRef.String(),
                    "resume_hash", planner.ShortHash(batch.ResumeHash),
                    "remaining_commits", len(remaining),
                    "new_batches", len(batch.Checkpoints))
                startIdx = 0
                err = nil
            }
        }
    }
    if err != nil && !batch.ResumeHash.IsZero() {
        // Temp ref hash not in the chain at all — truly stale. Delete and start fresh.
        p.log("bootstrap batch clearing stale temp ref",
            "branch", batch.Plan.TargetRef.String(),
            "temp_ref", batch.TempRef.String(),
265 unmodified lines

func (w *wrappedMultiRC) Read(p []byte) (int, error) { return w.Reader.Read(p) }

// chainPosition returns the index of hash in chain, or -1 if not found.
func chainPosition(chain []plumbing.Hash, hash plumbing.Hash) int {
    for i, h := range chain {
        if h == hash {
            return i
        }
    }
    return -1
}

// subdivideCheckpoints splits each remaining checkpoint range in half using
// the full commit chain. Called when a batch push is rejected for exceeding
// the target's body-size limit. Returns the expanded checkpoint list; if no