git_branchless/commands/
mod.rs

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