Skip to content

fix: update empty local metadata branch from remote on enable#516

Closed
dvydra wants to merge 1 commit intomainfrom
fix/update-empty-metadata-from-remote
Closed

fix: update empty local metadata branch from remote on enable#516
dvydra wants to merge 1 commit intomainfrom
fix/update-empty-metadata-from-remote

Conversation

@dvydra
Copy link
Contributor

@dvydra dvydra commented Feb 26, 2026

Problem

Users who already ran entire enable on old code have an empty orphan entire/checkpoints/v1 branch. When they update to the new code (from #511) and run enable again, it sees the local branch exists and does nothing — leaving entire explain broken.

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/v1 exists, 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 remote
  • Existing tests still pass (fresh clone, no remote)
  • mise run fmt && mise run lint && mise run test:ci clean

🤖 Generated with Claude Code

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
Copilot AI review requested due to automatic review settings February 26, 2026 05:36
@cursor
Copy link

cursor bot commented Feb 26, 2026

PR Summary

Medium Risk
Touches git ref/branch update logic for the metadata branch; while guarded to only update empty branches, mistakes could still overwrite or mis-point metadata refs and impact checkpoint visibility.

Overview
Fixes a recovery case where entire enable previously created an empty orphan entire/checkpoints/v1 branch, preventing later checkpoint reads even when origin/entire/checkpoints/v1 contains data.

EnsureMetadataBranch now checks for the remote-tracking metadata branch up front and, when a local branch exists, updates it only if it points to an empty-tree orphan and the remote has data; otherwise behavior stays the same (create from remote if missing, or create an empty orphan if neither exists). Adds isEmptyMetadataBranch plus a new test covering the “empty orphan gets updated from remote” scenario.

Written by Cursor Bugbot for commit e2aa173. Configure here.

Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Fix in Cursor Fix in Web

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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")
}
Copy link

Copilot AI Feb 26, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Suggested change
}
}
// 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))
}

Copilot uses AI. Check for mistakes.
if ref.Hash() == orphanHash {
t.Error("local branch still points to empty orphan — was not updated from remote")
}
})
Copy link

Copilot AI Feb 26, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copilot uses AI. Check for mistakes.
Comment on lines +308 to +315
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)
}
Copy link

Copilot AI Feb 26, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copilot uses AI. Check for mistakes.
Base automatically changed from fix/enable-preserve-remote-checkpoints to main February 26, 2026 10:55
@dvydra
Copy link
Contributor Author

dvydra commented Feb 26, 2026

superceded by #533

@dvydra dvydra closed this Feb 26, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

2 participants