fix: update empty local metadata branch from remote on enable#516
fix: update empty local metadata branch from remote on enable#516
Conversation
When enable previously created an empty orphan entire/checkpoints/v1 and the remote later has real checkpoint data, detect the empty local branch and update it from the remote-tracking branch. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Entire-Checkpoint: 15849a699702
PR SummaryMedium Risk Overview
Written by Cursor Bugbot for commit e2aa173. Configure here. |
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
Bugbot Autofix is OFF. To automatically fix reported issues with Cloud Agents, enable autofix in the Cursor dashboard.
Comment @cursor review or bugbot run to trigger another review on this PR
| return false, fmt.Errorf("failed to get tree: %w", err) | ||
| } | ||
| return len(tree.Entries) == 0, nil | ||
| } |
There was a problem hiding this comment.
Missing parent check allows overwriting non-orphan branches
Medium Severity
isEmptyMetadataBranch only checks if the tip commit's tree is empty but doesn't verify the commit is actually an orphan (no parents). The PR description states the intent is to detect "an empty orphan (single commit with empty tree)," but a branch with history — e.g., after a cleanup operation removes all checkpoints — could also have an empty tree at its tip while having parent commits. In that case, the local branch would be incorrectly overwritten by the remote, losing local-only history. Adding a len(commit.ParentHashes) == 0 check would properly restrict this to true orphan commits.
There was a problem hiding this comment.
Pull request overview
This PR fixes a recovery path for users who ran entire enable with old code that created an empty orphan entire/checkpoints/v1 branch. When they update to new code and run enable again, it now detects and updates the empty local branch from the remote if available, fixing broken entire explain functionality.
Changes:
- Enhanced
EnsureMetadataBranch()to detect empty local metadata branches and update them from remote when available - Added
isEmptyMetadataBranch()helper to check if a branch has an empty tree - Added test case verifying empty orphan branches are updated from remote
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
| cmd/entire/cli/strategy/common.go | Added logic to detect and update empty local metadata branches from remote; added helper function to check for empty branches |
| cmd/entire/cli/strategy/common_test.go | Added test case to verify empty orphan branches are updated from remote |
| } | ||
| if ref.Hash() == orphanHash { | ||
| t.Error("local branch still points to empty orphan — was not updated from remote") | ||
| } |
There was a problem hiding this comment.
This test verifies the hash changed but doesn't verify that the remote data was actually preserved. Consider adding an assertion that verifies the tree is no longer empty and contains the expected data, similar to the assertion in the "creates from remote on fresh clone" test (lines 1067-1069). This would more thoroughly validate the fix's behavior.
| } | |
| } | |
| // Verify the updated metadata branch commit has a non-empty tree (remote data preserved) | |
| commit, err := repo.CommitObject(ref.Hash()) | |
| if err != nil { | |
| t.Fatalf("failed to get commit: %v", err) | |
| } | |
| tree, err := commit.Tree() | |
| if err != nil { | |
| t.Fatalf("failed to get tree: %v", err) | |
| } | |
| if len(tree.Entries) == 0 { | |
| t.Errorf("expected non-empty tree after updating from remote, got %d entries", len(tree.Entries)) | |
| } |
| if ref.Hash() == orphanHash { | ||
| t.Error("local branch still points to empty orphan — was not updated from remote") | ||
| } | ||
| }) |
There was a problem hiding this comment.
The PR description states "Non-empty local branches are never overwritten," which is a critical safety guarantee. However, there's no test case verifying this behavior. Consider adding a test that creates a local branch with real data (different from the remote) and verifies EnsureMetadataBranch doesn't overwrite it. This would ensure the isEmpty check at line 308 correctly protects user data from being accidentally destroyed.
| isEmpty, checkErr := isEmptyMetadataBranch(repo, localRef) | ||
| if checkErr == nil && isEmpty { | ||
| ref := plumbing.NewHashReference(refName, remoteRef.Hash()) | ||
| if setErr := repo.Storer.SetReference(ref); setErr != nil { | ||
| return fmt.Errorf("failed to update metadata branch from remote: %w", setErr) | ||
| } | ||
| fmt.Fprintf(os.Stderr, "✓ Updated local branch '%s' from origin\n", paths.MetadataBranchName) | ||
| } |
There was a problem hiding this comment.
If isEmptyMetadataBranch returns an error, the code silently ignores it and leaves the local branch pointing to the empty orphan. While this may be intentional for robustness, it could mask real issues like disk I/O errors or repository corruption. Consider logging a warning when checkErr is not nil so users are aware that the update was skipped due to an error, using the logging package as per guideline 1000000.
|
superceded by #533 |


Problem
Users who already ran
entire enableon old code have an empty orphanentire/checkpoints/v1branch. When they update to the new code (from #511) and runenableagain, it sees the local branch exists and does nothing — leavingentire explainbroken.This is the recovery path for existing installs. PR #511 prevents the problem for fresh clones; this PR fixes repos already in the broken state.
Discussion: https://entireio.slack.com/archives/C0A095SNK32/p1772083910982219?thread_ts=1772052543.300359&cid=C0A095SNK32
Fix
When the local
entire/checkpoints/v1exists, check if it's an empty orphan (single commit with empty tree). If so, and the remote has real data, update the local branch to match the remote.Non-empty local branches are never overwritten.
Test plan
TestEnsureMetadataBranch/updates_empty_orphan_from_remote— detects empty orphan, updates from remotemise run fmt && mise run lint && mise run test:ciclean🤖 Generated with Claude Code