]> git.ipfire.org Git - thirdparty/git.git/commitdiff
rebase -i: introduce the 'break' command
authorJohannes Schindelin <johannes.schindelin@gmx.de>
Fri, 12 Oct 2018 13:14:26 +0000 (06:14 -0700)
committerJunio C Hamano <gitster@pobox.com>
Fri, 12 Oct 2018 14:03:04 +0000 (23:03 +0900)
The 'edit' command can be used to cherry-pick a commit and then
immediately drop out of the interactive rebase, with exit code 0, to let
the user amend the commit, or test it, or look around.

Sometimes this functionality would come in handy *without*
cherry-picking a commit, e.g. to interrupt the interactive rebase even
before cherry-picking a commit, or immediately after an 'exec' or a
'merge'.

This commit introduces that functionality, as the spanking new 'break'
command.

Suggested-by: Stefan Beller <sbeller@google.com>
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
Documentation/git-rebase.txt
rebase-interactive.c
sequencer.c
t/lib-rebase.sh
t/t3418-rebase-continue.sh

index d9771bd25b4a29ac058d0891b82b18b9ff6ee6a7..6b71694b0d91575e1968733030cccdde6c4a37d8 100644 (file)
@@ -561,6 +561,9 @@ By replacing the command "pick" with the command "edit", you can tell
 the files and/or the commit message, amend the commit, and continue
 rebasing.
 
+To interrupt the rebase (just like an "edit" command would do, but without
+cherry-picking any commit first), use the "break" command.
+
 If you just want to edit the commit message for a commit, replace the
 command "pick" with the command "reword".
 
index 0f4119cbae1bb6c126e15f734855ab2837d98d47..78f3263fc153079938898989822b57e5888568d6 100644 (file)
@@ -14,6 +14,7 @@ void append_todo_help(unsigned edit_todo, unsigned keep_empty,
 "s, squash <commit> = use commit, but meld into previous commit\n"
 "f, fixup <commit> = like \"squash\", but discard this commit's log message\n"
 "x, exec <command> = run command (the rest of the line) using shell\n"
+"b, break = stop here (continue rebase later with 'git rebase --continue')\n"
 "d, drop <commit> = remove commit\n"
 "l, label <label> = label current HEAD with a name\n"
 "t, reset <label> = reset HEAD to a label\n"
index 8dd6db5a017030da8468a48fe868d2982394699d..ee3961ec63a0b34c29a1b253bb2106c56f57c79e 100644 (file)
@@ -1416,6 +1416,7 @@ enum todo_command {
        TODO_SQUASH,
        /* commands that do something else than handling a single commit */
        TODO_EXEC,
+       TODO_BREAK,
        TODO_LABEL,
        TODO_RESET,
        TODO_MERGE,
@@ -1437,6 +1438,7 @@ static struct {
        { 'f', "fixup" },
        { 's', "squash" },
        { 'x', "exec" },
+       { 'b', "break" },
        { 'l', "label" },
        { 't', "reset" },
        { 'm', "merge" },
@@ -1964,7 +1966,7 @@ static int parse_insn_line(struct todo_item *item, const char *bol, char *eol)
        padding = strspn(bol, " \t");
        bol += padding;
 
-       if (item->command == TODO_NOOP) {
+       if (item->command == TODO_NOOP || item->command == TODO_BREAK) {
                if (bol != eol)
                        return error(_("%s does not accept arguments: '%s'"),
                                     command_to_string(item->command), bol);
@@ -3247,6 +3249,23 @@ static int checkout_onto(struct replay_opts *opts,
        return update_ref(NULL, "ORIG_HEAD", &oid, NULL, 0, UPDATE_REFS_MSG_ON_ERR);
 }
 
+static int stopped_at_head(void)
+{
+       struct object_id head;
+       struct commit *commit;
+       struct commit_message message;
+
+       if (get_oid("HEAD", &head) || !(commit = lookup_commit(&head)) ||
+           parse_commit(commit) || get_message(commit, &message))
+               fprintf(stderr, _("Stopped at HEAD\n"));
+       else {
+               fprintf(stderr, _("Stopped at %s\n"), message.label);
+               free_message(commit, &message);
+       }
+       return 0;
+
+}
+
 static const char rescheduled_advice[] =
 N_("Could not execute the todo command\n"
 "\n"
@@ -3293,6 +3312,9 @@ static int pick_commits(struct todo_list *todo_list, struct replay_opts *opts)
                        unlink(rebase_path_stopped_sha());
                        unlink(rebase_path_amend());
                        delete_ref(NULL, "REBASE_HEAD", NULL, REF_NO_DEREF);
+
+                       if (item->command == TODO_BREAK)
+                               return stopped_at_head();
                }
                if (item->command <= TODO_SQUASH) {
                        if (is_rebase_i(opts))
index 25a77ee5cb04088297b7d9fd93d04d76e1494875..584604ee63bd193795daa0f9ca4ad62d9a84b197 100644 (file)
@@ -49,7 +49,7 @@ set_fake_editor () {
                case $line in
                squash|fixup|edit|reword|drop)
                        action="$line";;
-               exec*)
+               exec*|break)
                        echo "$line" | sed 's/_/ /g' >> "$1";;
                "#")
                        echo '# comment' >> "$1";;
index c145dbac38bb549ab7e9030b4134a50eac468383..185a49108924ddad58c2ea75304a4fe4506c298d 100755 (executable)
@@ -239,5 +239,14 @@ test_rerere_autoupdate -m
 GIT_SEQUENCE_EDITOR=: && export GIT_SEQUENCE_EDITOR
 test_rerere_autoupdate -i
 test_rerere_autoupdate --preserve-merges
+unset GIT_SEQUENCE_EDITOR
+
+test_expect_success 'the todo command "break" works' '
+       rm -f execed &&
+       FAKE_LINES="break exec_>execed" git rebase -i HEAD &&
+       test_path_is_missing execed &&
+       git rebase --continue &&
+       test_path_is_file execed
+'
 
 test_done