CreateWorktree creates a branch from the default branch and adds a worktree at the given path. If the worktree path already exists and is a valid worktree on the expected branch, it is reused. If the worktree path exists but is stale (wrong branch or invalid), it is removed and recreated.
(repoDir, worktreePath, branch string)
| 49 | // If the worktree path already exists and is a valid worktree on the expected branch, it is reused. |
| 50 | // If the worktree path exists but is stale (wrong branch or invalid), it is removed and recreated. |
| 51 | func CreateWorktree(repoDir, worktreePath, branch string) error { |
| 52 | absWorktreePath, err := filepath.Abs(worktreePath) |
| 53 | if err != nil { |
| 54 | return fmt.Errorf("failed to resolve worktree path: %w", err) |
| 55 | } |
| 56 | |
| 57 | // Check if the path already exists as a worktree |
| 58 | if IsWorktree(absWorktreePath) { |
| 59 | // Check if it's on the expected branch |
| 60 | currentBranch, err := GetCurrentBranch(absWorktreePath) |
| 61 | if err == nil && currentBranch == branch { |
| 62 | // Valid worktree on the expected branch, reuse it |
| 63 | return nil |
| 64 | } |
| 65 | // Stale worktree (wrong branch or invalid), remove and recreate |
| 66 | if err := RemoveWorktree(repoDir, absWorktreePath); err != nil { |
| 67 | return fmt.Errorf("failed to remove stale worktree: %w", err) |
| 68 | } |
| 69 | } |
| 70 | |
| 71 | defaultBranch, err := GetDefaultBranch(repoDir) |
| 72 | if err != nil { |
| 73 | return fmt.Errorf("failed to detect default branch: %w", err) |
| 74 | } |
| 75 | |
| 76 | // Create the branch from the default branch if it doesn't exist |
| 77 | exists, err := BranchExists(repoDir, branch) |
| 78 | if err != nil { |
| 79 | return fmt.Errorf("failed to check branch existence: %w", err) |
| 80 | } |
| 81 | if !exists { |
| 82 | cmd := exec.Command("git", "branch", branch, defaultBranch) |
| 83 | cmd.Dir = repoDir |
| 84 | if out, err := cmd.CombinedOutput(); err != nil { |
| 85 | return fmt.Errorf("failed to create branch %s: %s", branch, strings.TrimSpace(string(out))) |
| 86 | } |
| 87 | } |
| 88 | |
| 89 | // Add the worktree |
| 90 | cmd := exec.Command("git", "worktree", "add", absWorktreePath, branch) |
| 91 | cmd.Dir = repoDir |
| 92 | if out, err := cmd.CombinedOutput(); err != nil { |
| 93 | return fmt.Errorf("failed to add worktree: %s", strings.TrimSpace(string(out))) |
| 94 | } |
| 95 | |
| 96 | return nil |
| 97 | } |
| 98 | |
| 99 | // RemoveWorktree removes a git worktree at the given path. |
| 100 | func RemoveWorktree(repoDir, worktreePath string) error { |