Skip to content

feat: keep tmux sessions visible when a worktree's HEAD diverges#17

Merged
xico42 merged 2 commits into
mainfrom
feat/checkout-remote
Jun 28, 2026
Merged

feat: keep tmux sessions visible when a worktree's HEAD diverges#17
xico42 merged 2 commits into
mainfrom
feat/checkout-remote

Conversation

@xico42

@xico42 xico42 commented Jun 28, 2026

Copy link
Copy Markdown
Owner

Summary

Keeps a codeherd worktree's tmux session visible in the TUI dashboard and ch list worktree when its HEAD diverges from the branch it was created for — a rebase in progress (detached HEAD) or a different branch checked out.

The dashboard correlated each worktree to its session by the worktree's live git branch. That key breaks the moment HEAD moves off the branch the worktree was created for: the live branch no longer matches the session's frozen canonical name, so a running agent silently disappears from the dashboard and the listing — exactly when the user most needs to find it.

Correlation now keys off a stable identity branch instead:

  • Worktrees under <clone>__worktrees/ → folder base name (the flattened branch the worktree was created for).
  • Main clone dir → configured default branch, falling back to the live branch.

Feeding this identity into SessionName reproduces the session's original name exactly, so the fix works retroactively for sessions that already exist.

The list still shows where HEAD actually points, via a live-state hint: detached mid-rebase, or on <branch> when a different branch is checked out (parsed from the detached line of git worktree list --porcelain). A new @codeherd_branch tmux option records the exact pretty branch at session start and is read back during listing; pre-upgrade sessions without the option fall back to the configured default and then the folder name.

Commits

  • 601fb3d — check out remote branches into tracking worktrees (pre-existing work on this branch).
  • HEAD-divergence session correlation (this change), with design and implementation-plan docs under docs/.

Verification

make check passes — coverage 81.6% (≥ 80% gate), integration tests green, lint clean, build OK. Each layer (semconv, worktree, tmux, session, tui) was built test-first.

🤖 Generated with Claude Code

codeherd could only create worktrees from branches the local clone already
knew about, and creation started from whatever state that clone happened to
be in. Reviewing a teammate's pushed branch meant fetching and adding a
worktree by hand, and even an ordinary new worktree could be based on a
stale default branch.

A new tracking-creation path fetches a remote branch and adds a worktree
whose local branch tracks it. The ref is parsed as [<remote>/]<branch> with
origin as the default, so both "feat-x" and "upstream/feat-x" work while
branch names containing slashes stay intact. When the derived local name
would collide with an existing branch, creation refuses rather than silently
reusing it, and a failed fetch of the requested branch is fatal — there is
nothing to check out.

Every creation path now freshens its source before branching. The fetch is
best-effort and never aborts an ordinary creation, but when a local source
branch exists it is fast-forwarded with --ff-only and used as the base
point, so the worktree reflects current upstream state without ever dropping
un-pushed local commits. Local-only refs, tags and SHAs skip the fetch and
are used verbatim.

On the CLI, create worktree gains --track, mutually exclusive with --from,
and the branch argument becomes optional: when omitted the local name is
derived from the remote branch. Shell completion suggests the project's
remote-tracking branches.

In the TUI, r is rebound from manual refresh to a remote-branch picker. The
dashboard already auto-refreshes every few seconds, so the manual binding
was redundant; r now fetches all remotes and opens a filterable list, and
selecting a branch hands off to the existing create-worktree form,
pre-filled and routed to the tracking path.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@xico42 xico42 force-pushed the feat/checkout-remote branch from 56bd285 to 7dadb68 Compare June 28, 2026 15:04
The TUI dashboard and `ch list worktree` correlated each worktree to its
tmux session by the worktree's live git branch. That key is wrong the
moment HEAD moves off the branch the worktree was created for — a rebase
in progress leaves a detached HEAD, and checking out another branch
swaps the name entirely. In both cases the live branch no longer matches
the session's frozen canonical name, so a running agent silently
disappears from the dashboard and the worktree listing, exactly when the
user most needs to find it.

Correlation now keys off a stable identity branch rather than the live
one. For worktrees under `<clone>__worktrees/` that identity is the
folder base name, which equals the flattened branch the worktree was
created for; for the main clone dir it is the configured default branch,
falling back to the live branch when none is set. Feeding this identity
into SessionName reproduces the session's original name exactly, so the
fix works retroactively for sessions that already exist.

The list still shows where HEAD actually points. A worktree whose HEAD
diverged is annotated with a live-state hint — `detached` mid-rebase, or
`on <branch>` when a different branch is checked out — parsed from the
`detached` line of `git worktree list --porcelain`. To display the real
branch the session belongs to rather than a flattened folder name, a new
`@codeherd_branch` tmux option records the exact pretty branch at session
start and is read back during listing. Pre-upgrade sessions lack that
option, so display falls back to the configured default (clone dir) and
then the folder name.
@xico42 xico42 force-pushed the feat/checkout-remote branch from 7dadb68 to 9f38907 Compare June 28, 2026 15:17
@xico42 xico42 merged commit b51f560 into main Jun 28, 2026
7 checks passed
@xico42 xico42 deleted the feat/checkout-remote branch June 28, 2026 15:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant