From 57a1498592986c7532a37dd7f3eb96dc72d75878 Mon Sep 17 00:00:00 2001 From: Phillip Wood Date: Wed, 12 Oct 2022 09:35:05 +0000 Subject: [PATCH 1/8] rebase --apply: remove duplicated code Use move_to_original_branch() when reattaching HEAD after a fast-forward rather than open coding a copy of that code. move_to_original_branch() does not call reset_head() if head_name is NULL but there should be no user visible changes even though we currently call reset_head() in that case. The reason for this is that the reset_head() call does not add a message to the reflog because we're not changing the commit that HEAD points to and so lock_ref_for_update() elides the update. When head_name is not NULL then reset_head() behaves like "git symbolic-ref" and so the reflog is updated. Note that the removal of "strbuf_release(&msg)" is safe as there is an identical call just above this hunk which can be seen by viewing the diff with -U6. Signed-off-by: Phillip Wood Signed-off-by: Junio C Hamano --- builtin/rebase.c | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/builtin/rebase.c b/builtin/rebase.c index ef520f66fb..e67020b358 100644 --- a/builtin/rebase.c +++ b/builtin/rebase.c @@ -1811,19 +1811,10 @@ int cmd_rebase(int argc, const char **argv, const char *prefix) * If the onto is a proper descendant of the tip of the branch, then * we just fast-forwarded. */ - strbuf_reset(&msg); if (oideq(&branch_base, &options.orig_head->object.oid)) { printf(_("Fast-forwarded %s to %s.\n"), branch_name, options.onto_name); - strbuf_addf(&msg, "rebase finished: %s onto %s", - options.head_name ? options.head_name : "detached HEAD", - oid_to_hex(&options.onto->object.oid)); - memset(&ropts, 0, sizeof(ropts)); - ropts.branch = options.head_name; - ropts.flags = RESET_HEAD_REFS_ONLY; - ropts.head_msg = msg.buf; - reset_head(the_repository, &ropts); - strbuf_release(&msg); + move_to_original_branch(&options); ret = finish_rebase(&options); goto cleanup; } From 4e5e1b4b616f0354218ff2e2ff3c71e4c730bbe1 Mon Sep 17 00:00:00 2001 From: Phillip Wood Date: Wed, 12 Oct 2022 09:35:06 +0000 Subject: [PATCH 2/8] t3406: rework rebase reflog tests Refactor the tests in preparation for adding more tests in the next few commits. The reworked tests use the same function for testing both the "merge" and "apply" backends. The test coverage for the "apply" backend now includes setting GIT_REFLOG_ACTION. Note that rebasing the "conflicts" branch does not create any conflicts yet. A commit to do that will be added in the next commit and the diff ends up smaller if we have don't rename the branch when it is added. Signed-off-by: Phillip Wood Signed-off-by: Junio C Hamano --- t/t3406-rebase-message.sh | 117 +++++++++++++++++++++++++------------- 1 file changed, 77 insertions(+), 40 deletions(-) diff --git a/t/t3406-rebase-message.sh b/t/t3406-rebase-message.sh index d17b450e81..5253dd1551 100755 --- a/t/t3406-rebase-message.sh +++ b/t/t3406-rebase-message.sh @@ -10,10 +10,15 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME test_expect_success 'setup' ' test_commit O fileO && test_commit X fileX && + git branch fast-forward && test_commit A fileA && test_commit B fileB && test_commit Y fileY && + git checkout -b conflicts O && + test_commit P && + test_commit Q && + git checkout -b topic O && git cherry-pick A B && test_commit Z fileZ && @@ -79,54 +84,86 @@ test_expect_success 'error out early upon -C or --whitespace=' ' test_i18ngrep "Invalid whitespace option" err ' -test_expect_success 'GIT_REFLOG_ACTION' ' - git checkout start && - test_commit reflog-onto && - git checkout -b reflog-topic start && - test_commit reflog-to-rebase && +write_reflog_expect () { + if test $mode = --apply + then + sed 's/.*(finish)/rebase finished/; s/ ([^)]*)//' + else + cat + fi >expect +} - git rebase reflog-onto && - git log -g --format=%gs -3 >actual && - cat >expect <<-\EOF && - rebase (finish): returning to refs/heads/reflog-topic - rebase (pick): reflog-to-rebase - rebase (start): checkout reflog-onto +test_reflog () { + mode=$1 + reflog_action="$2" + + test_expect_success "rebase $mode reflog${reflog_action:+ GIT_REFLOG_ACTION=$reflog_action}" ' + git checkout conflicts && + test_when_finished "git reset --hard Q" && + + ( + if test -n "$reflog_action" + then + GIT_REFLOG_ACTION="$reflog_action" && + export GIT_REFLOG_ACTION + fi && + git rebase $mode main + ) && + + git log -g --format=%gs -4 >actual && + write_reflog_expect <<-EOF && + ${reflog_action:-rebase} (finish): returning to refs/heads/conflicts + ${reflog_action:-rebase} (pick): Q + ${reflog_action:-rebase} (pick): P + ${reflog_action:-rebase} (start): checkout main EOF test_cmp expect actual && - git checkout -b reflog-prefix reflog-to-rebase && - GIT_REFLOG_ACTION=change-the-reflog git rebase reflog-onto && - git log -g --format=%gs -3 >actual && - cat >expect <<-\EOF && - change-the-reflog (finish): returning to refs/heads/reflog-prefix - change-the-reflog (pick): reflog-to-rebase - change-the-reflog (start): checkout reflog-onto - EOF - test_cmp expect actual -' - -test_expect_success 'rebase --apply reflog' ' - git checkout -b reflog-apply start && - old_head_reflog="$(git log -g --format=%gs -1 HEAD)" && - - git rebase --apply Y && - - git log -g --format=%gs -4 HEAD >actual && - cat >expect <<-EOF && - rebase finished: returning to refs/heads/reflog-apply - rebase: Z - rebase: checkout Y - $old_head_reflog + git log -g --format=%gs -1 conflicts >actual && + write_reflog_expect <<-EOF && + ${reflog_action:-rebase} (finish): refs/heads/conflicts onto $(git rev-parse main) EOF test_cmp expect actual && - git log -g --format=%gs -2 reflog-apply >actual && - cat >expect <<-EOF && - rebase finished: refs/heads/reflog-apply onto $(git rev-parse Y) - branch: Created from start + # check there is only one new entry in the branch reflog + test_cmp_rev conflicts@{1} Q + ' + + test_expect_success "rebase $mode fast-forward reflog${reflog_action:+ GIT_REFLOG_ACTION=$reflog_action}" ' + git checkout fast-forward && + test_when_finished "git reset --hard X" && + + ( + if test -n "$reflog_action" + then + GIT_REFLOG_ACTION="$reflog_action" && + export GIT_REFLOG_ACTION + fi && + git rebase $mode main + ) && + + git log -g --format=%gs -2 >actual && + write_reflog_expect <<-EOF && + ${reflog_action:-rebase} (finish): returning to refs/heads/fast-forward + ${reflog_action:-rebase} (start): checkout main EOF - test_cmp expect actual -' + test_cmp expect actual && + + git log -g --format=%gs -1 fast-forward >actual && + write_reflog_expect <<-EOF && + ${reflog_action:-rebase} (finish): refs/heads/fast-forward onto $(git rev-parse main) + EOF + test_cmp expect actual && + + # check there is only one new entry in the branch reflog + test_cmp_rev fast-forward@{1} X + ' +} + +test_reflog --merge +test_reflog --merge my-reflog-action +test_reflog --apply +test_reflog --apply my-reflog-action test_expect_success 'rebase -i onto unrelated history' ' git init unrelated && From da1d63363f13d4d65c59564c74fd8dd598b39c49 Mon Sep 17 00:00:00 2001 From: Phillip Wood Date: Wed, 12 Oct 2022 09:35:07 +0000 Subject: [PATCH 3/8] rebase --merge: fix reflog when continuing The reflog message for a conflict resolution committed by "rebase --continue" looks like rebase (continue): commit subject line Unfortunately the reflog message each subsequent pick look like rebase (continue) (pick): commit subject line Fix this by setting the reflog message for "rebase --continue" in sequencer_continue() so it does not affect subsequent commits. This introduces a memory leak similar to the one leaking GIT_REFLOG_ACTION in pick_commits(). Both of these will be fixed in a future series that stops the sequencer calling setenv(). If we fail to commit the staged changes then we error out so GIT_REFLOG_ACTION does not need to be reset in that case. Signed-off-by: Phillip Wood Signed-off-by: Junio C Hamano --- builtin/rebase.c | 2 -- sequencer.c | 5 +++++ t/t3406-rebase-message.sh | 9 +++++++-- 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/builtin/rebase.c b/builtin/rebase.c index e67020b358..414526f83a 100644 --- a/builtin/rebase.c +++ b/builtin/rebase.c @@ -1271,8 +1271,6 @@ int cmd_rebase(int argc, const char **argv, const char *prefix) int fd; options.action = "continue"; - set_reflog_action(&options); - /* Sanity check */ if (get_oid("HEAD", &head)) die(_("Cannot read HEAD")); diff --git a/sequencer.c b/sequencer.c index 61a8e0020d..5790b35d76 100644 --- a/sequencer.c +++ b/sequencer.c @@ -4785,6 +4785,8 @@ int sequencer_continue(struct repository *r, struct replay_opts *opts) if (read_populate_opts(opts)) return -1; if (is_rebase_i(opts)) { + char *previous_reflog_action; + if ((res = read_populate_todo(r, &todo_list, opts))) goto release_todo_list; @@ -4795,10 +4797,13 @@ int sequencer_continue(struct repository *r, struct replay_opts *opts) unlink(rebase_path_dropped()); } + previous_reflog_action = xstrdup(getenv(GIT_REFLOG_ACTION)); + setenv(GIT_REFLOG_ACTION, reflog_message(opts, "continue", NULL), 1); if (commit_staged_changes(r, opts, &todo_list)) { res = -1; goto release_todo_list; } + setenv(GIT_REFLOG_ACTION, previous_reflog_action, 1); } else if (!file_exists(get_todo_path(opts))) return continue_single_pick(r, opts); else if ((res = read_populate_todo(r, &todo_list, opts))) diff --git a/t/t3406-rebase-message.sh b/t/t3406-rebase-message.sh index 5253dd1551..3ca2fbb0d5 100755 --- a/t/t3406-rebase-message.sh +++ b/t/t3406-rebase-message.sh @@ -17,6 +17,7 @@ test_expect_success 'setup' ' git checkout -b conflicts O && test_commit P && + test_commit conflict-X fileX && test_commit Q && git checkout -b topic O && @@ -107,13 +108,17 @@ test_reflog () { GIT_REFLOG_ACTION="$reflog_action" && export GIT_REFLOG_ACTION fi && - git rebase $mode main + test_must_fail git rebase $mode main && + echo resolved >fileX && + git add fileX && + git rebase --continue ) && - git log -g --format=%gs -4 >actual && + git log -g --format=%gs -5 >actual && write_reflog_expect <<-EOF && ${reflog_action:-rebase} (finish): returning to refs/heads/conflicts ${reflog_action:-rebase} (pick): Q + ${reflog_action:-rebase} (continue): conflict-X ${reflog_action:-rebase} (pick): P ${reflog_action:-rebase} (start): checkout main EOF From 1f2d5dc4d2bbcae87736fcd7b7c0e6542008c5f7 Mon Sep 17 00:00:00 2001 From: Phillip Wood Date: Wed, 12 Oct 2022 09:35:08 +0000 Subject: [PATCH 4/8] rebase --merge: fix reflog message after skipping The reflog message for every pick after running "rebase --skip" looks like rebase (skip) (pick): commit subject line Fix this by not appending " (skip)" to the reflog action. Signed-off-by: Phillip Wood Signed-off-by: Junio C Hamano --- builtin/rebase.c | 2 -- t/t3406-rebase-message.sh | 24 ++++++++++++++++++++++++ 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/builtin/rebase.c b/builtin/rebase.c index 414526f83a..c1e68173b5 100644 --- a/builtin/rebase.c +++ b/builtin/rebase.c @@ -1297,8 +1297,6 @@ int cmd_rebase(int argc, const char **argv, const char *prefix) struct string_list merge_rr = STRING_LIST_INIT_DUP; options.action = "skip"; - set_reflog_action(&options); - rerere_clear(the_repository, &merge_rr); string_list_clear(&merge_rr, 1); ropts.flags = RESET_HEAD_HARD; diff --git a/t/t3406-rebase-message.sh b/t/t3406-rebase-message.sh index 3ca2fbb0d5..8aa6a79acc 100755 --- a/t/t3406-rebase-message.sh +++ b/t/t3406-rebase-message.sh @@ -163,6 +163,30 @@ test_reflog () { # check there is only one new entry in the branch reflog test_cmp_rev fast-forward@{1} X ' + + test_expect_success "rebase $mode --skip reflog${reflog_action:+ GIT_REFLOG_ACTION=$reflog_action}" ' + git checkout conflicts && + test_when_finished "git reset --hard Q" && + + ( + if test -n "$reflog_action" + then + GIT_REFLOG_ACTION="$reflog_action" && + export GIT_REFLOG_ACTION + fi && + test_must_fail git rebase $mode main && + git rebase --skip + ) && + + git log -g --format=%gs -4 >actual && + write_reflog_expect <<-EOF && + ${reflog_action:-rebase} (finish): returning to refs/heads/conflicts + ${reflog_action:-rebase} (pick): Q + ${reflog_action:-rebase} (pick): P + ${reflog_action:-rebase} (start): checkout main + EOF + test_cmp expect actual + ' } test_reflog --merge From 33f2b61ff9039247fd26d8b40db7e87e16ffe214 Mon Sep 17 00:00:00 2001 From: Phillip Wood Date: Wed, 12 Oct 2022 09:35:09 +0000 Subject: [PATCH 5/8] rebase --apply: respect GIT_REFLOG_ACTION The reflog messages when finishing a rebase hard code "rebase" rather than using GIT_REFLOG_ACTION. Signed-off-by: Phillip Wood Signed-off-by: Junio C Hamano --- builtin/rebase.c | 7 ++++--- t/t3406-rebase-message.sh | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/builtin/rebase.c b/builtin/rebase.c index c1e68173b5..ea246c6bb3 100644 --- a/builtin/rebase.c +++ b/builtin/rebase.c @@ -582,10 +582,11 @@ static int move_to_original_branch(struct rebase_options *opts) if (!opts->onto) BUG("move_to_original_branch without onto"); - strbuf_addf(&branch_reflog, "rebase finished: %s onto %s", + strbuf_addf(&branch_reflog, "%s finished: %s onto %s", + getenv(GIT_REFLOG_ACTION_ENVIRONMENT), opts->head_name, oid_to_hex(&opts->onto->object.oid)); - strbuf_addf(&head_reflog, "rebase finished: returning to %s", - opts->head_name); + strbuf_addf(&head_reflog, "%s finished: returning to %s", + getenv(GIT_REFLOG_ACTION_ENVIRONMENT), opts->head_name); ropts.branch = opts->head_name; ropts.flags = RESET_HEAD_REFS_ONLY; ropts.branch_msg = branch_reflog.buf; diff --git a/t/t3406-rebase-message.sh b/t/t3406-rebase-message.sh index 8aa6a79acc..bb2a4949ab 100755 --- a/t/t3406-rebase-message.sh +++ b/t/t3406-rebase-message.sh @@ -88,7 +88,7 @@ test_expect_success 'error out early upon -C or --whitespace=' ' write_reflog_expect () { if test $mode = --apply then - sed 's/.*(finish)/rebase finished/; s/ ([^)]*)//' + sed 's/(finish)/finished/; s/ ([^)]*)//' else cat fi >expect From be0d29d301ffe284b123247d6680b289f73924a4 Mon Sep 17 00:00:00 2001 From: Phillip Wood Date: Wed, 12 Oct 2022 09:35:10 +0000 Subject: [PATCH 6/8] rebase --apply: make reflog messages match rebase --merge The apply backend creates slightly different reflog messages to the merge backend when starting or finishing a rebase and when picking commits. These differences make it harder than it needs to be to parse the reflog (I have a script that reads the finishing messages from rebase and it is a pain to have to accommodate two different message formats). While it is possible to determine the backend used for a rebase from the reflog messages, the differences are not designed for that purpose. c2417d3af7 (rebase: drop '-i' from the reflog for interactive-based rebases, 2020-02-15) removed the clear distinction between the reflog messages of the two backends without complaint. As the merge backend is the default it is likely to be the format most common in existing reflogs. For that reason the apply backend is changed to format its reflog messages to match the merge backend as closely as possible. Note that there is still a difference as when committing a conflict resolution the apply backend will use "(pick)" rather than "(continue)" because it is not currently possible to change the message for a single commit. In addition to c2417d3af7 we also changed the reflog messages in 68aa495b59 (rebase: implement --merge via the interactive machinery, 2018-12-11) and 2ac0d6273f (rebase: change the default backend from "am" to "merge", 2020-02-15). This commit makes the same change to "git rebase --apply" that 2ac0d6273f made to "git rebase" without any backend specific options. As the messages are changed to use an existing format any scripts that can parse the reflog messages of the default rebase backend should be unaffected by this change. There are existing tests for the messages from both backends which are adjusted to ensure that they do not get out of sync in the future. Signed-off-by: Phillip Wood Signed-off-by: Junio C Hamano --- builtin/rebase.c | 9 +++++---- t/t3406-rebase-message.sh | 2 +- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/builtin/rebase.c b/builtin/rebase.c index ea246c6bb3..5253ba6686 100644 --- a/builtin/rebase.c +++ b/builtin/rebase.c @@ -582,10 +582,10 @@ static int move_to_original_branch(struct rebase_options *opts) if (!opts->onto) BUG("move_to_original_branch without onto"); - strbuf_addf(&branch_reflog, "%s finished: %s onto %s", + strbuf_addf(&branch_reflog, "%s (finish): %s onto %s", getenv(GIT_REFLOG_ACTION_ENVIRONMENT), opts->head_name, oid_to_hex(&opts->onto->object.oid)); - strbuf_addf(&head_reflog, "%s finished: returning to %s", + strbuf_addf(&head_reflog, "%s (finish): returning to %s", getenv(GIT_REFLOG_ACTION_ENVIRONMENT), opts->head_name); ropts.branch = opts->head_name; ropts.flags = RESET_HEAD_REFS_ONLY; @@ -615,7 +615,8 @@ static int run_am(struct rebase_options *opts) am.git_cmd = 1; strvec_push(&am.args, "am"); - + strvec_pushf(&am.env, GIT_REFLOG_ACTION_ENVIRONMENT "=%s (pick)", + getenv(GIT_REFLOG_ACTION_ENVIRONMENT)); if (opts->action && !strcmp("continue", opts->action)) { strvec_push(&am.args, "--resolved"); strvec_pushf(&am.args, "--resolvemsg=%s", resolvemsg); @@ -1792,7 +1793,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix) printf(_("First, rewinding head to replay your work on top of " "it...\n")); - strbuf_addf(&msg, "%s: checkout %s", + strbuf_addf(&msg, "%s (start): checkout %s", getenv(GIT_REFLOG_ACTION_ENVIRONMENT), options.onto_name); ropts.oid = &options.onto->object.oid; ropts.orig_head = &options.orig_head->object.oid, diff --git a/t/t3406-rebase-message.sh b/t/t3406-rebase-message.sh index bb2a4949ab..5c6cd9af3b 100755 --- a/t/t3406-rebase-message.sh +++ b/t/t3406-rebase-message.sh @@ -88,7 +88,7 @@ test_expect_success 'error out early upon -C or --whitespace=' ' write_reflog_expect () { if test $mode = --apply then - sed 's/(finish)/finished/; s/ ([^)]*)//' + sed 's/(continue)/(pick)/' else cat fi >expect From 6159e7add493cf1d62b4817eb86ac8890e768c17 Mon Sep 17 00:00:00 2001 From: Phillip Wood Date: Wed, 12 Oct 2022 09:35:11 +0000 Subject: [PATCH 7/8] rebase --abort: improve reflog message When aborting a rebase the reflog message looks like rebase (abort): updating HEAD which is not very informative. Improve the message by mentioning the branch that we are returning to as we do at the end of a successful rebase so it looks like. rebase (abort): returning to refs/heads/topic If GIT_REFLOG_ACTION is set in the environment we no longer omit "(abort)" from the reflog message. We don't omit "(start)" and "(finish)" when starting and finishing a rebase in that case so we shouldn't omit "(abort)". Signed-off-by: Phillip Wood Signed-off-by: Junio C Hamano --- builtin/rebase.c | 28 ++++++--------------- t/t3406-rebase-message.sh | 51 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 59 insertions(+), 20 deletions(-) diff --git a/builtin/rebase.c b/builtin/rebase.c index 5253ba6686..d63d77757e 100644 --- a/builtin/rebase.c +++ b/builtin/rebase.c @@ -1001,23 +1001,6 @@ static void NORETURN error_on_missing_default_upstream(void) exit(1); } -static void set_reflog_action(struct rebase_options *options) -{ - const char *env; - struct strbuf buf = STRBUF_INIT; - - if (!is_merge(options)) - return; - - env = getenv(GIT_REFLOG_ACTION_ENVIRONMENT); - if (env && strcmp("rebase", env)) - return; /* only override it if it is "rebase" */ - - strbuf_addf(&buf, "rebase (%s)", options->action); - setenv(GIT_REFLOG_ACTION_ENVIRONMENT, buf.buf, 1); - strbuf_release(&buf); -} - static int check_exec_cmd(const char *cmd) { if (strchr(cmd, '\n')) @@ -1311,18 +1294,23 @@ int cmd_rebase(int argc, const char **argv, const char *prefix) } case ACTION_ABORT: { struct string_list merge_rr = STRING_LIST_INIT_DUP; - options.action = "abort"; - set_reflog_action(&options); + struct strbuf head_msg = STRBUF_INIT; + options.action = "abort"; rerere_clear(the_repository, &merge_rr); string_list_clear(&merge_rr, 1); if (read_basic_state(&options)) exit(1); + + strbuf_addf(&head_msg, "%s (abort): returning to %s", + getenv(GIT_REFLOG_ACTION_ENVIRONMENT), + options.head_name ? options.head_name + : oid_to_hex(&options.orig_head->object.oid)); ropts.oid = &options.orig_head->object.oid; + ropts.head_msg = head_msg.buf; ropts.branch = options.head_name; ropts.flags = RESET_HEAD_HARD; - ropts.default_reflog_action = DEFAULT_REFLOG_ACTION; if (reset_head(the_repository, &ropts) < 0) die(_("could not move back to %s"), oid_to_hex(&options.orig_head->object.oid)); diff --git a/t/t3406-rebase-message.sh b/t/t3406-rebase-message.sh index 5c6cd9af3b..ceca160005 100755 --- a/t/t3406-rebase-message.sh +++ b/t/t3406-rebase-message.sh @@ -187,6 +187,57 @@ test_reflog () { EOF test_cmp expect actual ' + + test_expect_success "rebase $mode --abort reflog${reflog_action:+ GIT_REFLOG_ACTION=$reflog_action}" ' + git checkout conflicts && + test_when_finished "git reset --hard Q" && + + git log -g -1 conflicts >branch-expect && + ( + if test -n "$reflog_action" + then + GIT_REFLOG_ACTION="$reflog_action" && + export GIT_REFLOG_ACTION + fi && + test_must_fail git rebase $mode main && + git rebase --abort + ) && + + git log -g --format=%gs -3 >actual && + write_reflog_expect <<-EOF && + ${reflog_action:-rebase} (abort): returning to refs/heads/conflicts + ${reflog_action:-rebase} (pick): P + ${reflog_action:-rebase} (start): checkout main + EOF + test_cmp expect actual && + + # check branch reflog is unchanged + git log -g -1 conflicts >branch-actual && + test_cmp branch-expect branch-actual + ' + + test_expect_success "rebase $mode --abort detached HEAD reflog${reflog_action:+ GIT_REFLOG_ACTION=$reflog_action}" ' + git checkout Q && + test_when_finished "git reset --hard Q" && + + ( + if test -n "$reflog_action" + then + GIT_REFLOG_ACTION="$reflog_action" && + export GIT_REFLOG_ACTION + fi && + test_must_fail git rebase $mode main && + git rebase --abort + ) && + + git log -g --format=%gs -3 >actual && + write_reflog_expect <<-EOF && + ${reflog_action:-rebase} (abort): returning to $(git rev-parse Q) + ${reflog_action:-rebase} (pick): P + ${reflog_action:-rebase} (start): checkout main + EOF + test_cmp expect actual + ' } test_reflog --merge From 9a1925b08f3d9b71f06226f5ac32f24587f39151 Mon Sep 17 00:00:00 2001 From: Phillip Wood Date: Wed, 12 Oct 2022 09:35:12 +0000 Subject: [PATCH 8/8] rebase: cleanup action handling Treating the action as a string is a hang over from the scripted rebase. The last commit removed the only remaining use of the action that required a string so lets convert the other action users to use the existing action enum instead. If we ever need the action name as a string in the future the action_names array exists exactly for that purpose. Signed-off-by: Phillip Wood Signed-off-by: Junio C Hamano --- builtin/rebase.c | 93 +++++++++++++++++++++++------------------------- 1 file changed, 44 insertions(+), 49 deletions(-) diff --git a/builtin/rebase.c b/builtin/rebase.c index d63d77757e..d5e684a7ce 100644 --- a/builtin/rebase.c +++ b/builtin/rebase.c @@ -59,6 +59,26 @@ enum empty_type { EMPTY_ASK }; +enum action { + ACTION_NONE = 0, + ACTION_CONTINUE, + ACTION_SKIP, + ACTION_ABORT, + ACTION_QUIT, + ACTION_EDIT_TODO, + ACTION_SHOW_CURRENT_PATCH +}; + +static const char *action_names[] = { + "undefined", + "continue", + "skip", + "abort", + "quit", + "edit_todo", + "show_current_patch" +}; + struct rebase_options { enum rebase_type type; enum empty_type empty; @@ -85,7 +105,7 @@ struct rebase_options { REBASE_INTERACTIVE_EXPLICIT = 1<<4, } flags; struct strvec git_am_opts; - const char *action; + enum action action; int signoff; int allow_rerere_autoupdate; int keep_empty; @@ -156,24 +176,6 @@ static struct replay_opts get_replay_opts(const struct rebase_options *opts) return replay; } -enum action { - ACTION_NONE = 0, - ACTION_CONTINUE, - ACTION_SKIP, - ACTION_ABORT, - ACTION_QUIT, - ACTION_EDIT_TODO, - ACTION_SHOW_CURRENT_PATCH -}; - -static const char *action_names[] = { "undefined", - "continue", - "skip", - "abort", - "quit", - "edit_todo", - "show_current_patch" }; - static int edit_todo_file(unsigned flags) { const char *todo_file = rebase_path_todo(); @@ -310,8 +312,7 @@ static int do_interactive_rebase(struct rebase_options *opts, unsigned flags) return ret; } -static int run_sequencer_rebase(struct rebase_options *opts, - enum action command) +static int run_sequencer_rebase(struct rebase_options *opts) { unsigned flags = 0; int abbreviate_commands = 0, ret = 0; @@ -326,7 +327,7 @@ static int run_sequencer_rebase(struct rebase_options *opts, flags |= opts->reapply_cherry_picks ? TODO_LIST_REAPPLY_CHERRY_PICKS : 0; flags |= opts->flags & REBASE_NO_QUIET ? TODO_LIST_WARN_SKIPPED_CHERRY_PICKS : 0; - switch (command) { + switch (opts->action) { case ACTION_NONE: { if (!opts->onto && !opts->upstream) die(_("a base commit must be provided with --upstream or --onto")); @@ -359,7 +360,7 @@ static int run_sequencer_rebase(struct rebase_options *opts, break; } default: - BUG("invalid command '%d'", command); + BUG("invalid command '%d'", opts->action); } return ret; @@ -617,7 +618,7 @@ static int run_am(struct rebase_options *opts) strvec_push(&am.args, "am"); strvec_pushf(&am.env, GIT_REFLOG_ACTION_ENVIRONMENT "=%s (pick)", getenv(GIT_REFLOG_ACTION_ENVIRONMENT)); - if (opts->action && !strcmp("continue", opts->action)) { + if (opts->action == ACTION_CONTINUE) { strvec_push(&am.args, "--resolved"); strvec_pushf(&am.args, "--resolvemsg=%s", resolvemsg); if (opts->gpg_sign_opt) @@ -628,7 +629,7 @@ static int run_am(struct rebase_options *opts) return move_to_original_branch(opts); } - if (opts->action && !strcmp("skip", opts->action)) { + if (opts->action == ACTION_SKIP) { strvec_push(&am.args, "--skip"); strvec_pushf(&am.args, "--resolvemsg=%s", resolvemsg); status = run_command(&am); @@ -637,7 +638,7 @@ static int run_am(struct rebase_options *opts) return move_to_original_branch(opts); } - if (opts->action && !strcmp("show-current-patch", opts->action)) { + if (opts->action == ACTION_SHOW_CURRENT_PATCH) { strvec_push(&am.args, "--show-current-patch"); return run_command(&am); } @@ -730,7 +731,7 @@ static int run_am(struct rebase_options *opts) return status; } -static int run_specific_rebase(struct rebase_options *opts, enum action action) +static int run_specific_rebase(struct rebase_options *opts) { int status; @@ -748,7 +749,7 @@ static int run_specific_rebase(struct rebase_options *opts, enum action action) opts->gpg_sign_opt = tmp; } - status = run_sequencer_rebase(opts, action); + status = run_sequencer_rebase(opts); } else if (opts->type == REBASE_APPLY) status = run_am(opts); else @@ -1025,7 +1026,6 @@ int cmd_rebase(int argc, const char **argv, const char *prefix) struct strbuf buf = STRBUF_INIT; struct object_id branch_base; int ignore_whitespace = 0; - enum action action = ACTION_NONE; const char *gpg_sign = NULL; struct string_list exec = STRING_LIST_INIT_NODUP; const char *rebase_merges = NULL; @@ -1074,18 +1074,18 @@ int cmd_rebase(int argc, const char **argv, const char *prefix) OPT_BIT(0, "no-ff", &options.flags, N_("cherry-pick all commits, even if unchanged"), REBASE_FORCE), - OPT_CMDMODE(0, "continue", &action, N_("continue"), + OPT_CMDMODE(0, "continue", &options.action, N_("continue"), ACTION_CONTINUE), - OPT_CMDMODE(0, "skip", &action, + OPT_CMDMODE(0, "skip", &options.action, N_("skip current patch and continue"), ACTION_SKIP), - OPT_CMDMODE(0, "abort", &action, + OPT_CMDMODE(0, "abort", &options.action, N_("abort and check out the original branch"), ACTION_ABORT), - OPT_CMDMODE(0, "quit", &action, + OPT_CMDMODE(0, "quit", &options.action, N_("abort but keep HEAD where it is"), ACTION_QUIT), - OPT_CMDMODE(0, "edit-todo", &action, N_("edit the todo list " + OPT_CMDMODE(0, "edit-todo", &options.action, N_("edit the todo list " "during an interactive rebase"), ACTION_EDIT_TODO), - OPT_CMDMODE(0, "show-current-patch", &action, + OPT_CMDMODE(0, "show-current-patch", &options.action, N_("show the patch file being applied or merged"), ACTION_SHOW_CURRENT_PATCH), OPT_CALLBACK_F(0, "apply", &options, NULL, @@ -1174,7 +1174,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix) } else if (is_directory(merge_dir())) { strbuf_reset(&buf); strbuf_addf(&buf, "%s/rewritten", merge_dir()); - if (!(action == ACTION_ABORT) && is_directory(buf.buf)) { + if (!(options.action == ACTION_ABORT) && is_directory(buf.buf)) { die(_("`rebase --preserve-merges` (-p) is no longer supported.\n" "Use `git rebase --abort` to terminate current rebase.\n" "Or downgrade to v2.33, or earlier, to complete the rebase.")); @@ -1201,7 +1201,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix) "Note: Your `pull.rebase` configuration may also be set to 'preserve',\n" "which is no longer supported; use 'merges' instead")); - if (action != ACTION_NONE && total_argc != 2) { + if (options.action != ACTION_NONE && total_argc != 2) { usage_with_options(builtin_rebase_usage, builtin_rebase_options); } @@ -1232,11 +1232,11 @@ int cmd_rebase(int argc, const char **argv, const char *prefix) if (options.root && options.fork_point > 0) die(_("options '%s' and '%s' cannot be used together"), "--root", "--fork-point"); - if (action != ACTION_NONE && !in_progress) + if (options.action != ACTION_NONE && !in_progress) die(_("No rebase in progress?")); setenv(GIT_REFLOG_ACTION_ENVIRONMENT, "rebase", 0); - if (action == ACTION_EDIT_TODO && !is_merge(&options)) + if (options.action == ACTION_EDIT_TODO && !is_merge(&options)) die(_("The --edit-todo action can only be used during " "interactive rebase.")); @@ -1246,16 +1246,15 @@ int cmd_rebase(int argc, const char **argv, const char *prefix) else if (exec.nr) trace2_cmd_mode("interactive-exec"); else - trace2_cmd_mode(action_names[action]); + trace2_cmd_mode(action_names[options.action]); } - switch (action) { + switch (options.action) { case ACTION_CONTINUE: { struct object_id head; struct lock_file lock_file = LOCK_INIT; int fd; - options.action = "continue"; /* Sanity check */ if (get_oid("HEAD", &head)) die(_("Cannot read HEAD")); @@ -1281,7 +1280,6 @@ int cmd_rebase(int argc, const char **argv, const char *prefix) case ACTION_SKIP: { struct string_list merge_rr = STRING_LIST_INIT_DUP; - options.action = "skip"; rerere_clear(the_repository, &merge_rr); string_list_clear(&merge_rr, 1); ropts.flags = RESET_HEAD_HARD; @@ -1296,7 +1294,6 @@ int cmd_rebase(int argc, const char **argv, const char *prefix) struct string_list merge_rr = STRING_LIST_INIT_DUP; struct strbuf head_msg = STRBUF_INIT; - options.action = "abort"; rerere_clear(the_repository, &merge_rr); string_list_clear(&merge_rr, 1); @@ -1336,17 +1333,15 @@ int cmd_rebase(int argc, const char **argv, const char *prefix) goto cleanup; } case ACTION_EDIT_TODO: - options.action = "edit-todo"; options.dont_finish_rebase = 1; goto run_rebase; case ACTION_SHOW_CURRENT_PATCH: - options.action = "show-current-patch"; options.dont_finish_rebase = 1; goto run_rebase; case ACTION_NONE: break; default: - BUG("action: %d", action); + BUG("action: %d", options.action); } /* Make sure no rebase is in progress */ @@ -1370,7 +1365,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix) } if ((options.flags & REBASE_INTERACTIVE_EXPLICIT) || - (action != ACTION_NONE) || + (options.action != ACTION_NONE) || (exec.nr > 0) || options.autosquash) { allow_preemptive_ff = 0; @@ -1815,7 +1810,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix) options.revisions = revisions.buf; run_rebase: - ret = run_specific_rebase(&options, action); + ret = run_specific_rebase(&options); cleanup: strbuf_release(&buf);