Skip to content

fix: reconcile disconnected local/remote metadata branches on enable#518

Closed
dvydra wants to merge 2 commits intofix/update-empty-metadata-from-remotefrom
fix/reconcile-disconnected-metadata-branch
Closed

fix: reconcile disconnected local/remote metadata branches on enable#518
dvydra wants to merge 2 commits intofix/update-empty-metadata-from-remotefrom
fix/reconcile-disconnected-metadata-branch

Conversation

@dvydra
Copy link
Contributor

@dvydra dvydra commented Feb 26, 2026

Problem

When a user hit the empty-orphan bug (#511) and then worked normally, the CLI recorded checkpoints onto the local orphan. Now the local entire/checkpoints/v1 has real data on a completely disconnected history from the remote — no common ancestor, both containing real checkpoint data.

Neither #511 (fresh clone fix) nor #516 (empty orphan update) handle this case because the local branch isn't empty.

Discussion: https://entireio.slack.com/archives/C0A095SNK32/p1772083910982219?thread_ts=1772052543.300359&cid=C0A095SNK32

Fix

EnsureMetadataBranch() now detects when local and remote metadata branches have real data but differ, and uses git merge-base --is-ancestor to determine the relationship:

  1. Remote is ancestor of local → already synced, nothing to do
  2. Local is ancestor of remote → fast-forward local to remote
  3. Neither (disconnected/diverged) → merge both trees into a merge commit

The merge is safe because checkpoint data is sharded by random ID (<id[:2]>/<id[2:]>/) with no shared index or manifest — different checkpoints never write to the same paths.

Uses the same tree-merge pattern as fetchAndMergeSessionsCommon() in push_common.go: flatten both trees via FlattenTree(), combine entries, rebuild via BuildTreeFromEntries(), create merge commit with both parents.

Test plan

  • TestEnsureMetadataBranch_ReconcilesDisconnectedBranches — creates disconnected orphan with local data, verifies merge contains both sides
  • TestEnsureMetadataBranch_FastForwardsWhenBehind — local behind remote, verifies fast-forward
  • Existing tests still pass (fresh clone, empty orphan, no remote)
  • mise run fmt && mise run lint && mise run test:ci clean

🤖 Generated with Claude Code

When a user hit the empty-orphan bug and then worked normally, the local
entire/checkpoints/v1 has real checkpoint data on a disconnected history
from the remote. EnsureMetadataBranch now detects this using
git merge-base and reconciles by merging both trees (checkpoint shards
are unique, so no conflicts). Also handles the simpler case where local
is behind remote (fast-forward).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Entire-Checkpoint: cee58fd2febc
Copilot AI review requested due to automatic review settings February 26, 2026 06:51
@cursor
Copy link

cursor bot commented Feb 26, 2026

PR Summary

Medium Risk
Touches git ref/commit manipulation for the metadata branch and shells out to git merge-base, so failures could impact checkpoint syncing or create unexpected merge commits if assumptions about tree merging change.

Overview
Fixes EnsureMetadataBranch() so that when both local and origin/entire/checkpoints/v1 exist with non-empty but different histories, the CLI determines ancestry via git merge-base --is-ancestor and either does nothing, fast-forwards the local ref, or creates a merge commit that combines both checkpoint trees.

Adds syncMetadataBranch/isAncestorCLI helpers (uses git CLI with a timeout) and expands tests to cover disconnected-history reconciliation and the “local behind remote” fast-forward case, plus a small test utility for cloning with git identity.

Written by Cursor Bugbot for commit 32ad256. Configure here.

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 critical bug where users who encountered the empty-orphan bug (#511) and then continued working would have disconnected local and remote metadata branches with real checkpoint data but no common ancestor. The fix adds logic to detect and reconcile such disconnected branches through merging.

Changes:

  • Added syncMetadataBranch() function to handle disconnected/diverged local and remote metadata branches using git merge-base for ancestry checks
  • Added isAncestorCLI() helper to check commit ancestry via git CLI (avoiding go-git depth limits)
  • Added comprehensive test coverage for branch reconciliation scenarios including disconnected branches and fast-forward cases

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.

File Description
cmd/entire/cli/strategy/common.go Implements branch reconciliation logic with ancestry detection and tree merging for disconnected metadata branches
cmd/entire/cli/strategy/common_test.go Adds test helper and comprehensive tests for reconciliation scenarios (disconnected branches, fast-forward, existing tests)

…ite time

Move detection and repair of disconnected local/remote metadata branches
from EnsureMetadataBranch (enable) to a sync.Once-guarded reconciliation
that runs when commands actually access the metadata branch (explain,
rewind, resume, etc.). Uses cherry-pick strategy instead of merge to
preserve linear commit history.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Entire-Checkpoint: 639c85c9977a
@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