migrate-to-ulid: switch the repo onto the git-refs backend · Entire

migrate-to-ulid: switch the repo onto the git-refs backend

d86ba7f·

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

The migration created ULID refs and enqueued them for push, but left checkpoints.primary unset — so the configured backend stayed git-branch, the pre-push hook took the v1-branch path, and the queued ULID refs were never flushed. Symptom: git push says "Everything up-to-date" while the refs sit in .git/entire-checkpoint-push-queue.jsonl forever.

--yes now writes checkpoints.primary = git-refs into .entire/settings.json (preserving other keys; creating .entire if absent), so the repo is genuinely on the refs backend: reads route to refs and the pre-push hook flushes the ref queue. The final message notes the settings change and that a git push flushes the refs (the pre-push hook runs even when the branch is up to date).

Test asserts checkpoints.primary is git-refs after apply.

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

Sessions

1782339e41c8View transcript

Changes

2

2 unmodified lines

3
4
5
6
7
8
9
10
11
12
13
14
15
2 unmodified lines

18
19
20
21
22
23
24
81 unmodified lines

106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
2 unmodified lines

123
124
125
114
126
127
128
129
130
131
120
121
132
133
134
135
136
137
138
49 unmodified lines

188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221

2 unmodified lines

import (
    "bufio"
    "context"
    "encoding/json"
    "errors"
    "fmt"
    "io"
    "os"
    "os/exec"
    "path/filepath"
    "regexp"
    "strings"

2 unmodified lines

cpkg "github.com/entireio/cli/cmd/entire/cli/checkpoint"
    "github.com/entireio/cli/cmd/entire/cli/paths"
    "github.com/entireio/cli/cmd/entire/cli/settings"
)

// newDoctorMigrateToULIDCmd builds the hidden `entire doctor migrate-to-ulid`

fmt.Fprintf(out, "\nWrote %d ULID checkpoint ref(s).\n", len(result.Mapping))

// Switch the repo onto the git-refs backend. Without this the configured
            // primary stays git-branch, so the pre-push hook takes the v1-branch path
            // and never flushes the queued ULID refs — the whole point is to be "on
            // refs", which the settings must declare.
            if err := setGitRefsPrimary(ctx); err != nil {
                return fmt.Errorf("switch repo to git-refs backend: %w", err)
            }
            fmt.Fprintln(out, "Set checkpoints.primary = git-refs in .entire/settings.json.");

// Rewrite the Entire-Checkpoint trailers across the user branches.
            if len(userBranches) > 0 {
                if err := rewriteCheckpointTrailers(ctx, repoRoot, result.Mapping, userBranches); err != nil {
                fmt.Fprintf(out, "Rewrote Entire-Checkpoint trailers on %d branch(es).\n", len(userBranches))
            }

// 3. Drop the entire/* infra branches so only the ULID refs remain.
            // Drop the entire/* infra branches so only the ULID refs remain.
            dropped := deleteBranches(ctx, repoRoot, infraBranches)
            if dropped > 0 {
                fmt.Fprintf(out, "Deleted %d entire/* branch(es) (v1 + shadow).\n", dropped)
            }

fmt.Fprintln(out, "\nDone. The repo now uses ULID refs only. Force-push branches and push the")
            fmt.Fprintln(out, "checkpoint refs to your test remote to validate commands and the UI.")
            fmt.Fprintln(out, "\nDone. The repo is now on the git-refs backend with ULID refs only.")
            fmt.Fprintln(out, "The ULID refs are queued for push; a `git push` flushes them (the pre-push")
            fmt.Fprintln(out, "hook runs even when the branch is up to date). Commit the settings change and")
            fmt.Fprintln(out, "force-push the rewritten branches to your test remote to validate the UI.")
            return nil
        },
    }

49 unmodified lines

return forEachRef(ctx, repoRoot, "refs/heads/entire")

// setGitRefsPrimary writes checkpoints.primary = git-refs into the project
// .entire/settings.json, preserving all other keys, so the repo is actually on
// the git-refs backend (reads route to refs and the pre-push hook flushes the
// checkpoint-ref queue).
func setGitRefsPrimary(ctx context.Context) error {
    path, raw, _, err := settings.LoadProjectRaw(ctx)
    if err != nil {
        return fmt.Errorf("load project settings: %w", err)
    }
    if raw == nil {
        raw = map[string]json.RawMessage{}
    }
    block, err := json.Marshal(settings.CheckpointsConfig{
        Primary: settings.BackendConfig{Type: cpkg.BackendTypeGitRefs},
    })
    if err != nil {
        return fmt.Errorf("encode checkpoints config: %w", err)
    }
    raw["checkpoints"] = block
    if err := os.MkdirAll(filepath.Dir(path), 0o750); err != nil {
        return fmt.Errorf("create .entire dir: %w", err)
    }
    if err := settings.SaveProjectRaw(path, raw); err != nil {
        return fmt.Errorf("write project settings: %w", err)
    }
    return nil
}

// hexCheckpointTrailerRe matches a legacy-hex Entire-Checkpoint trailer value.
var hexCheckpointTrailerRe = regexp.MustCompile(`Entire-Checkpoint: ([0-9a-f]{12})`)

Mcmd/entire/cli/doctor_migrate_ulid.go+45/-3

11 unmodified lines

12
13
14
15
16
17
18
74 unmodified lines

93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108

11 unmodified lines

cpkg "github.com/entireio/cli/cmd/entire/cli/checkpoint"
    "github.com/entireio/cli/cmd/entire/cli/checkpoint/id"
    "github.com/entireio/cli/cmd/entire/cli/paths"
    "github.com/entireio/cli/cmd/entire/cli/settings"
    "github.com/entireio/cli/cmd/entire/cli/testutil"
    "github.com/entireio/cli/cmd/entire/cli/trailers"
    "github.com/entireio/cli/redact"
74 unmodified lines

t.Fatalf("ULID ref %s should exist: %v", refName, err)
    }

// The repo is now configured on the git-refs backend (so pre-push flushes the
    // ULID ref queue and reads resolve as refs).
    cfg, err := settings.LoadCheckpointsConfig(ctx)
    if err != nil {
        t.Fatalf("load checkpoints config: %v", err)
    }
    if cfg == nil || cfg.Primary.Type != cpkg.BackendTypeGitRefs {
        t.Fatalf("checkpoints.primary should be git-refs after migration, got %+v", cfg)
    }

// The entire/checkpoints/v1 branch is gone (refs-native).
    v1 := plumbing.NewBranchReferenceName(paths.MetadataBranchName)
    if _, err := repo2.Reference(v1, true); err == nil {