Skip to content

Commit d6ffe23

Browse files
committed
Refactor: Reorder 'wt pr' steps to avoid checkout conflict
1 parent 38083ae commit d6ffe23

1 file changed

Lines changed: 38 additions & 19 deletions

File tree

src/commands/pr.ts

Lines changed: 38 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -65,14 +65,8 @@ export async function prWorktreeHandler(
6565
} catch (ghError: any) {
6666
if (ghError.stderr?.includes("is already checked out")) {
6767
console.log(chalk.yellow(`Branch "${prBranchName}" for PR #${prNumber} is already checked out.`));
68-
// Attempt to switch to it to ensure tracking is potentially updated by gh
69-
try {
70-
await execa("git", ["checkout", prBranchName], { stdio: 'pipe' });
71-
} catch (checkoutError: any) {
72-
// If checkout fails (e.g., uncommitted changes), gh pr checkout would likely have failed too.
73-
// Rethrow the original gh error as it's more informative.
74-
throw ghError;
75-
}
68+
// It's already checked out, we might not need to switch, but ensure tracking is set
69+
// 'gh pr checkout' likely handled tracking. We'll proceed.
7670
} else if (ghError.stderr?.includes("Could not find pull request")) {
7771
throw new Error(`Pull Request #${prNumber} not found.`);
7872
} else if (ghError.stderr?.includes("gh not found") || ghError.message?.includes("ENOENT")) {
@@ -83,6 +77,25 @@ export async function prWorktreeHandler(
8377
}
8478
}
8579

80+
// 4.5 Switch back to original branch IMMEDIATELY after gh checkout ensures the main worktree is clean
81+
if (originalBranch) {
82+
try {
83+
const currentBranchAfterGh = await getCurrentBranch();
84+
if (currentBranchAfterGh === prBranchName && currentBranchAfterGh !== originalBranch) {
85+
console.log(chalk.blue(`Switching main worktree back to "${originalBranch}" before creating worktree...`));
86+
await execa("git", ["checkout", originalBranch]);
87+
} else if (currentBranchAfterGh !== originalBranch) {
88+
console.log(chalk.yellow(`Current branch is ${currentBranchAfterGh}, not ${prBranchName}. Assuming gh handled checkout correctly.`));
89+
// If gh failed but left us on a different branch, still try to go back
90+
await execa("git", ["checkout", originalBranch]);
91+
}
92+
} catch (checkoutError: any) {
93+
console.warn(chalk.yellow(`⚠️ Warning: Failed to switch main worktree back to original branch "${originalBranch}" after gh checkout. Please check manually.`));
94+
console.warn(checkoutError.stderr || checkoutError.message);
95+
// Proceed with caution, worktree add might fail
96+
}
97+
}
98+
8699
// 5. Build final path for the new worktree
87100
let folderName: string;
88101
if (options.path) {
@@ -127,19 +140,21 @@ export async function prWorktreeHandler(
127140
process.exit(1);
128141
}
129142
} else {
130-
// 7. Create the worktree using the locally checked-out PR branch
143+
// 7. Create the worktree using the PR branch (now only fetched/tracked, not checked out here)
131144
console.log(chalk.blue(`Creating new worktree for branch "${prBranchName}" at: ${resolvedPath}`));
132145
try {
133-
// Use the PR branch name which 'gh pr checkout' created/updated locally
146+
// Use the PR branch name which 'gh pr checkout' fetched/tracked locally
134147
await execa("git", ["worktree", "add", resolvedPath, prBranchName]);
135148
worktreeCreated = true;
136149
} catch (worktreeError: any) {
137-
console.error(chalk.red(`Failed to create worktree for branch "${prBranchName}" at ${resolvedPath}:`), worktreeError.stderr || worktreeError.message);
138-
// Common error: branch checked out elsewhere (shouldn't happen with this flow ideally, but check)
139-
if (worktreeError.stderr?.includes("is already checked out at")) {
140-
console.error(chalk.red(`Branch "${prBranchName}" might be checked out in another worktree.`));
150+
// The "already checked out" error should ideally not happen with the new flow.
151+
// Handle other potential worktree add errors.
152+
console.error(chalk.red(`❌ Failed to create worktree for branch "${prBranchName}" at ${resolvedPath}:`), worktreeError.stderr || worktreeError.message);
153+
// Suggest checking if the branch exists locally if it fails
154+
if (worktreeError.stderr?.includes("fatal:")) {
155+
console.error(chalk.cyan(` Suggestion: Verify branch "${prBranchName}" exists locally ('git branch') and the path "${resolvedPath}" is valid and empty.`));
141156
}
142-
throw worktreeError; // Rethrow to trigger finally block and cleanup
157+
throw worktreeError; // Rethrow to trigger main catch block and cleanup
143158
}
144159

145160
// 8. (Optional) Install dependencies
@@ -179,17 +194,21 @@ export async function prWorktreeHandler(
179194
}
180195
process.exit(1);
181196
} finally {
182-
// 10. Switch back to the original branch in the main worktree
197+
// 10. Ensure we are back on the original branch in the main worktree
198+
// This is now mostly a safeguard, as we attempted to switch back earlier.
183199
if (originalBranch) {
184200
try {
185201
const currentBranchNow = await getCurrentBranch();
186202
if (currentBranchNow !== originalBranch) {
187-
console.log(chalk.blue(`Switching main worktree back to "${originalBranch}"...`));
203+
console.log(chalk.blue(`Ensuring main worktree is back on "${originalBranch}"...`));
188204
await execa("git", ["checkout", originalBranch]);
189205
}
190206
} catch (checkoutError: any) {
191-
console.warn(chalk.yellow(`⚠️ Warning: Failed to switch main worktree back to original branch "${originalBranch}". Please check manually.`));
192-
console.warn(checkoutError.stderr || checkoutError.message);
207+
// Don't warn again if the previous attempt already warned
208+
if (!checkoutError.message.includes("already warned")) { // Avoid redundant warnings
209+
console.warn(chalk.yellow(`⚠️ Warning: Final check failed to switch main worktree back to original branch "${originalBranch}". Please check manually.`));
210+
console.warn(checkoutError.stderr || checkoutError.message);
211+
}
193212
}
194213
}
195214
}

0 commit comments

Comments
 (0)