fix: Merge worktree conflict when target branch already checked out
Use a temp branch + update-ref to avoid "already checked out" error when merging into the default branch. Also show actual branch name in the Merge & Push button instead of "Default".
This commit is contained in:
@@ -31,19 +31,27 @@ export class SimpleGitBranchManager implements BranchManager {
|
||||
}
|
||||
|
||||
async mergeBranch(repoPath: string, sourceBranch: string, targetBranch: string): Promise<MergeResult> {
|
||||
// Use an ephemeral worktree for merge safety
|
||||
// Use an ephemeral worktree with a temp branch for merge safety.
|
||||
// We can't check out targetBranch directly — it may already be checked out
|
||||
// in the clone's main working tree or an agent worktree.
|
||||
const tmpPath = mkdtempSync(join(tmpdir(), 'cw-merge-'));
|
||||
const repoGit = simpleGit(repoPath);
|
||||
const tempBranch = `cw-merge-${Date.now()}`;
|
||||
|
||||
try {
|
||||
// Create ephemeral worktree on target branch
|
||||
await repoGit.raw(['worktree', 'add', tmpPath, targetBranch]);
|
||||
// Create worktree with a temp branch starting at targetBranch's commit
|
||||
await repoGit.raw(['worktree', 'add', '-b', tempBranch, tmpPath, targetBranch]);
|
||||
|
||||
const wtGit = simpleGit(tmpPath);
|
||||
|
||||
try {
|
||||
await wtGit.merge([sourceBranch, '--no-edit']);
|
||||
|
||||
// Update the real target branch ref to the merge result.
|
||||
// update-ref bypasses the "branch is checked out" guard.
|
||||
const mergeCommit = (await wtGit.revparse(['HEAD'])).trim();
|
||||
await repoGit.raw(['update-ref', `refs/heads/${targetBranch}`, mergeCommit]);
|
||||
|
||||
log.info({ repoPath, sourceBranch, targetBranch }, 'merge completed cleanly');
|
||||
return { success: true, message: `Merged ${sourceBranch} into ${targetBranch}` };
|
||||
} catch (mergeErr) {
|
||||
@@ -73,6 +81,10 @@ export class SimpleGitBranchManager implements BranchManager {
|
||||
try { rmSync(tmpPath, { recursive: true, force: true }); } catch { /* ignore */ }
|
||||
try { await repoGit.raw(['worktree', 'prune']); } catch { /* ignore */ }
|
||||
}
|
||||
// Delete the temp branch
|
||||
try {
|
||||
await repoGit.raw(['branch', '-D', tempBranch]);
|
||||
} catch { /* ignore — may already be cleaned up */ }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -214,7 +214,7 @@ export function InitiativeReview({ initiativeId, onCompleted }: InitiativeReview
|
||||
) : (
|
||||
<GitMerge className="h-3.5 w-3.5" />
|
||||
)}
|
||||
Merge & Push to Default
|
||||
Merge & Push to {targetBranch || "default"}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user