git_worktree_manager/cli.rs
1/// CLI definitions using clap derive.
2///
3/// Mirrors the Typer-based CLI in src/git_worktree_manager/cli.py.
4pub mod completions;
5pub mod global;
6
7use clap::{Parser, Subcommand, ValueHint};
8
9/// Git worktree manager CLI.
10#[derive(Parser, Debug)]
11#[command(
12 name = "gw",
13 version,
14 about = "git worktree manager — AI coding assistant integration",
15 long_about = None,
16 arg_required_else_help = true,
17)]
18pub struct Cli {
19 /// Run in global mode (across all registered repositories)
20 #[arg(short = 'g', long = "global", global = true)]
21 pub global: bool,
22
23 #[command(subcommand)]
24 pub command: Option<Commands>,
25}
26
27#[derive(Subcommand, Debug)]
28pub enum Commands {
29 /// Create new worktree for feature branch
30 New {
31 /// Branch name for the new worktree
32 name: String,
33
34 /// Custom worktree path (default: ../<repo>-<branch>)
35 #[arg(short, long, value_hint = ValueHint::DirPath)]
36 path: Option<String>,
37
38 /// Base branch to create from (default: from config)
39 #[arg(short, long)]
40 branch: Option<String>,
41
42 /// Force creation even if branch exists
43 #[arg(short, long)]
44 force: bool,
45
46 /// Skip AI tool launch
47 #[arg(long)]
48 no_ai: bool,
49
50 /// Terminal launch method (e.g., tmux, iterm-tab, zellij)
51 #[arg(long)]
52 term: Option<String>,
53
54 /// Launch AI tool in background
55 #[arg(long)]
56 bg: bool,
57 },
58
59 /// Create GitHub Pull Request from worktree
60 Pr {
61 /// Branch name (default: current worktree branch)
62 branch: Option<String>,
63
64 /// PR title
65 #[arg(short, long)]
66 title: Option<String>,
67
68 /// PR body
69 #[arg(short, long)]
70 body: Option<String>,
71
72 /// Create as draft PR
73 #[arg(short, long)]
74 draft: bool,
75
76 /// Skip pushing to remote
77 #[arg(long)]
78 no_push: bool,
79 },
80
81 /// Merge feature branch into base branch
82 Merge {
83 /// Branch name (default: current worktree branch)
84 branch: Option<String>,
85
86 /// Interactive rebase
87 #[arg(short, long)]
88 interactive: bool,
89
90 /// Dry run (show what would happen)
91 #[arg(long)]
92 dry_run: bool,
93
94 /// Push to remote after merge
95 #[arg(long)]
96 push: bool,
97 },
98
99 /// Resume AI work in a worktree
100 Resume {
101 /// Branch name to resume (default: current worktree)
102 branch: Option<String>,
103
104 /// Terminal launch method
105 #[arg(long)]
106 term: Option<String>,
107
108 /// Launch AI tool in background
109 #[arg(long)]
110 bg: bool,
111 },
112
113 /// Open interactive shell or execute command in a worktree
114 Shell {
115 /// Worktree branch to shell into
116 worktree: Option<String>,
117
118 /// Command and arguments to execute
119 #[arg(trailing_var_arg = true, allow_hyphen_values = true)]
120 args: Vec<String>,
121 },
122
123 /// Show current worktree status
124 Status,
125
126 /// Delete a worktree
127 Delete {
128 /// Branch name or path of worktree to delete
129 target: String,
130
131 /// Keep the branch (only remove worktree)
132 #[arg(long)]
133 keep_branch: bool,
134
135 /// Also delete the remote branch
136 #[arg(long)]
137 delete_remote: bool,
138
139 /// Don't use --force flag
140 #[arg(long)]
141 no_force: bool,
142 },
143
144 /// List all worktrees
145 #[command(alias = "ls")]
146 List,
147
148 /// Batch cleanup of worktrees
149 Clean {
150 /// Delete worktrees for branches already merged to base
151 #[arg(long)]
152 merged: bool,
153
154 /// Delete worktrees older than N days
155 #[arg(long, value_name = "DAYS")]
156 older_than: Option<u64>,
157
158 /// Interactive selection UI
159 #[arg(short, long)]
160 interactive: bool,
161
162 /// Show what would be deleted without deleting
163 #[arg(long)]
164 dry_run: bool,
165 },
166
167 /// Display worktree hierarchy as a tree
168 Tree,
169
170 /// Show worktree statistics
171 Stats,
172
173 /// Compare two branches
174 Diff {
175 /// First branch
176 branch1: String,
177 /// Second branch
178 branch2: String,
179 /// Show statistics only
180 #[arg(long)]
181 summary: bool,
182 /// Show changed files only
183 #[arg(long)]
184 files: bool,
185 },
186
187 /// Sync worktree with base branch
188 Sync {
189 /// Branch name (default: current worktree)
190 branch: Option<String>,
191
192 /// Sync all worktrees
193 #[arg(long)]
194 all: bool,
195
196 /// Only fetch updates without rebasing
197 #[arg(long)]
198 fetch_only: bool,
199 },
200
201 /// Change base branch for a worktree
202 ChangeBase {
203 /// New base branch
204 new_base: String,
205 /// Branch name (default: current worktree)
206 branch: Option<String>,
207
208 /// Dry run (show what would happen)
209 #[arg(long)]
210 dry_run: bool,
211 },
212
213 /// Configuration management
214 Config {
215 #[command(subcommand)]
216 action: ConfigAction,
217 },
218
219 /// Backup and restore worktrees
220 Backup {
221 #[command(subcommand)]
222 action: BackupAction,
223 },
224
225 /// Stash management (worktree-aware)
226 Stash {
227 #[command(subcommand)]
228 action: StashAction,
229 },
230
231 /// Manage lifecycle hooks
232 Hook {
233 #[command(subcommand)]
234 action: HookAction,
235 },
236
237 /// Export worktree configuration to a file
238 Export {
239 /// Output file path
240 #[arg(short, long)]
241 output: Option<String>,
242 },
243
244 /// Import worktree configuration from a file
245 Import {
246 /// Path to the configuration file to import
247 import_file: String,
248
249 /// Apply the imported configuration (default: preview only)
250 #[arg(long)]
251 apply: bool,
252 },
253
254 /// Scan for repositories (global mode)
255 Scan,
256
257 /// Clean up stale registry entries (global mode)
258 Prune,
259
260 /// Run diagnostics
261 Doctor,
262
263 /// Check for updates / upgrade
264 Upgrade,
265
266 /// Interactive shell integration setup
267 ShellSetup,
268
269 /// [Internal] Get worktree path for a branch
270 #[command(name = "_path", hide = true)]
271 Path {
272 /// Branch name
273 branch: Option<String>,
274
275 /// List branch names (for tab completion)
276 #[arg(long)]
277 list_branches: bool,
278
279 /// Interactive worktree selection
280 #[arg(short, long)]
281 interactive: bool,
282 },
283
284 /// Generate shell function for cw-cd
285 #[command(name = "_shell-function", hide = true)]
286 ShellFunction {
287 /// Shell type: bash, zsh, or fish
288 shell: String,
289 },
290}
291
292#[derive(Subcommand, Debug)]
293pub enum ConfigAction {
294 /// Show current configuration
295 Show,
296 /// Set a configuration value
297 Set {
298 /// Dot-separated config key (e.g., git.default_base_branch)
299 key: String,
300 /// Value to set
301 value: String,
302 },
303 /// Use a predefined AI tool preset
304 UsePreset {
305 /// Preset name (e.g., claude, codex, no-op)
306 name: String,
307 },
308 /// List available presets
309 ListPresets,
310 /// Reset configuration to defaults
311 Reset,
312}
313
314#[derive(Subcommand, Debug)]
315pub enum BackupAction {
316 /// Create backup of worktree(s) using git bundle
317 Create {
318 /// Branch name to backup (default: current worktree)
319 branch: Option<String>,
320
321 /// Backup all worktrees
322 #[arg(long)]
323 all: bool,
324
325 /// Output directory for backups
326 #[arg(short, long)]
327 output: Option<String>,
328 },
329 /// List available backups
330 List {
331 /// Filter by branch name
332 branch: Option<String>,
333 },
334 /// Restore worktree from backup
335 Restore {
336 /// Branch name to restore
337 branch: String,
338
339 /// Custom path for restored worktree
340 #[arg(short, long)]
341 path: Option<String>,
342 },
343}
344
345#[derive(Subcommand, Debug)]
346pub enum StashAction {
347 /// Save changes in current worktree to stash
348 Save {
349 /// Optional message to describe the stash
350 message: Option<String>,
351 },
352 /// List all stashes organized by worktree/branch
353 List,
354 /// Apply a stash to a different worktree
355 Apply {
356 /// Branch name of worktree to apply stash to
357 target_branch: String,
358
359 /// Stash reference (default: stash@{0})
360 #[arg(short, long, default_value = "stash@{0}")]
361 stash: String,
362 },
363}
364
365#[derive(Subcommand, Debug)]
366pub enum HookAction {
367 /// Add a new hook for an event
368 Add {
369 /// Hook event (e.g., worktree.post_create, merge.pre)
370 event: String,
371 /// Shell command to execute
372 command: String,
373 /// Custom hook identifier
374 #[arg(long)]
375 id: Option<String>,
376 /// Human-readable description
377 #[arg(short, long)]
378 description: Option<String>,
379 },
380 /// Remove a hook
381 Remove {
382 /// Hook event
383 event: String,
384 /// Hook identifier to remove
385 hook_id: String,
386 },
387 /// List all hooks
388 List {
389 /// Filter by event
390 event: Option<String>,
391 },
392 /// Enable a disabled hook
393 Enable {
394 /// Hook event
395 event: String,
396 /// Hook identifier
397 hook_id: String,
398 },
399 /// Disable a hook without removing it
400 Disable {
401 /// Hook event
402 event: String,
403 /// Hook identifier
404 hook_id: String,
405 },
406 /// Manually run all hooks for an event
407 Run {
408 /// Hook event to run
409 event: String,
410 /// Show what would be executed without running
411 #[arg(long)]
412 dry_run: bool,
413 },
414}