Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 10 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -166,11 +166,12 @@ wtp add feature/remote-only

# If branch exists in multiple remotes, shows helpful error:
# Error: branch 'feature/shared' exists in multiple remotes: origin, upstream
# Please specify the remote explicitly (e.g., --track origin/feature/shared)
# Create a local branch for the remote you want, then run wtp add again
wtp add feature/shared

# Explicitly specify which remote to track
wtp add -b feature/shared upstream/feature/shared
# Example manual disambiguation:
git branch --track feature/shared upstream/feature/shared
wtp add feature/shared
```

### Management Commands
Expand Down Expand Up @@ -409,7 +410,12 @@ wtp provides clear error messages:
Error: branch 'nonexistent' not found in local or remote branches

# Multiple remotes have same branch
Error: branch 'feature' exists in multiple remotes: origin, upstream. Please specify remote explicitly
Error: branch 'feature' exists in multiple remotes: origin, upstream

Solution: Create a local tracking branch for the remote you want without checking it out, then run wtp add again.
• git branch --track feature origin/feature
• git branch --track feature upstream/feature
• wtp add feature

# Worktree already exists
Error: failed to create worktree: exit status 128
Expand Down
64 changes: 30 additions & 34 deletions cmd/wtp/add.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,15 @@ import (
wtpio "github.com/satococoa/wtp/v2/internal/io"
)

const addUsageText = "wtp add <existing-branch> [--quiet]\n" +
" wtp add -b <new-branch> [<commit>] [--quiet]"

// NewAddCommand creates the add command definition
func NewAddCommand() *cli.Command {
return &cli.Command{
Name: "add",
Usage: "Create a new worktree",
UsageText: "wtp add <existing-branch>\n" +
" wtp add -b <new-branch> [<commit>]\n" +
" wtp add -b <new-branch> --quiet",
Name: "add",
Usage: "Create a new worktree",
UsageText: addUsageText,
Description: "Creates a new worktree for the specified branch. If the branch doesn't exist locally " +
"but exists on a remote, it will be automatically tracked.\n\n" +
"Examples:\n" +
Expand Down Expand Up @@ -190,7 +191,6 @@ func buildWorktreeCommand(
Branch: cmd.String("branch"),
}

// Use resolved track if provided
if resolvedTrack != "" {
opts.Track = resolvedTrack
}
Expand All @@ -199,11 +199,11 @@ func buildWorktreeCommand(

// Handle different argument patterns based on flags
if resolvedTrack != "" {
// When using resolved tracking, the commitish is the remote branch
// When tracking, the commitish is the remote branch reference.
commitish = resolvedTrack
// If there's an argument, it's the local branch name (not used as commitish)
if cmd.Args().Len() > 0 && opts.Branch == "" {
// The first argument is the branch name when using resolved tracking without -b
// The first argument is the local branch name when using tracking without -b.
opts.Branch = cmd.Args().Get(0)
}
} else if cmd.Args().Len() > 0 {
Expand Down Expand Up @@ -249,10 +249,10 @@ func analyzeGitWorktreeError(workTreePath, branchName string, gitError error, gi
}
}

if isMultipleBranchesError(errorOutput) {
return &MultipleBranchesError{
BranchName: branchName,
GitError: gitError,
if isAmbiguousReferenceError(errorOutput) {
return &AmbiguousReferenceError{
Reference: branchName,
GitError: gitError,
}
}

Expand Down Expand Up @@ -307,8 +307,10 @@ func isPathAlreadyExistsError(errorOutput string) bool {
return strings.Contains(errorOutput, "already exists")
}

func isMultipleBranchesError(errorOutput string) bool {
return strings.Contains(errorOutput, "more than one remote") || strings.Contains(errorOutput, "ambiguous")
func isAmbiguousReferenceError(errorOutput string) bool {
return strings.Contains(errorOutput, "matched multiple branches") ||
strings.Contains(errorOutput, "ambiguous argument") ||
strings.Contains(errorOutput, "is ambiguous")
}

func isInvalidPathError(errorOutput, workTreePath, gitOutput string) bool {
Expand All @@ -333,7 +335,6 @@ func (e *WorktreeAlreadyExistsError) Error() string {
The branch '%s' is already checked out in another worktree.

Solutions:
• Use '--force' flag to allow multiple checkouts
• Choose a different branch
• Remove the existing worktree first

Expand Down Expand Up @@ -371,27 +372,29 @@ func (e *PathAlreadyExistsError) Error() string {
The target directory already exists and is not empty.

Solutions:
• Use --force flag to overwrite existing directory
• Remove the existing directory
• Use a different branch name

Original error: %v`, e.Path, e.GitError)
}

// MultipleBranchesError reports that a branch name resolves to multiple remotes and needs disambiguation.
type MultipleBranchesError struct {
BranchName string
GitError error
// AmbiguousReferenceError indicates that git could not uniquely resolve the requested ref.
type AmbiguousReferenceError struct {
Reference string
GitError error
}

func (e *MultipleBranchesError) Error() string {
return fmt.Sprintf(`branch '%s' exists in multiple remotes
func (e *AmbiguousReferenceError) Error() string {
return fmt.Sprintf(`reference '%s' is ambiguous

The git command matched more than one branch or revision for '%s'.

Use the --track flag to specify which remote to use:
• wtp add --track origin/%s %s
• wtp add --track upstream/%s %s
Suggestions:
• Use a specific local branch name
• Use an exact commit SHA
• If you need a remote branch, create a local tracking branch first with 'git branch --track %s <remote>/%s'

Original error: %v`, e.BranchName, e.BranchName, e.BranchName, e.BranchName, e.BranchName, e.GitError)
Original error: %v`, e.Reference, e.Reference, e.Reference, e.Reference, e.GitError)
}

func executePostCreateHooks(w io.Writer, cfg *config.Config, repoPath, workTreePath string) error {
Expand Down Expand Up @@ -467,7 +470,7 @@ func executePostCreateCommand(

func validateAddInput(cmd *cli.Command) error {
if cmd.Args().Len() == 0 && cmd.String("branch") == "" {
return errors.BranchNameRequired("wtp add <existing-branch> | -b <new-branch> [<commit>]")
return errors.BranchNameRequired(addUsageText)
}

return nil
Expand Down Expand Up @@ -674,13 +677,6 @@ func resolveBranchTracking(
// Check if branch exists locally or in remotes
resolvedBranch, isRemote, err := repo.ResolveBranch(branchName)
if err != nil {
// Check if it's a multiple branches error
if strings.Contains(err.Error(), "exists in multiple remotes") {
return "", &MultipleBranchesError{
BranchName: branchName,
GitError: err,
}
}
return "", err
}

Expand Down
Loading
Loading