Browse Source

rebase -i: introduce the 'break' command

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>
maint
Johannes Schindelin 6 years ago committed by Junio C Hamano
parent
commit
71f82465b1
  1. 3
      Documentation/git-rebase.txt
  2. 1
      rebase-interactive.c
  3. 24
      sequencer.c
  4. 2
      t/lib-rebase.sh
  5. 9
      t/t3418-rebase-continue.sh

3
Documentation/git-rebase.txt

@ -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 the files and/or the commit message, amend the commit, and continue
rebasing. 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 If you just want to edit the commit message for a commit, replace the
command "pick" with the command "reword". command "pick" with the command "reword".



1
rebase-interactive.c

@ -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" "s, squash <commit> = use commit, but meld into previous commit\n"
"f, fixup <commit> = like \"squash\", but discard this commit's log message\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" "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" "d, drop <commit> = remove commit\n"
"l, label <label> = label current HEAD with a name\n" "l, label <label> = label current HEAD with a name\n"
"t, reset <label> = reset HEAD to a label\n" "t, reset <label> = reset HEAD to a label\n"

24
sequencer.c

@ -1416,6 +1416,7 @@ enum todo_command {
TODO_SQUASH, TODO_SQUASH,
/* commands that do something else than handling a single commit */ /* commands that do something else than handling a single commit */
TODO_EXEC, TODO_EXEC,
TODO_BREAK,
TODO_LABEL, TODO_LABEL,
TODO_RESET, TODO_RESET,
TODO_MERGE, TODO_MERGE,
@ -1437,6 +1438,7 @@ static struct {
{ 'f', "fixup" }, { 'f', "fixup" },
{ 's', "squash" }, { 's', "squash" },
{ 'x', "exec" }, { 'x', "exec" },
{ 'b', "break" },
{ 'l', "label" }, { 'l', "label" },
{ 't', "reset" }, { 't', "reset" },
{ 'm', "merge" }, { 'm', "merge" },
@ -1964,7 +1966,7 @@ static int parse_insn_line(struct todo_item *item, const char *bol, char *eol)
padding = strspn(bol, " \t"); padding = strspn(bol, " \t");
bol += padding; bol += padding;


if (item->command == TODO_NOOP) { if (item->command == TODO_NOOP || item->command == TODO_BREAK) {
if (bol != eol) if (bol != eol)
return error(_("%s does not accept arguments: '%s'"), return error(_("%s does not accept arguments: '%s'"),
command_to_string(item->command), bol); 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); 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[] = static const char rescheduled_advice[] =
N_("Could not execute the todo command\n" N_("Could not execute the todo command\n"
"\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_stopped_sha());
unlink(rebase_path_amend()); unlink(rebase_path_amend());
delete_ref(NULL, "REBASE_HEAD", NULL, REF_NO_DEREF); delete_ref(NULL, "REBASE_HEAD", NULL, REF_NO_DEREF);

if (item->command == TODO_BREAK)
return stopped_at_head();
} }
if (item->command <= TODO_SQUASH) { if (item->command <= TODO_SQUASH) {
if (is_rebase_i(opts)) if (is_rebase_i(opts))

2
t/lib-rebase.sh

@ -49,7 +49,7 @@ set_fake_editor () {
case $line in case $line in
squash|fixup|edit|reword|drop) squash|fixup|edit|reword|drop)
action="$line";; action="$line";;
exec*) exec*|break)
echo "$line" | sed 's/_/ /g' >> "$1";; echo "$line" | sed 's/_/ /g' >> "$1";;
"#") "#")
echo '# comment' >> "$1";; echo '# comment' >> "$1";;

9
t/t3418-rebase-continue.sh

@ -239,5 +239,14 @@ test_rerere_autoupdate -m
GIT_SEQUENCE_EDITOR=: && export GIT_SEQUENCE_EDITOR GIT_SEQUENCE_EDITOR=: && export GIT_SEQUENCE_EDITOR
test_rerere_autoupdate -i test_rerere_autoupdate -i
test_rerere_autoupdate --preserve-merges 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 test_done

Loading…
Cancel
Save