Skip to content

feat: grove cd and grove shell-init#25

Merged
rrbe merged 2 commits into
mainfrom
feat/cli-cd
May 20, 2026
Merged

feat: grove cd and grove shell-init#25
rrbe merged 2 commits into
mainfrom
feat/cli-cd

Conversation

@rrbe
Copy link
Copy Markdown
Owner

@rrbe rrbe commented May 20, 2026

Summary

补齐 git worktree 最大的痛点:没法 cd 到 worktree

  • `grove cd [branch]` — 打印目标 worktree 路径。无参回主仓;带参先精确匹配,没中退化到子串包含
  • `grove shell-init <zsh|bash|fish>` — 打印 shell 函数定义。装一次:
    ```bash
    eval "$(grove shell-init zsh)" # 写到 .zshrc
    grove cd feat/login # 真的 cd 过去
    ```

匹配规则:

  • 精确命中 1 个 → 打印路径
  • 精确没中、子串命中 1 个 → 打印路径
  • 多个候选 → 列出候选 + hint,exit 1
  • 零命中 → 友好错误,exit 1

顺手修了一个 latent bug

CLI 路径里 `current_repo_root` 用的是 `git rev-parse --show-toplevel`,在 linked worktree 内调用会返回当前 worktree 而不是主仓。这导致:

  • `scan_worktrees` 的 `is_main` flag 标错(哪个 worktree 是主仓取决于你 cwd 在哪)
  • `grove config` 的 store key 跟主仓 key 不一致
  • `grove new` 在 worktree 里跑会算错 worktree_root

新增 `git::main_worktree_root`(基于 `git rev-parse --git-common-dir`),`current_repo_root` 切到它。所有 CLI 入口现在不管 cwd 在哪都解析到主仓。

测试

  • 单测:`match_branch` × 4(精确优先 / 子串退化 / 多候选 / 零命中)
  • cargo test:38/38 通过(+4 新)
  • clippy:干净
  • 真 zsh shell 端到端:从主仓和从 worktree 内 `grove cd`/`grove cd ` 都正确

CLI 示例

```bash
$ grove cd # 主仓路径
/Users/you/code/grove

$ grove cd login # 子串命中 feat/login
/Users/you/code/grove/.worktrees/login

$ grove cd feat/ # 多候选
error: 'feat/' matches multiple worktrees:
feat/login
feat/oauth
hint: pass the full branch name
```

Test plan

  • cargo test 38/38
  • cargo clippy 干净
  • zsh wrapper 实测:从主仓 cd 到 worktree、从 worktree 内 cd 回主仓、子串模糊命中、多候选报错
  • bash / fish wrapper 实测(语法上对、未在干净 bash/fish 环境实跑)
  • GUI 回归:current_repo_root 改了底层,scan_worktrees 在 GUI 里仍是主仓路径调用(GUI 自己传 repo_root),应该无影响——但 PR 评审时手测一次

🤖 Generated with Claude Code

rrbe and others added 2 commits May 20, 2026 15:14
\`grove cd [branch]\` prints the path of a matching worktree on stdout.
With no argument it picks the main worktree; with one it tries exact
branch match first, then falls back to substring containment. Multiple
matches surface a candidate list on stderr and exit 1.

\`grove shell-init <zsh|bash|fish>\` emits a shell function that wraps
\`grove cd\` so users can actually \`cd\` after \`eval "\$(grove shell-init
zsh)"\` in their rc. Other subcommands fall through to the binary.

Adds \`git::main_worktree_root\` (using \`git rev-parse --git-common-dir\`)
and routes \`current_repo_root\` through it. Previously CLI commands run
from inside a linked worktree resolved to that worktree's path, which
made \`scan_worktrees\` mis-flag \`is_main\` and store keys diverged from
the main repo path. The new helper fixes that latent bug for every CLI
entry point.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
`grove cd` runs on every shell directory change via the shell-init
wrapper, but was calling scan_worktrees — which shells out to gh and
runs ~5 git subprocesses per worktree for status/PR data it never uses.

- Add git::list_worktrees, a porcelain-only helper for branch→path lookup
- Switch cmd_cd to list_worktrees; drop the unneeded store::load_store
- Fold main_worktree_root onto the existing run_git_text helper
- Tighten the multi-match error and drop the manual Debug for MatchOutcome

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@rrbe rrbe merged commit 2294202 into main May 20, 2026
3 checks passed
@rrbe rrbe deleted the feat/cli-cd branch May 20, 2026 09:01
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