From fba2dfe2592cc2bdfb8a8cce4a2862a137389e49 Mon Sep 17 00:00:00 2001 From: zawakin Date: Mon, 29 Jun 2026 18:57:59 +0900 Subject: [PATCH] docs: put first move in gw -h and enrich subcommand help Close the two remaining CLI_REVIEW gaps for gw: - Rule 6: -h now shows the first command ("Start here: gw new feature/login"), not just --help, so the on-ramp is in the reflex view. - Rule 14: every subcommand --help gains a description paragraph + Example, matching the now-rich root. Covers home/new/cleanup/status/pause/abandon/ undo/sync/open/await and the worktree pool commands, removing the rich-root / bare-subcommand asymmetry. Each -h stays the compact summary and signals "(see more with '--help')". Co-Authored-By: Claude Opus 4.8 (1M context) --- src/cli.rs | 149 ++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 148 insertions(+), 1 deletion(-) diff --git a/src/cli.rs b/src/cli.rs index 8eeecb7..63cff15 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -4,7 +4,10 @@ use clap::{Parser, Subcommand}; #[derive(Parser)] #[command(name = "gw")] -#[command(about = "Worktree-aware git workflow: branch -> PR -> cleanup, safely.")] +#[command(about = "\ +Worktree-aware git workflow: branch -> PR -> cleanup, safely. + +Start here: gw new feature/login # the full flow is in --help")] #[command(long_about = "\ Worktree-aware git workflow: branch -> PR -> cleanup, safely. @@ -39,42 +42,129 @@ pub struct Cli { #[derive(Subcommand)] pub enum Commands { /// Switch to home branch and sync with origin/main + #[command(long_about = "\ +Switch to your home branch and sync it with origin/main. + +\"home branch\" = the branch a worktree returns to (the main worktree's home is +`main`). Use this instead of `git checkout main`, which conflicts across +worktrees. + +Example: + gw home")] Home, /// Create new branch from origin/main + #[command(long_about = "\ +Create a new branch off a freshly fetched origin/main. + +If you already edited on your home branch, gw new carries those changes onto the +new branch -- nothing is stranded on `main`. + +Example: + gw new feature/add-login")] New { /// Name of the branch to create (e.g., feature/add-login) branch: Option, }, /// Delete merged branch and return to home + #[command(long_about = "\ +Delete a merged branch and return to your home branch. + +Verifies the PR was merged before deleting, then switches home and syncs with +origin/main. Usually run for you by `gw await` -- reach for it directly only to +clean up a leftover branch. + +Example: + gw cleanup # the current branch + gw cleanup feature/old # a specific branch")] Cleanup { /// Branch to delete (defaults to current branch if not on home) branch: Option, }, /// Show current repository state + #[command(long_about = "\ +Show the current repository state and the single next command to run. + +Inspects your working dir, upstream sync, home branch, and PR state, then prints +one `Next:` line -- the engine of the gw workflow. When in doubt, run this. + +Example: + gw status")] Status, /// Pause current work: WIP commit and return to home branch + #[command(long_about = "\ +Pause current work: record a WIP commit, then return to your home branch. + +A safe way to switch tasks mid-change -- the WIP commit travels across worktrees, +unlike `git stash`. Resume later by checking the branch back out. + +Example: + gw pause \"investigating flaky test\"")] Pause { /// Optional message describing why work is paused message: Option, }, /// Abandon current changes and return to home branch + #[command(long_about = "\ +Discard all changes on the current branch and return to your home branch. + +Destructive: both committed and uncommitted work on this branch is thrown away. +Use it when the branch is a dead end. + +Example: + gw abandon")] Abandon, /// Undo the last commit (soft reset HEAD~1) + #[command(long_about = "\ +Undo the last commit, keeping its changes as unstaged edits (soft reset HEAD~1). + +Lets you re-stage or rewrite the most recent commit. Touches history only -- your +working files are left intact. + +Example: + gw undo")] Undo, /// Sync current branch after base PR is merged (update base to main, rebase, force push) + #[command(long_about = "\ +Restack this branch after the PR it was based on merged. + +Updates the PR's base to main on GitHub, rebases onto the latest main, and +force-pushes. Use this instead of hand-rebasing stacked PRs. + +Rewrites history and force-pushes the branch. + +Example: + gw sync")] Sync, /// Open the PR for the current branch in the browser + #[command(long_about = "\ +Open the current branch's PR in your browser. + +The browser command is configured via GW_OPEN_URL_CMD in your dotfiles. + +Example: + gw open")] Open, /// Watch a specific PR until merged or closed, then clean up its branch + #[command(long_about = "\ +Watch a specific PR until it merges or closes, then clean up its branch. + +Takes a PR number (not a branch) so the watcher stays bound to that PR even if +you switch branches. It waits for CI, then -- with --open -- opens the PR, +watches it to merge, and runs `gw cleanup`. If CI fails it stops and reports, so +you can fix, push, and rerun. Launch it in the background right after creating +the PR. + +Example: + gw await 41 --open")] Await { /// PR number to watch (required so the watcher stays bound to one PR /// even if you switch branches, e.g. while working a stacked PR) @@ -103,6 +193,14 @@ pub enum Commands { }, /// Manage worktrees + #[command(long_about = "\ +Manage git worktrees for running parallel work in isolation. + +Subcommands live under `gw worktree pool` -- a pre-warmed set of ready-to-use +worktrees so parallel agents each get their own checkout. + +Example: + gw worktree pool warm 3")] Worktree { #[command(subcommand)] command: WorktreeCommands, @@ -112,6 +210,18 @@ pub enum Commands { #[derive(Subcommand)] pub enum WorktreeCommands { /// Manage a pre-warmed worktree pool + #[command(long_about = "\ +Manage a pre-warmed pool of worktrees for parallel, isolated work. + +Warm the pool once, then acquire a worktree per task and release it when done so +the next task can reuse it. Always release, even on error -- a forgotten release +drains the pool. + +Example: + gw worktree pool warm 3 # pre-create 3 worktrees + gw worktree pool acquire # take one (prints its path) + gw worktree pool release # return it when done + gw worktree pool drain # remove them all")] Pool { #[command(subcommand)] command: PoolCommands, @@ -121,24 +231,61 @@ pub enum WorktreeCommands { #[derive(Subcommand)] pub enum PoolCommands { /// Pre-warm the pool with ready-to-use worktrees + #[command(long_about = "\ +Pre-create worktrees so the pool has `count` ready to acquire. + +Run once before fanning out parallel work. + +Example: + gw worktree pool warm 3")] Warm { /// Target number of available worktrees in the pool count: usize, }, /// Acquire a worktree from the pool (prints path to stdout) + #[command(long_about = "\ +Take a worktree from the pool and print its path to stdout. + +Capture the path and run the task inside it; release it when done. Acquire fails +if the pool is empty -- `gw worktree pool warm ` first. + +Example: + WORKTREE_PATH=$(gw worktree pool acquire)")] Acquire, /// Show pool status + #[command(long_about = "\ +Show how many pool worktrees exist and how many are available to acquire. + +Example: + gw worktree pool status")] Status, /// Release acquired worktree(s) back to the pool + #[command(long_about = "\ +Return an acquired worktree to the pool so it can be reused. + +With no name, releases all worktrees acquired by this process. Always release, +even on error -- a forgotten release drains the pool. + +Example: + gw worktree pool release # all acquired + gw worktree pool release wt-2 # a specific one")] Release { /// Name of the worktree to release (defaults to all acquired) name: Option, }, /// Remove all worktrees and clean up the pool + #[command(long_about = "\ +Remove every pool worktree and tear the pool down. + +Refuses to drain while worktrees are still acquired unless you pass --force. + +Example: + gw worktree pool drain + gw worktree pool drain --force")] Drain { /// Force drain even if worktrees are acquired #[arg(long)]