Skip to content

Commit 71f8246

Browse files
dschogitster
authored andcommitted
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 <[email protected]> Signed-off-by: Johannes Schindelin <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent b8c0b21 commit 71f8246

File tree

5 files changed

+37
-2
lines changed

5 files changed

+37
-2
lines changed

Documentation/git-rebase.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -561,6 +561,9 @@ By replacing the command "pick" with the command "edit", you can tell
561561
the files and/or the commit message, amend the commit, and continue
562562
rebasing.
563563

564+
To interrupt the rebase (just like an "edit" command would do, but without
565+
cherry-picking any commit first), use the "break" command.
566+
564567
If you just want to edit the commit message for a commit, replace the
565568
command "pick" with the command "reword".
566569

rebase-interactive.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ void append_todo_help(unsigned edit_todo, unsigned keep_empty,
1414
"s, squash <commit> = use commit, but meld into previous commit\n"
1515
"f, fixup <commit> = like \"squash\", but discard this commit's log message\n"
1616
"x, exec <command> = run command (the rest of the line) using shell\n"
17+
"b, break = stop here (continue rebase later with 'git rebase --continue')\n"
1718
"d, drop <commit> = remove commit\n"
1819
"l, label <label> = label current HEAD with a name\n"
1920
"t, reset <label> = reset HEAD to a label\n"

sequencer.c

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1416,6 +1416,7 @@ enum todo_command {
14161416
TODO_SQUASH,
14171417
/* commands that do something else than handling a single commit */
14181418
TODO_EXEC,
1419+
TODO_BREAK,
14191420
TODO_LABEL,
14201421
TODO_RESET,
14211422
TODO_MERGE,
@@ -1437,6 +1438,7 @@ static struct {
14371438
{ 'f', "fixup" },
14381439
{ 's', "squash" },
14391440
{ 'x', "exec" },
1441+
{ 'b', "break" },
14401442
{ 'l', "label" },
14411443
{ 't', "reset" },
14421444
{ 'm', "merge" },
@@ -1964,7 +1966,7 @@ static int parse_insn_line(struct todo_item *item, const char *bol, char *eol)
19641966
padding = strspn(bol, " \t");
19651967
bol += padding;
19661968

1967-
if (item->command == TODO_NOOP) {
1969+
if (item->command == TODO_NOOP || item->command == TODO_BREAK) {
19681970
if (bol != eol)
19691971
return error(_("%s does not accept arguments: '%s'"),
19701972
command_to_string(item->command), bol);
@@ -3247,6 +3249,23 @@ static int checkout_onto(struct replay_opts *opts,
32473249
return update_ref(NULL, "ORIG_HEAD", &oid, NULL, 0, UPDATE_REFS_MSG_ON_ERR);
32483250
}
32493251

3252+
static int stopped_at_head(void)
3253+
{
3254+
struct object_id head;
3255+
struct commit *commit;
3256+
struct commit_message message;
3257+
3258+
if (get_oid("HEAD", &head) || !(commit = lookup_commit(&head)) ||
3259+
parse_commit(commit) || get_message(commit, &message))
3260+
fprintf(stderr, _("Stopped at HEAD\n"));
3261+
else {
3262+
fprintf(stderr, _("Stopped at %s\n"), message.label);
3263+
free_message(commit, &message);
3264+
}
3265+
return 0;
3266+
3267+
}
3268+
32503269
static const char rescheduled_advice[] =
32513270
N_("Could not execute the todo command\n"
32523271
"\n"
@@ -3293,6 +3312,9 @@ static int pick_commits(struct todo_list *todo_list, struct replay_opts *opts)
32933312
unlink(rebase_path_stopped_sha());
32943313
unlink(rebase_path_amend());
32953314
delete_ref(NULL, "REBASE_HEAD", NULL, REF_NO_DEREF);
3315+
3316+
if (item->command == TODO_BREAK)
3317+
return stopped_at_head();
32963318
}
32973319
if (item->command <= TODO_SQUASH) {
32983320
if (is_rebase_i(opts))

t/lib-rebase.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ set_fake_editor () {
4949
case $line in
5050
squash|fixup|edit|reword|drop)
5151
action="$line";;
52-
exec*)
52+
exec*|break)
5353
echo "$line" | sed 's/_/ /g' >> "$1";;
5454
"#")
5555
echo '# comment' >> "$1";;

t/t3418-rebase-continue.sh

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -239,5 +239,14 @@ test_rerere_autoupdate -m
239239
GIT_SEQUENCE_EDITOR=: && export GIT_SEQUENCE_EDITOR
240240
test_rerere_autoupdate -i
241241
test_rerere_autoupdate --preserve-merges
242+
unset GIT_SEQUENCE_EDITOR
243+
244+
test_expect_success 'the todo command "break" works' '
245+
rm -f execed &&
246+
FAKE_LINES="break exec_>execed" git rebase -i HEAD &&
247+
test_path_is_missing execed &&
248+
git rebase --continue &&
249+
test_path_is_file execed
250+
'
242251

243252
test_done

0 commit comments

Comments
 (0)