Web lists-archives.com

[PATCH/RFC 2/2] rebase: add --break switch

From: Phil Hord <phil.hord@xxxxxxxxx>

Expand the rebase edit switches to include the break switch. This
switch lets the user add a "break" instruction to the todo-list
before the mentioned reference.

This switch is a little different from the ones added so far because
it adds a new instruction between commits in the todo-list instead of
changing the command used to include a commit. It is a little like
"exec" in this regard, except it doesn't add the command after every

It is not immediately clear whether we should add the break command
before or after the referenced commit.  That is, when the user says
'--break ref', does she mean to break after ref is picked or before
it?  The answer comes when we realize that a 'break' after a ref
is functionally the same as '--edit ref'. Since the user didn't
say '--edit ref', clearly she must have wanted to break _before_ ref
is picked.  So, insert the break before the mentioned ref.

Annoyingly, however, when git stops at a break, it declares that the
previous commit is the one we stopped on, which is always different
from the one the user specified. Does anyone care?  Should --break
effectively be an alias for --edit?

    '--break <ref>' to stop the rebase before the mentioned commit

Signed-off-by: Phil Hord <phil.hord@xxxxxxxxx>
 builtin/rebase--interactive.c | 3 +++
 builtin/rebase.c              | 4 ++++
 sequencer.c                   | 7 +++++++
 sequencer.h                   | 1 +
 4 files changed, 15 insertions(+)

diff --git a/builtin/rebase--interactive.c b/builtin/rebase--interactive.c
index 9285d05443..a81fa9c1c5 100644
--- a/builtin/rebase--interactive.c
+++ b/builtin/rebase--interactive.c
@@ -164,6 +164,7 @@ static int resolve_commit_list(const struct string_list *str,
 static int resolve_edits_commit_list(struct sequence_edits *edits)
 	return resolve_commit_list(&edits->drop, &edits->revs) ||
+	       resolve_commit_list(&edits->breaks, &edits->revs) ||
 	       resolve_commit_list(&edits->edit, &edits->revs) ||
 	       resolve_commit_list(&edits->reword, &edits->revs);
@@ -302,6 +303,8 @@ int cmd_rebase__interactive(int argc, const char **argv, const char *prefix)
 			   N_("restrict-revision"), N_("restrict revision")),
 		OPT_STRING(0, "squash-onto", &squash_onto, N_("squash-onto"),
 			   N_("squash onto")),
+		OPT_STRING_LIST(0, "break", &edits.breaks, N_("revision"),
+				N_("stop before the mentioned ref")),
 		OPT_STRING_LIST(0, "drop", &edits.drop, N_("revision"),
 				N_("drop the mentioned ref from the "
 				   "todo list")),
diff --git a/builtin/rebase.c b/builtin/rebase.c
index a8101630cf..02079c4172 100644
--- a/builtin/rebase.c
+++ b/builtin/rebase.c
@@ -1053,6 +1053,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 					      NULL };
 	const char *gpg_sign = NULL;
 	struct string_list exec = STRING_LIST_INIT_NODUP;
+	struct string_list breaks = STRING_LIST_INIT_NODUP;
 	struct string_list reword = STRING_LIST_INIT_NODUP;
 	struct string_list edit = STRING_LIST_INIT_NODUP;
 	struct string_list drop = STRING_LIST_INIT_NODUP;
@@ -1138,6 +1139,8 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 		OPT_STRING_LIST('x', "exec", &exec, N_("exec"),
 				N_("add exec lines after each commit of the "
 				   "editable list")),
+		OPT_STRING_LIST(0, "break", &breaks, N_("revision"),
+				N_("stop before the mentioned ref")),
 		OPT_STRING_LIST(0, "drop", &drop, N_("revision"),
 				N_("drop the mentioned ref from the "
 				   "todo list")),
@@ -1404,6 +1407,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 		options.cmd = xstrdup(buf.buf);

+	forward_switches(&options, "--break", &breaks);
 	forward_switches(&options, "--drop", &drop);
 	forward_switches(&options, "--edit", &edit);
 	forward_switches(&options, "--reword", &reword);
diff --git a/sequencer.c b/sequencer.c
index d7384d987c..4a1a371757 100644
--- a/sequencer.c
+++ b/sequencer.c
@@ -4261,6 +4261,7 @@ static const char *label_oid(struct object_id *oid, const char *label,

 void free_sequence_edits(struct sequence_edits *edits)
+	string_list_clear(&edits->breaks, 0);
 	string_list_clear(&edits->drop, 0);
 	string_list_clear(&edits->edit, 0);
 	string_list_clear(&edits->reword, 0);
@@ -4294,6 +4295,7 @@ static int check_unused_refs(const struct string_list *refs)
 static int check_unused_edits(const struct sequence_edits *edits)
 	return check_unused_refs(&edits->drop) ||
+		check_unused_refs(&edits->breaks) ||
 		check_unused_refs(&edits->edit) ||
@@ -4320,6 +4322,11 @@ static void add_edit_todo_inst(struct strbuf *buf, const struct object_id *oid,
 	enum todo_command cmd = TODO_PICK;

+	if (consume_oid(oid, &edits->breaks)) {
+		add_todo_cmd(buf, TODO_BREAK, flags);
+		strbuf_addstr(buf, "\n");
+	}
 	if (consume_oid(oid, &edits->drop))
 		cmd = TODO_DROP;
 	else if (consume_oid(oid, &edits->edit))
diff --git a/sequencer.h b/sequencer.h
index 7887509fea..310829f222 100644
--- a/sequencer.h
+++ b/sequencer.h
@@ -139,6 +139,7 @@ int sequencer_remove_state(struct replay_opts *opts);
 struct sequence_edits {
 	struct commit_list *revs;
+	struct string_list breaks;
 	struct string_list drop;
 	struct string_list edit;
 	struct string_list reword;