# Push git-refs checkpoints from pre-push via the discovery queue

`b1e2993`·

Soph·2w ago·3 files·+231 added/-6 removed

When the configured primary is git-refs, PrePush drains the push-discovery queue
and batch force-pushes those per-checkpoint refs (one git push, +ref:ref force
refspecs — independent histories, no fetch+rebase recovery) instead of pushing
the v1 branch. Default config (git-branch) is unchanged.

- partitionLocalRefs drops stale queue entries (refs deleted locally); surviving
refs are removed from the queue only on a confirmed push, so a failed/transient
push leaves them for the next pre-push and never blocks the user's git push.
- Shared post-push shadow cleanup extracted to cleanupPushedShadowBranches.

A configured git-branch mirror's v1 ref is not pushed here yet (downgrade-safety
mirror push is later), and OPF stays descoped for git-refs.

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

## Sessions

7ca5586da108View transcript

## Changes

3

- cmd/entire/cli/strategy
  
  - Mmanual_commit_push.go+77/-6
  
  - Mpush_common.go+37
  
  - Arefs_push_test.go+117

``` 
42 unmodified lines

43
44
45
46
47
48
49
50
51
52
53
54
55
60 unmodified lines

116
117
118
112
113
114
115
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
3 unmodified lines

195
196
197
125
126
198

42 unmodified lines

return nil
	}

// git-refs primary: push the per-checkpoint refs recorded in the push queue
	// instead of the single v1 branch. (A configured git-branch mirror's v1 ref
	// is not pushed here yet — mirror push for downgrade safety is a later step.)
	if cpCfg, _ := settings.LoadCheckpointsConfig(ctx); checkpoint.PrimaryIsRefs(cpCfg) { //nolint:errcheck // fail-soft: a bad checkpoints block already surfaces via Open; default to no refs push
		return s.prePushCheckpointRefs(ctx, ps)
	}

refs := checkpoint.ResolveRefs(ctx)
	if !syncCheckpointPolicyForPrePush(ctx, ps) {
		return nil
	}
pushCheckpointsSpan.End()

// Post-push cleanup: only when all configured checkpoint refs were pushed
	// successfully, so we know condensed checkpoint data reached the remote.
	// Failures here are non-fatal — shadow branches just accumulate until
	// `entire clean` or the next successful push.
	cleanupPushedShadowBranches(ctx)
	return nil
}

// prePushCheckpointRefs drains the per-checkpoint push queue and batch force-pushes
// the recorded refs (git-refs primary). Transient push failures are logged and
// swallowed — like the v1 path, they must not block the user's git push — and the
// refs stay queued for the next pre-push. OPF is not applied (it is descoped for
// the git-refs store for now).
func (s *ManualCommitStrategy) prePushCheckpointRefs(ctx context.Context, ps pushSettings) error {
	repo, err := OpenRepository(ctx)
	if err != nil {
		logging.Warn(ctx, "git-refs pre-push: open repo failed; skipping checkpoint push",
			slog.String("error", err.Error()))
		return nil
	}
	defer repo.Close()

queue, err := checkpoint.PushQueueForRepo(ctx, repo)
	if err != nil {
		logging.Warn(ctx, "git-refs pre-push: resolve push queue failed; skipping checkpoint push",
			slog.String("error", err.Error()))
		return nil
	}
	queued, err := queue.Drain()
	if err != nil {
		logging.Warn(ctx, "git-refs pre-push: drain push queue failed; skipping checkpoint push",
			slog.String("error", err.Error()))
		return nil
	}
	if len(queued) == 0 {
		return nil
	}

// Drop stale entries (refs no longer present locally) so they don't block
	// the queue forever, then push what remains.
	existing, stale := partitionLocalRefs(repo, queued)
	if len(stale) > 0 {
		if err := queue.Remove(stale); err != nil {
			logging.Warn(ctx, "git-refs pre-push: prune stale queue entries failed",
				slog.String("error", err.Error()))
		}
	}
	if len(existing) == 0 {
		return nil
	}

pushCtx, pushSpan := perf.Start(ctx, "push_checkpoint_refs")
	pushErr := batchForcePushRefs(pushCtx, ps.pushTarget(), existing)
pushSpan.End()
	if pushErr != nil {
		// Leave the refs queued; the next pre-push retries. Non-fatal so the
		// user's push proceeds.
		logging.Warn(ctx, "git-refs pre-push: batch push failed; refs left queued for retry",
			slog.String("error", pushErr.Error()))
		return nil
	}
	if err := queue.Remove(existing); err != nil {
		logging.Warn(ctx, "git-refs pre-push: clear pushed refs from queue failed",
			slog.String("error", err.Error()))
	}

cleanupPushedShadowBranches(ctx)
	return nil
}

// cleanupPushedShadowBranches runs post-push shadow-branch cleanup. Failures are
// non-fatal — shadow branches just accumulate until `entire clean` or the next
// successful push.
func cleanupPushedShadowBranches(ctx context.Context) {
	if deleted, cleanupErr := CleanupPushedShadowBranches(ctx); cleanupErr != nil {
		logging.Warn(ctx, "post-push shadow branch cleanup failed",
			slog.String("error", cleanupErr.Error()),
			slog.Int("count", deleted),
		)
	}

return nil
}
``

Mcmd/entire/cli/strategy/manual_commit_push.go+77/-6

```
21 unmodified lines

22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64

21 unmodified lines

"github.com/go-git/go-git/v6/plumbing/object"

// partitionLocalRefs splits refs into those that exist locally (pushable) and
// those that don't (stale queue entries — e.g. a checkpoint ref deleted by
// cleanup). Stale refs can never push, so callers drop them from the queue
// rather than retrying them forever.
func partitionLocalRefs(repo *git.Repository, refs []plumbing.ReferenceName) (existing, stale []plumbing.ReferenceName) {
	for _, ref := range refs {
		if _, err := repo.Reference(ref, false); err != nil {
			stale = append(stale, ref)
			continue
		}
		existing = append(existing, ref)
	}
	return existing, stale
}

// batchForcePushRefs pushes all of refs to target in a single git push. Each
// uses a force refspec (+ref:ref), matching how non-branch checkpoint refs are
// already pushed: per-checkpoint refs have independent histories with no
// remote-tracking shadow, so there is no fast-forward to preserve and no
// fetch+rebase recovery to attempt. Batching keeps a backfill of many refs to
// one network round-trip. It is all-or-nothing: on error the caller leaves every
// ref queued for the next pre-push (partial-failure reconciliation is out of
// scope for now).
func batchForcePushRefs(ctx context.Context, target string, refs []plumbing.ReferenceName) error {
	if len(refs) == 0 {
		return nil
	}
	refSpecs := make([]string, 0, len(refs))
	for _, ref := range refs {
		refSpecs = append(refSpecs, "+"+ref.String()+":"+ref.String())
	}
	if _, err := remote.PushWithOptions(ctx, remote.PushOptions{Remote: target, RefSpecs: refSpecs}); err != nil {
		return fmt.Errorf("batch push %d checkpoint refs: %w", len(refs), err)
	}
	return nil
}

// pushRefIfNeeded pushes a ref to the given target if it has unpushed changes.
// The target can be a remote name (e.g., "origin") or a URL for direct push.
// For branch refs, the "has unpushed" optimization consults the remote-tracking
