* Destroys a git worktree at the given path. * First attempts to use `git worktree remove`, then falls back to rm -rf. * Safe to call on non-existent paths.
(worktreePath: string)
| 490 | * Safe to call on non-existent paths. |
| 491 | */ |
| 492 | async function destroyWorktree(worktreePath: string): Promise<void> { |
| 493 | // Read the .git file in the worktree to find the main repo |
| 494 | const gitFilePath = join(worktreePath, '.git') |
| 495 | let mainRepoPath: string | null = null |
| 496 | |
| 497 | try { |
| 498 | const gitFileContent = (await readFile(gitFilePath, 'utf-8')).trim() |
| 499 | // The .git file contains something like: gitdir: /path/to/repo/.git/worktrees/worktree-name |
| 500 | const match = gitFileContent.match(/^gitdir:\s*(.+)$/) |
| 501 | if (match && match[1]) { |
| 502 | // Extract the main repo .git directory (go up from .git/worktrees/name to .git) |
| 503 | const worktreeGitDir = match[1] |
| 504 | // Go up 2 levels from .git/worktrees/name to get to .git, then get parent for repo root |
| 505 | const mainGitDir = join(worktreeGitDir, '..', '..') |
| 506 | mainRepoPath = join(mainGitDir, '..') |
| 507 | } |
| 508 | } catch { |
| 509 | // Ignore errors reading .git file (path doesn't exist, not a file, etc.) |
| 510 | } |
| 511 | |
| 512 | // Try to remove using git worktree remove command |
| 513 | if (mainRepoPath) { |
| 514 | const result = await execFileNoThrowWithCwd( |
| 515 | gitExe(), |
| 516 | ['worktree', 'remove', '--force', worktreePath], |
| 517 | { cwd: mainRepoPath }, |
| 518 | ) |
| 519 | |
| 520 | if (result.code === 0) { |
| 521 | logForDebugging( |
| 522 | `[TeammateTool] Removed worktree via git: ${worktreePath}`, |
| 523 | ) |
| 524 | return |
| 525 | } |
| 526 | |
| 527 | // Check if the error is "not a working tree" (already removed) |
| 528 | if (result.stderr?.includes('not a working tree')) { |
| 529 | logForDebugging( |
| 530 | `[TeammateTool] Worktree already removed: ${worktreePath}`, |
| 531 | ) |
| 532 | return |
| 533 | } |
| 534 | |
| 535 | logForDebugging( |
| 536 | `[TeammateTool] git worktree remove failed, falling back to rm: ${result.stderr}`, |
| 537 | ) |
| 538 | } |
| 539 | |
| 540 | // Fallback: manually remove the directory |
| 541 | try { |
| 542 | await rm(worktreePath, { recursive: true, force: true }) |
| 543 | logForDebugging( |
| 544 | `[TeammateTool] Removed worktree directory manually: ${worktreePath}`, |
| 545 | ) |
| 546 | } catch (error) { |
| 547 | logForDebugging( |
| 548 | `[TeammateTool] Failed to remove worktree ${worktreePath}: ${errorMessage(error)}`, |
| 549 | ) |
no test coverage detected