1mod amend;
4mod bug_report;
5mod hide;
6mod repair;
7mod restack;
8mod snapshot;
9mod split;
10mod sync;
11mod wrap;
12
13use git_branchless_invoke::CommandContext;
14use lib::core::rewrite::MergeConflictRemediation;
15
16use lib::util::ExitCode;
17use lib::{core::gc, util::EyreExitOr};
18
19use git_branchless_opts::{
20 Command, MessageArgs, Opts, ResolveRevsetOptions, SnapshotSubcommand, WrappedCommand,
21 rewrite_args,
22};
23use lib::git::GitRunInfo;
24
25fn command_main(ctx: CommandContext, opts: Opts) -> EyreExitOr<()> {
26 let CommandContext {
27 effects,
28 git_run_info,
29 } = ctx.clone();
30 let Opts {
31 global_args: _,
32 command,
33 } = opts;
34
35 let exit_code = match command {
36 Command::Amend {
37 move_options,
38 untracked_file_strategy,
39 } => amend::amend(
40 &effects,
41 &git_run_info,
42 &ResolveRevsetOptions::default(),
43 &move_options,
44 untracked_file_strategy,
45 )?,
46
47 Command::BugReport => bug_report::bug_report(&effects, &git_run_info)?,
48
49 Command::Difftool(opts) => {
50 let result = scm_diff_editor::run(opts);
51 match result {
52 Ok(()) | Err(scm_diff_editor::Error::Cancelled) => Ok(()),
53 Err(err) => {
54 eprintln!("Error: {err}");
55 Err(ExitCode(1))
56 }
57 }
58 }
59
60 Command::Switch { switch_options } => {
61 git_branchless_navigation::switch(&effects, &git_run_info, &switch_options)?
62 }
63
64 Command::Gc => {
65 gc::gc(&effects)?;
66 Ok(())
67 }
68
69 Command::Hook(args) => git_branchless_hook::command_main(ctx, args)?,
70
71 Command::Hide {
72 revsets,
73 resolve_revset_options,
74 no_delete_branches,
75 recursive,
76 } => hide::hide(
77 &effects,
78 &git_run_info,
79 revsets,
80 &resolve_revset_options,
81 no_delete_branches,
82 recursive,
83 )?,
84
85 Command::Init(args) => git_branchless_init::command_main(ctx, args)?,
86
87 Command::InstallManPages(args) => {
88 git_branchless_init::command_install_man_pages(ctx, args)?
89 }
90
91 Command::Move {
92 source,
93 dest,
94 base,
95 exact,
96 resolve_revset_options,
97 move_options,
98 fixup,
99 insert,
100 dry_run,
101 } => git_branchless_move::r#move(
102 &effects,
103 &git_run_info,
104 source,
105 dest,
106 base,
107 exact,
108 &resolve_revset_options,
109 &move_options,
110 fixup,
111 insert,
112 dry_run,
113 )?,
114
115 Command::Next {
116 traverse_commits_options,
117 } => git_branchless_navigation::traverse_commits(
118 &effects,
119 &git_run_info,
120 git_branchless_navigation::Command::Next,
121 &traverse_commits_options,
122 )?,
123
124 Command::Prev {
125 traverse_commits_options,
126 } => git_branchless_navigation::traverse_commits(
127 &effects,
128 &git_run_info,
129 git_branchless_navigation::Command::Prev,
130 &traverse_commits_options,
131 )?,
132
133 Command::Query(args) => git_branchless_query::command_main(ctx, args)?,
134
135 Command::Repair { dry_run } => repair::repair(&effects, dry_run)?,
136
137 Command::Restack {
138 revsets,
139 resolve_revset_options,
140 move_options,
141 } => restack::restack(
142 &effects,
143 &git_run_info,
144 revsets,
145 &resolve_revset_options,
146 &move_options,
147 MergeConflictRemediation::Retry,
148 )?,
149
150 Command::Record(args) => git_branchless_record::command_main(ctx, args)?,
151
152 Command::Reword {
153 revsets,
154 message_args:
155 MessageArgs {
156 messages,
157 commit_to_fixup,
158 },
159 resolve_revset_options,
160 force_rewrite_public_commits,
161 discard,
162 } => {
163 let messages = if discard {
164 git_branchless_reword::InitialCommitMessages::Discard
165 } else if let Some(commit_to_fixup) = commit_to_fixup {
166 git_branchless_reword::InitialCommitMessages::FixUp(commit_to_fixup)
167 } else {
168 git_branchless_reword::InitialCommitMessages::Messages(messages)
169 };
170 git_branchless_reword::reword(
171 &effects,
172 revsets,
173 &resolve_revset_options,
174 messages,
175 &git_run_info,
176 force_rewrite_public_commits,
177 )?
178 }
179
180 Command::Smartlog(args) => git_branchless_smartlog::command_main(ctx, args)?,
181
182 Command::Snapshot { subcommand } => match subcommand {
183 SnapshotSubcommand::Create => snapshot::create(&effects, &git_run_info)?,
184 SnapshotSubcommand::Restore { snapshot_oid } => {
185 snapshot::restore(&effects, &git_run_info, snapshot_oid)?
186 }
187 },
188
189 Command::Split {
190 before,
191 detach,
192 discard,
193 files,
194 resolve_revset_options,
195 revset,
196 move_options,
197 } => {
198 let split_mode = match (before, detach, discard) {
199 (false, true, false) => split::SplitMode::DetachAfter,
200 (false, false, true) => split::SplitMode::Discard,
201 (false, false, false) => split::SplitMode::InsertAfter,
202 (true, false, false) => split::SplitMode::InsertBefore,
203 (true, true, false)
204 | (true, false, true)
205 | (false, true, true)
206 | (true, true, true) => {
207 unreachable!("clap should prevent this")
208 }
209 };
210
211 split::split(
212 &effects,
213 revset,
214 &resolve_revset_options,
215 files,
216 split_mode,
217 &move_options,
218 &git_run_info,
219 )?
220 }
221
222 Command::Submit(args) => git_branchless_submit::command_main(ctx, args)?,
223
224 Command::Sync {
225 pull,
226 move_options,
227 revsets,
228 resolve_revset_options,
229 } => sync::sync(
230 &effects,
231 &git_run_info,
232 pull,
233 &move_options,
234 revsets,
235 &resolve_revset_options,
236 )?,
237
238 Command::Test(args) => git_branchless_test::command_main(ctx, args)?,
239
240 Command::Undo { interactive, yes } => {
241 git_branchless_undo::undo(&effects, &git_run_info, interactive, yes)?
242 }
243
244 Command::Unhide {
245 revsets,
246 resolve_revset_options,
247 recursive,
248 } => hide::unhide(&effects, revsets, &resolve_revset_options, recursive)?,
249
250 Command::Wrap {
251 git_executable: explicit_git_executable,
252 command: WrappedCommand::WrappedCommand(args),
253 } => {
254 let git_run_info = match explicit_git_executable {
255 Some(path_to_git) => GitRunInfo {
256 path_to_git,
257 ..git_run_info
258 },
259 None => git_run_info,
260 };
261 wrap::wrap(&git_run_info, args.as_slice())?
262 }
263 };
264
265 Ok(exit_code)
266}
267
268pub fn main() {
270 color_eyre::install().expect("Could not install panic handler");
272 let args: Vec<_> = std::env::args_os().collect();
273 let args = rewrite_args(args);
274 let exit_code = git_branchless_invoke::do_main_and_drop_locals(command_main, args)
275 .expect("A fatal error occurred");
276 std::process::exit(exit_code);
277}