# /simplify: make non-branch ref push non-force too (one consistent policy)

`e8e7e94`→[main](/content/gh/entireio/cli/commits/main/index.html)·

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

Altitude follow-up to the non-force checkpoint push: tryPushRefCommon (the v1-era
per-ref pusher behind doPushRef) still force-pushed non-branch refs (+ref:ref),
which contradicts the new fast-forward-only policy for per-checkpoint refs and was
a latent footgun — a future caller routing a checkpoint ref through doPushRef
would silently overwrite a divergence. The non-branch path has no production
caller today (the v1 PrePush loop only pushes the v1 branch), so dropping the
force is safe and unifies the policy: every checkpoint ref, branch or
per-checkpoint, is fast-forward-only with doPushRef's fetch+rebase recovery on
divergence.

Also clarify (comment) that explain_export's RefName-error branch is defensive —
cid is already validated by NewCheckpointID, so it can't fire — rather than a
swallowed live error.

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

## Sessions

89a2a991d773View transcript

[?\
Build Checkpoints Store Based on DesignClaude Code·2 steps](/content/gh/entireio/cli/session/6852b33a-0d22-4364-aa6c-8de706ecc215#timeline-89a2a991d773/index.html)

## Changes

2

- cmd/entire/cli

- Mexplain_export.go+3

- strategy

- Mpush_common.go+7/-3

```
205 unmodified lines

206
207
208
209
210
211
212
213
214

205 unmodified lines

// then re-list. Falls through to the v1-branch fetch below otherwise.
	if cpCfg, _ := settings.LoadCheckpointsConfig(ctx); checkpoint.PrimaryIsRefs(cpCfg) { //nolint:errcheck // fail-soft: bad config surfaces via Open elsewhere
		if cid, err := id.NewCheckpointID(prefix); err == nil {
			// cid is already validated by NewCheckpointID above, so RefName can't
			// error here; the guard is defensive — fall back to the v1-branch path
			// rather than fetch a malformed ref.
			refName, refErr := checkpoint.RefName(cid)
			if refErr != nil {
				return nil, lookup
```

Mcmd/entire/cli/explain_export.go+3

```
298 unmodified lines

299
300
301
302
303
302
303
304
305
306
307
308
309
310
307
311
312
313
314

298 unmodified lines

// tryPushRefCommon attempts to push a ref. No timeout of its own —
// runs under doPushRef's shared budget. Branch refs use a bare branch-name
// refSpec so existing remote-tracking works; non-branch refs use a force
// refspec ("+refs/...:refs/...") with no tracking shadow.
// refSpec so existing remote-tracking works; non-branch refs use an explicit
// "refs/...:refs/..." refSpec with no tracking shadow. Neither forces: a
// non-fast-forward is rejected so doPushRef's fetch+rebase recovery runs (and a
// genuinely diverged ref is never silently overwritten — there is no
// server-side ref protection). This keeps one consistent non-force policy for
// every checkpoint ref, branch or per-checkpoint.
func tryPushRefCommon(ctx context.Context, remoteName string, ref plumbing.ReferenceName) (pushResult, error) {
	refSpec := ref.Short()
	if !ref.IsBranch() {
		refSpec = "+" + ref.String() + ":" + ref.String()
		refSpec = ref.String() + ":" + ref.String()
	}

// Span the actual `git push` subprocess: on a slow remote (e.g. a custom
```

Mcmd/entire/cli/strategy/push_common.go+7/-3
