* Remove a worktree. If the worktree does not exist, this is a no-op.
(worktreePath: string)
| 274 | * Remove a worktree. If the worktree does not exist, this is a no-op. |
| 275 | */ |
| 276 | async remove(worktreePath: string): Promise<WorktreeRemoveResult> { |
| 277 | const targetPath = path.resolve(worktreePath); |
| 278 | const managed = await this.isManagedWorktreePath(targetPath); |
| 279 | const pathExists = await this.pathExists(targetPath); |
| 280 | |
| 281 | if (!pathExists) { |
| 282 | // Worktree directory doesn't exist — run prune to clean up stale refs, then return |
| 283 | await this.prune(); |
| 284 | return { status: 'missing', path: targetPath, managed }; |
| 285 | } |
| 286 | |
| 287 | const worktrees = await this.listWorktrees(); |
| 288 | const registered = await this.isRegisteredWorktreePath(targetPath, worktrees); |
| 289 | if (!registered) { |
| 290 | return this.removeUnregisteredPath(targetPath, managed, worktrees); |
| 291 | } |
| 292 | |
| 293 | try { |
| 294 | await execGit(this.repoPath, ['worktree', 'remove', targetPath, '--force']); |
| 295 | return { status: 'removed', path: targetPath, managed }; |
| 296 | } catch (err) { |
| 297 | // Re-check Git's registry instead of matching localized stderr text. |
| 298 | let stillRegistered = true; |
| 299 | try { |
| 300 | stillRegistered = await this.isRegisteredWorktreePath(targetPath); |
| 301 | } catch { |
| 302 | throw err; |
| 303 | } |
| 304 | |
| 305 | if (stillRegistered) { |
| 306 | throw err; |
| 307 | } |
| 308 | } |
| 309 | |
| 310 | const stillExists = await this.pathExists(targetPath); |
| 311 | if (!stillExists) { |
| 312 | await this.prune(); |
| 313 | return { status: 'missing', path: targetPath, managed }; |
| 314 | } |
| 315 | |
| 316 | return this.removeUnregisteredPath(targetPath, managed, await this.listWorktrees()); |
| 317 | } |
| 318 | |
| 319 | /** |
| 320 | * Ensure a worktree exists for an existing branch. If the worktree directory |
no test coverage detected