1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
//! CLI argument definitions using clap
use clap::{Parser, Subcommand};
use clap_complete::Shell;
#[derive(Parser)]
#[command(name = "deadbranch")]
#[command(author, version, about = "Clean up stale git branches safely", long_about = None)]
#[command(propagate_version = true)]
pub struct Cli {
#[command(subcommand)]
pub command: Commands,
}
#[derive(Subcommand)]
pub enum Commands {
/// List stale branches
List {
/// Only show branches older than N days (default: from config or 30)
#[arg(short, long)]
days: Option<u32>,
/// Only show local branches
#[arg(long)]
local: bool,
/// Only show remote branches
#[arg(long, conflicts_with = "local")]
remote: bool,
/// Only show merged branches
#[arg(long)]
merged: bool,
},
/// Delete stale branches (merged only by default, use --force for unmerged)
Clean {
/// Only delete branches older than N days (default: from config or 30)
#[arg(short, long)]
days: Option<u32>,
/// Only delete merged branches (this is the default behavior)
#[arg(long)]
merged: bool,
/// Force delete unmerged branches (dangerous!)
#[arg(long)]
force: bool,
/// Show what would be deleted without doing it
#[arg(long)]
dry_run: bool,
/// Only delete local branches
#[arg(long)]
local: bool,
/// Only delete remote branches
#[arg(long, conflicts_with = "local")]
remote: bool,
/// Skip confirmation prompts (useful for scripts)
#[arg(short, long)]
yes: bool,
},
/// Manage configuration
Config {
#[command(subcommand)]
action: ConfigAction,
},
/// Manage backups
Backup {
#[command(subcommand)]
action: BackupAction,
},
/// Show repository branch statistics
Stats {
/// Treat branches older than N days as stale (default: from config or 30)
#[arg(short, long)]
days: Option<u32>,
},
/// Generate shell completion scripts
Completions {
/// Shell to generate completions for
shell: Shell,
},
}
#[derive(Subcommand)]
pub enum ConfigAction {
/// Set a configuration value
Set {
/// Configuration key (e.g., default-days, protected-branches, default-branch, exclude-patterns)
key: String,
/// Configuration value(s) - use multiple arguments for lists
/// Example: config set exclude-patterns "wip/*" "draft/*" "temp/*"
#[arg(required = true, num_args = 1..)]
values: Vec<String>,
},
/// Show current configuration
Show,
/// Open config file in $EDITOR
Edit,
/// Reset configuration to defaults
Reset,
}
#[derive(Subcommand)]
pub enum BackupAction {
/// List available backups
List {
/// Only show backups for current repository
#[arg(long, conflicts_with = "repo")]
current: bool,
/// Show backups for a specific repository by name
#[arg(long)]
repo: Option<String>,
},
/// Restore a branch from backup
Restore {
/// Name of the branch to restore
branch: String,
/// Restore from a specific backup file (defaults to most recent)
#[arg(long)]
from: Option<String>,
/// Restore with a different branch name
#[arg(long, value_name = "NAME")]
r#as: Option<String>,
/// Overwrite existing branch if it exists
#[arg(long)]
force: bool,
},
/// Show backup storage statistics
Stats,
/// Remove old backups, keeping the most recent ones
Clean {
/// Clean backups for current repository
#[arg(long, conflicts_with = "repo", required_unless_present = "repo")]
current: bool,
/// Clean backups for a specific repository by name
#[arg(long, required_unless_present = "current")]
repo: Option<String>,
/// Number of most recent backups to keep (default: 10)
#[arg(long, default_value = "10")]
keep: usize,
/// Show what would be deleted without doing it
#[arg(long)]
dry_run: bool,
/// Skip confirmation prompt
#[arg(short, long)]
yes: bool,
},
}