Introduce subcommands to manage the sequencer state for git-history(1). These aren't really useful yet, but will become useful in subsequent commits where we will introduce git-history(1) subcommands that actually edit history. Signed-off-by: Patrick Steinhardt <ps@xxxxxx> --- Documentation/git-history.adoc | 20 +++++++- builtin/history.c | 114 +++++++++++++++++++++++++++++++++++++++-- t/meson.build | 3 +- t/t3450-history.sh | 32 +++++++++++- 4 files changed, 163 insertions(+), 6 deletions(-) diff --git a/Documentation/git-history.adoc b/Documentation/git-history.adoc index 1537960374..3e9a789b83 100644 --- a/Documentation/git-history.adoc +++ b/Documentation/git-history.adoc @@ -8,7 +8,9 @@ git-history - EXPERIMENTAL: Rewrite history of the current branch SYNOPSIS -------- [synopsis] -git history [<options>] +git history abort +git history continue +git history quit DESCRIPTION ----------- @@ -33,6 +35,22 @@ COMMANDS This command requires a subcommand. Several subcommands are available to rewrite history in different ways: +The following commands are used to manage an interrupted history-rewriting +operation: + +`abort`:: + Abort the history-rewriting operation and reset HEAD to the original + branch. + +`continue`:: + Restart the history-rewriting process after having resolved a merge + conflict. + +`quit`:: + Abort the history-rewriting operation but `HEAD` is not reset back to + the original branch. The index and working tree are also left unchanged + as a result. + CONFIGURATION ------------- diff --git a/builtin/history.c b/builtin/history.c index d1a40368e0..0ad45dbfef 100644 --- a/builtin/history.c +++ b/builtin/history.c @@ -1,20 +1,128 @@ #include "builtin.h" +#include "branch.h" #include "gettext.h" #include "parse-options.h" +#include "sequencer.h" + +static int cmd_history_abort(int argc, + const char **argv, + const char *prefix, + struct repository *repo) +{ + const char * const usage[] = { + N_("git history abort"), + NULL, + }; + struct option options[] = { + OPT_END(), + }; + struct replay_opts opts = REPLAY_OPTS_INIT; + int ret; + + argc = parse_options(argc, argv, prefix, options, usage, 0); + if (argc) { + ret = error(_("command does not take arguments")); + goto out; + } + + opts.action = REPLAY_HISTORY_EDIT; + ret = sequencer_rollback(repo, &opts); + if (ret) + goto out; + + ret = 0; + +out: + replay_opts_release(&opts); + return ret; +} + +static int cmd_history_continue(int argc, + const char **argv, + const char *prefix, + struct repository *repo) +{ + const char * const usage[] = { + N_("git history continue"), + NULL, + }; + struct option options[] = { + OPT_END(), + }; + struct replay_opts opts = REPLAY_OPTS_INIT; + int ret; + + argc = parse_options(argc, argv, prefix, options, usage, 0); + if (argc) { + ret = error(_("command does not take arguments")); + goto out; + } + + opts.action = REPLAY_HISTORY_EDIT; + ret = sequencer_continue(repo, &opts); + if (ret) + goto out; + + ret = 0; + +out: + replay_opts_release(&opts); + return ret; +} + +static int cmd_history_quit(int argc, + const char **argv, + const char *prefix, + struct repository *repo) +{ + const char * const usage[] = { + N_("git history quit"), + NULL, + }; + struct option options[] = { + OPT_END(), + }; + struct replay_opts opts = REPLAY_OPTS_INIT; + int ret; + + argc = parse_options(argc, argv, prefix, options, usage, 0); + if (argc) { + ret = error(_("command does not take arguments")); + goto out; + } + + opts.action = REPLAY_HISTORY_EDIT; + ret = sequencer_remove_state(repo, &opts); + if (ret) + goto out; + remove_branch_state(repo, 0); + + ret = 0; + +out: + replay_opts_release(&opts); + return ret; +} int cmd_history(int argc, const char **argv, const char *prefix, - struct repository *repo UNUSED) + struct repository *repo) { const char * const usage[] = { - N_("git history [<options>]"), + N_("git history abort"), + N_("git history continue"), + N_("git history quit"), NULL, }; + parse_opt_subcommand_fn *fn = NULL; struct option options[] = { + OPT_SUBCOMMAND("abort", &fn, cmd_history_abort), + OPT_SUBCOMMAND("continue", &fn, cmd_history_continue), + OPT_SUBCOMMAND("quit", &fn, cmd_history_quit), OPT_END(), }; argc = parse_options(argc, argv, prefix, options, usage, 0); - return 0; + return fn(argc, argv, prefix, repo); } diff --git a/t/meson.build b/t/meson.build index bbeba1a8d5..966d7c14f4 100644 --- a/t/meson.build +++ b/t/meson.build @@ -376,6 +376,7 @@ integration_tests = [ 't3436-rebase-more-options.sh', 't3437-rebase-fixup-options.sh', 't3438-rebase-broken-files.sh', + 't3450-history.sh', 't3500-cherry.sh', 't3501-revert-cherry-pick.sh', 't3502-cherry-pick-merge.sh', @@ -1214,4 +1215,4 @@ if perl.found() and time.found() timeout: 0, ) endforeach -endif \ No newline at end of file +endif diff --git a/t/t3450-history.sh b/t/t3450-history.sh index 9eb1ed6749..aa9d44c03b 100755 --- a/t/t3450-history.sh +++ b/t/t3450-history.sh @@ -6,7 +6,37 @@ test_description='tests for git-history command' test_expect_success 'refuses to do anything without subcommand' ' test_must_fail git history 2>err && - test_grep foo err + test_grep "need a subcommand" err +' + +test_expect_success 'abort complains about arguments' ' + test_must_fail git history abort foo 2>err && + test_grep "command does not take arguments" err +' + +test_expect_success 'abort complains when no history edit is active' ' + test_must_fail git history abort 2>err && + test_grep "no history edit in progress" err +' + +test_expect_success 'continue complains about arguments' ' + test_must_fail git history continue foo 2>err && + test_grep "command does not take arguments" err +' + +test_expect_success 'continue complains when no history edit is active' ' + test_must_fail git history continue 2>err && + test_grep "no history edit in progress" err +' + +test_expect_success 'quit complains about arguments' ' + test_must_fail git history quit foo 2>err && + test_grep "command does not take arguments" err +' + +test_expect_success 'quit does not complain when no history edit is active' ' + git history quit 2>err && + test_must_be_empty err ' test_done -- 2.51.0.308.g032396e0da.dirty