Skip to content

lich open --worktree fails when the target branch already exists locally #334

Closed

Description

@johnathancruz

What happened

lich open --worktree always attempts to create the requested branch with git worktree add -b, so it fails when the branch was deliberately created before opening the lich worktree.

This blocks workflows where a branch must first be created from an updated remote base and linked to a GitHub issue before a coding session starts.

Reproduction

From a clean repository on main:

git fetch origin main
git branch issue-4-etapa-40-decidir-ownership-e-credencial-de-migration origin/main
lich open --project elan-app --kind claude \
  --worktree issue-4-etapa-40-decidir-ownership-e-credencial-de-migration \
  --base origin/main \
  --json

Observed output:

lich: A branch or worktree with that name already exists.

Relevant reviewed log lines:

level=WARN source=github.com/omartelo/lich/internal/project/toolerror.go:45 msg="git failed" command="worktree add --track -b issue-4-etapa-40-decidir-ownership-e-credencial-de-migration -- /Users/johnathan/.local/share/lich/worktrees/698322dd0b0f/issue-4-etapa-40-decidir-ownership-e-credencial-de-migration origin/main" err="exit status 255" stderr="Preparing worktree (new branch issue-4-etapa-40-decidir-ownership-e-credencial-de-migration)\nfatal: a branch named issue-4-etapa-40-decidir-ownership-e-credencial-de-migration already exists"
level=WARN source=github.com/omartelo/lich/internal/rpc/rpc.go:145 msg="rpc: call failed" method=spawn.Open err="A branch or worktree with that name already exists."

git worktree list --porcelain confirmed that the branch was not checked out in another worktree. lich worktrees --project elan-app --json returned [].

Expected behavior

When the named local branch exists and is not attached to another worktree, lich should create the worktree using that existing branch, equivalent to:

git worktree add <lich-worktree-path> issue-4-etapa-40-decidir-ownership-e-credencial-de-migration

If reusing an existing branch is intentionally unsupported, the CLI should expose an explicit mode/flag for it. Deleting the branch first is risky here: the remote issue branch already exists, while the current --base origin/main path recreates a local branch tracking origin/main rather than clearly attaching to the linked issue branch.

The command failed before creating a worktree or Claude session. Cleanup required deleting the local and remote attempt and restoring the project card state.

lich version

0.38.0

Platform

darwin/arm64 — macOS 27.0 (Build 26A5406e)

Additional environment:

  • Git 2.47.1
  • GitHub CLI 2.92.0
  • lich doctor: all applicable checks passed; running lich listener and Claude/Codex providers were detected

Log

The relevant sanitized lines are included above. No session token or secret is present.

Activity

  1. self-assigned this
    on Aug 21, 2026
  2. omartelo commented on Aug 21, 2026

    @omartelo
    Collaborator

    Thank you for this — the report had everything needed to land on the cause without a single follow-up question: the exact commands, the git worktree list --porcelain check that ruled out another checkout, and the raw command= line from the log. That last one is what made it a five-minute diagnosis.

    Reproduced locally, and the cause is exactly where your log points. CreateWorktree built every call as git worktree add -b <name>, unconditionally. -b means create the branch, so git refuses a name it already knows — regardless of whether the branch is free, which is why your worktree list came back clean and the failure still stood.

    Your expected behavior is what it now does: an existing branch is checked out as it stands, git worktree add <path> <branch>. No new flag. Naming a branch is naming the work on it, and lich already read it that way for a branch that holds a worktree — it just did not extend that to a branch that merely exists. The fix covers all three surfaces, since the New worktree dialog, lich open --worktree and the open_session MCP tool all route through the same function.

    One consequence worth stating plainly, because it is a real trade-off: when the named branch already exists, --base is ignored. It says where a branch starts, and yours had already started. So your invocation now attaches to the linked issue branch rather than recreating one off origin/main — the ambiguity you flagged at the end of the report.

    Your report also turned up a second bug. Reusing an existing branch makes a git failure reachable that this path could never hit before — the branch being held by another checkout — and git reworded that message in 2.36, from is already checked out at to is already used by worktree at. lich only knew the old wording, so on any current git that case fell through to the unhelpful "git could not complete the operation." Fixed in the same change.

    Fix is up in #335, with a regression test that replicates your exact invocation — prepared branch plus --base origin/main. It will go out in the next release.

    Sorry about the cleanup you had to do on the local and remote branch.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

bugSomething is broken

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions