fix(sync): use sync-branch worktree for --full --no-pull (#1183)
* fix(sync): use sync-branch worktree for --full --no-pull (#1173) Bug 1: PullFromSyncBranch was copying uncommitted worktree changes to main repo when remoteAhead==0. This corrupted the 3-way merge because local changes appeared as remote changes. Fixed by copying only the committed state from HEAD instead of the working directory. Bug 2: doExportOnlySync was checking main repo for changes via gitHasBeadsChanges, but when sync-branch is configured, changes go to the worktree, not main. Fixed by detecting sync-branch config and using CommitToSyncBranch which operates on the worktree. Fixes #1173 * refactor(sync): consolidate sync-branch detection and commit/push logic Extract repeated patterns into reusable helpers: - SyncBranchContext struct: holds branch name and repo root - getSyncBranchContext(): detects sync-branch config from store - commitAndPushBeads(): handles both sync-branch and regular git workflows This eliminates duplicated sync-branch detection code (was in 3 places) and the duplicated commit/push conditional logic (was in 2 places). Net reduction of ~20 lines while improving maintainability. * fix: remove unused bool return from commitAndPushBeads
This commit is contained in:
@@ -272,8 +272,12 @@ func PullFromSyncBranch(ctx context.Context, repoRoot, syncBranch, jsonlPath str
|
||||
// Case 1: Already up to date (remote has nothing new)
|
||||
if remoteAhead == 0 {
|
||||
result.Pulled = true
|
||||
// Still copy JSONL in case worktree has uncommitted changes
|
||||
if err := copyJSONLToMainRepo(worktreePath, jsonlRelPath, jsonlPath); err != nil {
|
||||
// GH#1173: Do NOT copy uncommitted worktree changes to main repo.
|
||||
// The worktree may have uncommitted changes from previous exports that
|
||||
// haven't been committed yet. Copying those to main would make local
|
||||
// data appear as "remote" data, corrupting the 3-way merge.
|
||||
// Instead, copy only the COMMITTED state from the worktree.
|
||||
if err := copyCommittedJSONLToMainRepo(ctx, worktreePath, jsonlRelPath, jsonlPath); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return result, nil
|
||||
@@ -655,6 +659,35 @@ func extractJSONLFromCommit(ctx context.Context, worktreePath, commit, filePath
|
||||
return output, nil
|
||||
}
|
||||
|
||||
// copyCommittedJSONLToMainRepo copies the COMMITTED JSONL from worktree to main repo.
|
||||
// GH#1173: This extracts the file from HEAD rather than the working directory,
|
||||
// ensuring uncommitted local changes don't corrupt the 3-way merge.
|
||||
func copyCommittedJSONLToMainRepo(ctx context.Context, worktreePath, jsonlRelPath, jsonlPath string) error {
|
||||
// GH#785: Handle bare repo worktrees
|
||||
normalizedRelPath := normalizeBeadsRelPath(jsonlRelPath)
|
||||
|
||||
// Extract the committed JSONL from HEAD
|
||||
data, err := extractJSONLFromCommit(ctx, worktreePath, "HEAD", normalizedRelPath)
|
||||
if err != nil {
|
||||
// File might not exist in HEAD yet (first sync), nothing to copy
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := os.WriteFile(jsonlPath, data, 0600); err != nil {
|
||||
return fmt.Errorf("failed to write main JSONL: %w", err)
|
||||
}
|
||||
|
||||
// Also copy committed metadata.json if it exists
|
||||
beadsDir := filepath.Dir(jsonlPath)
|
||||
metadataRelPath := filepath.Join(filepath.Dir(normalizedRelPath), "metadata.json")
|
||||
if metaData, err := extractJSONLFromCommit(ctx, worktreePath, "HEAD", metadataRelPath); err == nil {
|
||||
dstPath := filepath.Join(beadsDir, "metadata.json")
|
||||
_ = os.WriteFile(dstPath, metaData, 0600) // Best effort
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// copyJSONLToMainRepo copies JSONL and related files from worktree to main repo.
|
||||
func copyJSONLToMainRepo(worktreePath, jsonlRelPath, jsonlPath string) error {
|
||||
// GH#785: Handle bare repo worktrees where jsonlRelPath might include the
|
||||
|
||||
Reference in New Issue
Block a user