git/list[1] front-page[2] threads[3] people[4] search[5] about
 

[PATCH v2 07/34] sequencer (rebase -i): add support for the 'fixup' and 'squash' commands

From
Johannes Schindelin <johannes.schindelin@gmx.de>
Date
Dec 13, 2016, 15:30 UTC
Message-ID
<ae521f75a105c6b9e54595d68bda3c5b62f313b6.1481642927.git.johannes.schindelin@gmx.de>
In-Reply-To
<cover.1481642927.git.johannes.schindelin@gmx.de>

This is a huge patch, and at the same time a huge step forward to execute the performance-critical parts of the interactive rebase in a builtin command.

Since 'fixup' and 'squash' are not only similar, but also need to know about each other (we want to reduce a series of fixups/squashes into a single, final commit message edit, from the user's point of view), we really have to implement them both at the same time.

Most of the actual work is done by the existing code path that already handles the "pick" and the "edit" commands; We added support for other features (e.g. to amend the commit message) in the patches leading up to this one, yet there are still quite a few bits in this patch that simply would not make sense as individual patches (such as: determining whether there was anything to "fix up" in the "todo" script, etc).

In theory, it would be possible to reuse the fast-forward code path also for the fixup and the squash code paths, but in practice this would make the code less readable. The end result cannot be fast-forwarded anyway, therefore let's just extend the cherry-picking code path for now.

Since the sequencer parses the entire `git-rebase-todo` script in one go, fixup or squash commands without a preceding pick can be reported early (in git-rebase--interactive, we could only report such errors just before executing the fixup/squash).

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 sequencer.c | 232 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 222 insertions(+), 10 deletions(-)
diff --git a/sequencer.c b/sequencer.c
index f6e20b142a..271c21581d 100644
--- a/sequencer.c
+++ b/sequencer.c
@@ -45,6 +45,35 @@ static GIT_PATH_FUNC(rebase_path_todo, "rebase-merge/git-rebase-todo")
  */
 static GIT_PATH_FUNC(rebase_path_done, "rebase-merge/done")
 /*
+ * The commit message that is planned to be used for any changes that
+ * need to be committed following a user interaction.
+ */
+static GIT_PATH_FUNC(rebase_path_message, "rebase-merge/message")
+/*
+ * The file into which is accumulated the suggested commit message for
+ * squash/fixup commands. When the first of a series of squash/fixups
+ * is seen, the file is created and the commit message from the
+ * previous commit and from the first squash/fixup commit are written
+ * to it. The commit message for each subsequent squash/fixup commit
+ * is appended to the file as it is processed.
+ *
+ * The first line of the file is of the form
+ *     # This is a combination of $count commits.
+ * where $count is the number of commits whose messages have been
+ * written to the file so far (including the initial "pick" commit).
+ * Each time that a commit message is processed, this line is read and
+ * updated. It is deleted just before the combined commit is made.
+ */
+static GIT_PATH_FUNC(rebase_path_squash_msg, "rebase-merge/message-squash")
+/*
+ * If the current series of squash/fixups has not yet included a squash
+ * command, then this file exists and holds the commit message of the
+ * original "pick" commit.  (If the series ends without a "squash"
+ * command, then this can be used as the commit message of the combined
+ * commit without opening the editor.)
+ */
+static GIT_PATH_FUNC(rebase_path_fixup_msg, "rebase-merge/message-fixup")
+/*
  * A script to set the GIT_AUTHOR_NAME, GIT_AUTHOR_EMAIL, and
  * GIT_AUTHOR_DATE that will be used for the commit that is currently
  * being rebased.
@@ -673,6 +702,8 @@ enum todo_command {
 	TODO_PICK = 0,
 	TODO_REVERT,
 	TODO_EDIT,
+	TODO_FIXUP,
+	TODO_SQUASH,
 	/* commands that do something else than handling a single commit */
 	TODO_EXEC,
 	/* commands that do nothing but are counted for reporting progress */
@@ -683,6 +714,8 @@ static const char *todo_command_strings[] = {
 	"pick",
 	"revert",
 	"edit",
+	"fixup",
+	"squash",
 	"exec",
 	"noop"
 };
@@ -694,16 +727,119 @@ static const char *command_to_string(const enum todo_command command)
 	die("Unknown command: %d", command);
 }
 
+static int is_fixup(enum todo_command command)
+{
+	return command == TODO_FIXUP || command == TODO_SQUASH;
+}
+
+static int update_squash_messages(enum todo_command command,
+		struct commit *commit, struct replay_opts *opts)
+{
+	struct strbuf buf = STRBUF_INIT;
+	int count, res;
+	const char *message, *body;
+
+	if (file_exists(rebase_path_squash_msg())) {
+		char *p, *p2;
+
+		if (strbuf_read_file(&buf, rebase_path_squash_msg(), 2048) <= 0)
+			return error(_("could not read '%s'"),
+				rebase_path_squash_msg());
+
+		if (buf.buf[0] != comment_line_char ||
+		    !skip_prefix(buf.buf + 1, " This is a combination of ",
+				 (const char **)&p))
+			return error(_("unexpected 1st line of squash message:"
+				       "\n\n\t%.*s"),
+				     (int)(strchrnul(buf.buf, '\n') - buf.buf),
+				     buf.buf);
+		count = strtol(p, &p2, 10);
+
+		if (count < 1 || *p2 != ' ')
+			return error(_("invalid 1st line of squash message:\n"
+				       "\n\t%.*s"),
+				     (int)(strchrnul(buf.buf, '\n') - buf.buf),
+				     buf.buf);
+
+		sprintf((char *)p, "%d", ++count);
+		if (!*p2)
+			*p2 = ' ';
+		else {
+			*(++p2) = 'c';
+			strbuf_insert(&buf, p2 - buf.buf, " ", 1);
+		}
+	}
+	else {
+		unsigned char head[20];
+		struct commit *head_commit;
+		const char *head_message, *body;
+
+		if (get_sha1("HEAD", head))
+			return error(_("need a HEAD to fixup"));
+		if (!(head_commit = lookup_commit_reference(head)))
+			return error(_("could not read HEAD"));
+		if (!(head_message = get_commit_buffer(head_commit, NULL)))
+			return error(_("could not read HEAD's commit message"));
+
+		body = strstr(head_message, "\n\n");
+		if (!body)
+			body = "";
+		else
+			body = skip_blank_lines(body + 2);
+		if (write_message(body, strlen(body),
+				  rebase_path_fixup_msg(), 0))
+			return error(_("cannot write '%s'"),
+				     rebase_path_fixup_msg());
+
+		count = 2;
+		strbuf_addf(&buf, _("%c This is a combination of 2 commits.\n"
+				    "%c The first commit's message is:\n\n%s"),
+			    comment_line_char, comment_line_char, body);
+
+		unuse_commit_buffer(head_commit, head_message);
+	}
+
+	if (!(message = get_commit_buffer(commit, NULL)))
+		return error(_("could not read commit message of %s"),
+			     oid_to_hex(&commit->object.oid));
+	body = strstr(message, "\n\n");
+	if (!body)
+		body = "";
+	else
+		body = skip_blank_lines(body + 2);
+
+	if (command == TODO_SQUASH) {
+		unlink(rebase_path_fixup_msg());
+		strbuf_addf(&buf, _("\n%c This is the commit message #%d:\n"
+				    "\n%s"),
+			    comment_line_char, count, body);
+	}
+	else if (command == TODO_FIXUP) {
+		strbuf_addf(&buf, _("\n%c The commit message #%d "
+				    "will be skipped:\n\n"),
+			    comment_line_char, count);
+		strbuf_add_commented_lines(&buf, body, strlen(body));
+	}
+	else
+		return error(_("unknown command: %d"), command);
+	unuse_commit_buffer(commit, message);
+
+	res = write_message(buf.buf, buf.len, rebase_path_squash_msg(), 0);
+	strbuf_release(&buf);
+	return res;
+}
 
 static int do_pick_commit(enum todo_command command, struct commit *commit,
-		struct replay_opts *opts)
+		struct replay_opts *opts, int final_fixup)
 {
+	int edit = opts->edit, cleanup_commit_message = 0;
+	const char *msg_file = edit ? NULL : git_path_merge_msg();
 	unsigned char head[20];
 	struct commit *base, *next, *parent;
 	const char *base_label, *next_label;
 	struct commit_message msg = { NULL, NULL, NULL, NULL };
 	struct strbuf msgbuf = STRBUF_INIT;
-	int res, unborn = 0, allow;
+	int res, unborn = 0, amend = 0, allow;
 
 	if (opts->no_commit) {
 		/*
@@ -749,7 +885,7 @@ static int do_pick_commit(enum todo_command command, struct commit *commit,
 	else
 		parent = commit->parents->item;
 
-	if (opts->allow_ff &&
+	if (opts->allow_ff && !is_fixup(command) &&
 	    ((parent && !hashcmp(parent->object.oid.hash, head)) ||
 	     (!parent && unborn)))
 		return fast_forward_to(commit->object.oid.hash, head, unborn, opts);
@@ -813,6 +949,28 @@ static int do_pick_commit(enum todo_command command, struct commit *commit,
 		}
 	}
 
+	if (is_fixup(command)) {
+		if (update_squash_messages(command, commit, opts))
+			return -1;
+		amend = 1;
+		if (!final_fixup)
+			msg_file = rebase_path_squash_msg();
+		else if (file_exists(rebase_path_fixup_msg())) {
+			cleanup_commit_message = 1;
+			msg_file = rebase_path_fixup_msg();
+		}
+		else {
+			const char *dest = git_path("SQUASH_MSG");
+			unlink(dest);
+			if (copy_file(dest, rebase_path_squash_msg(), 0666))
+				return error(_("could not rename '%s' to '%s'"),
+					     rebase_path_squash_msg(), dest);
+			unlink(git_path("MERGE_MSG"));
+			msg_file = dest;
+			edit = 1;
+		}
+	}
+
 	if (!opts->strategy || !strcmp(opts->strategy, "recursive") || command == TODO_REVERT) {
 		res = do_recursive_merge(base, next, base_label, next_label,
 					 head, &msgbuf, opts);
@@ -868,8 +1026,13 @@ static int do_pick_commit(enum todo_command command, struct commit *commit,
 		goto leave;
 	}
 	if (!opts->no_commit)
-		res = run_git_commit(opts->edit ? NULL : git_path_merge_msg(),
-				     opts, allow, opts->edit, 0, 0);
+		res = run_git_commit(msg_file, opts, allow, edit, amend,
+				     cleanup_commit_message);
+
+	if (!res && final_fixup) {
+		unlink(rebase_path_fixup_msg());
+		unlink(rebase_path_squash_msg());
+	}
 
 leave:
 	free_message(commit, &msg);
@@ -1009,7 +1172,7 @@ static int parse_insn_buffer(char *buf, struct todo_list *todo_list)
 {
 	struct todo_item *item;
 	char *p = buf, *next_p;
-	int i, res = 0;
+	int i, res = 0, fixup_okay = file_exists(rebase_path_done());
 
 	for (i = 1; *p; i++, p = next_p) {
 		char *eol = strchrnul(p, '\n');
@@ -1024,8 +1187,16 @@ static int parse_insn_buffer(char *buf, struct todo_list *todo_list)
 		if (parse_insn_line(item, p, eol)) {
 			res = error(_("invalid line %d: %.*s"),
 				i, (int)(eol - p), p);
-			item->command = -1;
+			item->command = TODO_NOOP;
 		}
+
+		if (fixup_okay)
+			; /* do nothing */
+		else if (is_fixup(item->command))
+			return error(_("cannot '%s' without a previous commit"),
+				command_to_string(item->command));
+		else if (item->command != TODO_NOOP)
+			fixup_okay = 1;
 	}
 	if (!todo_list->nr)
 		return error(_("no commits parsed."));
@@ -1434,6 +1605,20 @@ static int error_with_patch(struct commit *commit,
 	return exit_code;
 }
 
+static int error_failed_squash(struct commit *commit,
+	struct replay_opts *opts, int subject_len, const char *subject)
+{
+	if (rename(rebase_path_squash_msg(), rebase_path_message()))
+		return error(_("could not rename '%s' to '%s'"),
+			rebase_path_squash_msg(), rebase_path_message());
+	unlink(rebase_path_fixup_msg());
+	unlink(git_path("MERGE_MSG"));
+	if (copy_file(git_path("MERGE_MSG"), rebase_path_message(), 0666))
+		return error(_("could not copy '%s' to '%s'"),
+			     rebase_path_message(), git_path("MERGE_MSG"));
+	return error_with_patch(commit, subject, subject_len, opts, 1, 0);
+}
+
 static int do_exec(const char *command_line)
 {
 	const char *child_argv[] = { NULL, NULL };
@@ -1475,6 +1660,21 @@ static int do_exec(const char *command_line)
 	return status;
 }
 
+static int is_final_fixup(struct todo_list *todo_list)
+{
+	int i = todo_list->current;
+
+	if (!is_fixup(todo_list->items[i].command))
+		return 0;
+
+	while (++i < todo_list->nr)
+		if (is_fixup(todo_list->items[i].command))
+			return 0;
+		else if (todo_list->items[i].command < TODO_NOOP)
+			break;
+	return 1;
+}
+
 static int pick_commits(struct todo_list *todo_list, struct replay_opts *opts)
 {
 	int res = 0;
@@ -1490,9 +1690,15 @@ static int pick_commits(struct todo_list *todo_list, struct replay_opts *opts)
 		struct todo_item *item = todo_list->items + todo_list->current;
 		if (save_todo(todo_list, opts))
 			return -1;
-		if (item->command <= TODO_EDIT) {
+		if (is_rebase_i(opts)) {
+			unlink(rebase_path_message());
+			unlink(rebase_path_author_script());
+			unlink(rebase_path_stopped_sha());
+			unlink(rebase_path_amend());
+		}
+		if (item->command <= TODO_SQUASH) {
 			res = do_pick_commit(item->command, item->commit,
-					opts);
+					opts, is_final_fixup(todo_list));
 			if (item->command == TODO_EDIT) {
 				struct commit *commit = item->commit;
 				if (!res)
@@ -1503,6 +1709,12 @@ static int pick_commits(struct todo_list *todo_list, struct replay_opts *opts)
 					item->arg, item->arg_len, opts, res,
 					!res);
 			}
+			if (res && is_fixup(item->command)) {
+				if (res == 1)
+					intend_to_amend();
+				return error_failed_squash(item->commit, opts,
+					item->arg_len, item->arg);
+			}
 		}
 		else if (item->command == TODO_EXEC) {
 			char *end_of_arg = (char *)(item->arg + item->arg_len);
@@ -1597,7 +1809,7 @@ static int single_pick(struct commit *cmit, struct replay_opts *opts)
 {
 	setenv(GIT_REFLOG_ACTION, action_name(opts), 0);
 	return do_pick_commit(opts->action == REPLAY_PICK ?
-		TODO_PICK : TODO_REVERT, cmit, opts);
+		TODO_PICK : TODO_REVERT, cmit, opts, 0);
 }
 
 int sequencer_pick_revisions(struct replay_opts *opts)
-- 
2.11.0.rc3.windows.1
Previous: Junio C HamanoNext: Junio C Hamano
Message 86 of 212 in “Teach the sequencer to act as rebase -i's backend”
  1. 00/34 Teach the sequencer to act as rebase -i's backendJohannes Schindelin, Aug 31, 2016
  2. 07/34 sequencer (rebase -i): add support for the 'fixup' and 'squash' commandsJohannes Schindelin, Aug 31, 2016
  3. Dennis KaarsemakerSep 1, 2016
  4. Johannes SchindelinSep 1, 2016
  5. Dennis KaarsemakerSep 1, 2016
  6. Johannes SchindelinSep 2, 2016
  7. Dennis KaarsemakerSep 2, 2016
  8. Johannes SchindelinSep 2, 2016
  9. Dennis KaarsemakerSep 2, 2016
  10. Junio C HamanoSep 1, 2016
  11. Johannes SchindelinSep 2, 2016
  12. 05/34 sequencer (rebase -i): learn about the 'verbose' modeJohannes Schindelin, Aug 31, 2016
  13. Dennis KaarsemakerAug 31, 2016
  14. Johannes SchindelinAug 31, 2016
  15. 04/34 sequencer (rebase -i): implement the 'exec' commandJohannes Schindelin, Aug 31, 2016
  16. 03/34 sequencer (rebase -i): implement the 'edit' commandJohannes Schindelin, Aug 31, 2016
  17. 02/34 sequencer (rebase -i): implement the 'noop' commandJohannes Schindelin, Aug 31, 2016
  18. 01/34 sequencer: support a new action: 'interactive rebase'Johannes Schindelin, Aug 31, 2016
  19. Kevin DaudtSep 2, 2016
  20. Johannes SchindelinSep 3, 2016
  21. 08/34 sequencer (rebase -i): implement the short commandsJohannes Schindelin, Aug 31, 2016
  22. 09/34 sequencer (rebase -i): write an author-script fileJohannes Schindelin, Aug 31, 2016
  23. 12/34 sequencer (rebase -i): skip some revert/cherry-pick specific code pathJohannes Schindelin, Aug 31, 2016
  24. 11/34 sequencer (rebase -i): remove CHERRY_PICK_HEAD when no longer neededJohannes Schindelin, Aug 31, 2016
  25. 13/34 sequencer (rebase -i): the todo can be empty when continuingJohannes Schindelin, Aug 31, 2016
  26. 10/34 sequencer (rebase -i): allow continuing with staged changesJohannes Schindelin, Aug 31, 2016
  27. 16/34 sequencer (rebase -i): implement the 'reword' commandJohannes Schindelin, Aug 31, 2016
  28. 19/34 sequencer (rebase -i): set the reflog message consistentlyJohannes Schindelin, Aug 31, 2016
  29. 18/34 sequencer (rebase -i): refactor setting the reflog messageJohannes Schindelin, Aug 31, 2016
  30. 21/34 sequencer (rebase -i): record interrupted commits in rewritten, tooJohannes Schindelin, Aug 31, 2016
  31. 20/34 sequencer (rebase -i): copy commit notes at endJohannes Schindelin, Aug 31, 2016
  32. Dennis KaarsemakerSep 1, 2016
  33. Johannes SchindelinSep 1, 2016
  34. 22/34 sequencer (rebase -i): run the post-rewrite hook, if neededJohannes Schindelin, Aug 31, 2016
  35. 26/34 sequencer (rebase -i): implement the 'drop' commandJohannes Schindelin, Aug 31, 2016
  36. 23/34 sequencer (rebase -i): respect the rebase.autostash settingJohannes Schindelin, Aug 31, 2016
  37. 27/34 sequencer (rebase -i): differentiate between comments and 'noop'Johannes Schindelin, Aug 31, 2016
  38. Dennis KaarsemakerSep 1, 2016
  39. Johannes SchindelinSep 1, 2016
  40. Dennis KaarsemakerSep 1, 2016
  41. Johannes SchindelinSep 2, 2016
  42. 24/34 sequencer (rebase -i): respect strategy/strategy_opts settingsJohannes Schindelin, Aug 31, 2016
  43. 25/34 sequencer (rebase -i): allow rescheduling commandsJohannes Schindelin, Aug 31, 2016
  44. 17/34 sequencer (rebase -i): allow fast-forwarding for edit/rewordJohannes Schindelin, Aug 31, 2016
  45. 28/34 run_command_opt(): optionally hide stderr when the command succeedsJohannes Schindelin, Aug 31, 2016
  46. 29/34 sequencer (rebase -i): show only failed `git commit`'s outputJohannes Schindelin, Aug 31, 2016
  47. 31/34 sequencer (rebase -i): suggest --edit-todo upon unknown commandJohannes Schindelin, Aug 31, 2016
  48. 32/34 sequencer (rebase -i): show the progressJohannes Schindelin, Aug 31, 2016
  49. Dennis KaarsemakerSep 1, 2016
  50. Johannes SchindelinSep 1, 2016
  51. 33/34 sequencer (rebase -i): write the progress into filesJohannes Schindelin, Aug 31, 2016
  52. 30/34 sequencer (rebase -i): show only failed cherry-picks' outputJohannes Schindelin, Aug 31, 2016
  53. 34/34 sequencer (rebase -i): write out the final messageJohannes Schindelin, Aug 31, 2016
  54. 15/34 sequencer (rebase -i): leave a patch upon errorJohannes Schindelin, Aug 31, 2016
  55. Dennis KaarsemakerAug 31, 2016
  56. Johannes SchindelinSep 1, 2016
  57. 06/34 sequencer (rebase -i): write the 'done' fileJohannes Schindelin, Aug 31, 2016
  58. Dennis KaarsemakerAug 31, 2016
  59. Johannes SchindelinSep 1, 2016
  60. 14/34 sequencer (rebase -i): update refs after a successful rebaseJohannes Schindelin, Aug 31, 2016
  61. Dennis KaarsemakerAug 31, 2016
  62. Johannes SchindelinSep 1, 2016
  63. 00/34 Teach the sequencer to act as rebase -i's backendJohannes Schindelin, Dec 13, 2016
  64. 04/34 sequencer (rebase -i): implement the 'exec' commandJohannes Schindelin, Dec 13, 2016
  65. Junio C HamanoDec 13, 2016
  66. Johannes SchindelinDec 19, 2016
  67. 03/34 sequencer (rebase -i): implement the 'edit' commandJohannes Schindelin, Dec 13, 2016
  68. Junio C HamanoDec 13, 2016
  69. Johannes SchindelinDec 19, 2016
  70. Junio C HamanoDec 19, 2016
  71. Junio C HamanoDec 19, 2016
  72. 12/34 sequencer (rebase -i): skip some revert/cherry-pick specific code pathJohannes Schindelin, Dec 13, 2016
  73. 14/34 sequencer (rebase -i): update refs after a successful rebaseJohannes Schindelin, Dec 13, 2016
  74. Junio C HamanoDec 16, 2016
  75. Johannes SchindelinDec 19, 2016
  76. 27/34 sequencer (rebase -i): differentiate between comments and 'noop'Johannes Schindelin, Dec 13, 2016
  77. Junio C HamanoDec 19, 2016
  78. 06/34 sequencer (rebase -i): write the 'done' fileJohannes Schindelin, Dec 13, 2016
  79. Junio C HamanoDec 13, 2016
  80. 05/34 sequencer (rebase -i): learn about the 'verbose' modeJohannes Schindelin, Dec 13, 2016
  81. Junio C HamanoDec 13, 2016
  82. Junio C HamanoDec 14, 2016
  83. Johannes SchindelinJan 2, 2017
  84. Junio C HamanoJan 7, 2017
  85. Junio C HamanoJan 8, 2017
  86. 07/34 sequencer (rebase -i): add support for the 'fixup' and 'squash' commandsJohannes Schindelin, Dec 13, 2016
  87. Junio C HamanoDec 15, 2016
  88. Jeff KingDec 15, 2016
  89. Johannes SchindelinDec 19, 2016
  90. Jeff KingDec 19, 2016
  91. Johannes SchindelinDec 19, 2016
  92. Jeff KingDec 15, 2016
  93. Stefan BellerDec 15, 2016
  94. Jeff KingDec 15, 2016
  95. Stefan BellerDec 15, 2016
  96. Johannes SchindelinDec 19, 2016
  97. 13/34 sequencer (rebase -i): the todo can be empty when continuingJohannes Schindelin, Dec 13, 2016
  98. 28/34 run_command_opt(): optionally hide stderr when the command succeedsJohannes Schindelin, Dec 13, 2016
  99. Johannes SixtDec 14, 2016
  100. Jeff KingDec 14, 2016
  101. Jeff KingDec 14, 2016
  102. Johannes SixtDec 14, 2016
  103. Johannes SchindelinJan 2, 2017
  104. 26/34 sequencer (rebase -i): implement the 'drop' commandJohannes Schindelin, Dec 13, 2016
  105. 15/34 sequencer (rebase -i): leave a patch upon errorJohannes Schindelin, Dec 13, 2016
  106. Junio C HamanoDec 16, 2016
  107. 25/34 sequencer (rebase -i): allow rescheduling commandsJohannes Schindelin, Dec 13, 2016
  108. 24/34 sequencer (rebase -i): respect strategy/strategy_opts settingsJohannes Schindelin, Dec 13, 2016
  109. Junio C HamanoDec 19, 2016
  110. 20/34 sequencer (rebase -i): copy commit notes at endJohannes Schindelin, Dec 13, 2016
  111. Junio C HamanoDec 16, 2016
  112. Johannes SchindelinJan 2, 2017
  113. 23/34 sequencer (rebase -i): respect the rebase.autostash settingJohannes Schindelin, Dec 13, 2016
  114. 22/34 sequencer (rebase -i): run the post-rewrite hook, if neededJohannes Schindelin, Dec 13, 2016
  115. 19/34 sequencer (rebase -i): set the reflog message consistentlyJohannes Schindelin, Dec 13, 2016
  116. 21/34 sequencer (rebase -i): record interrupted commits in rewritten, tooJohannes Schindelin, Dec 13, 2016
  117. 18/34 sequencer (rebase -i): refactor setting the reflog messageJohannes Schindelin, Dec 13, 2016
  118. Junio C HamanoDec 16, 2016
  119. 17/34 sequencer (rebase -i): allow fast-forwarding for edit/rewordJohannes Schindelin, Dec 13, 2016
  120. 16/34 sequencer (rebase -i): implement the 'reword' commandJohannes Schindelin, Dec 13, 2016
  121. 32/34 sequencer (rebase -i): show the progressJohannes Schindelin, Dec 13, 2016
  122. Junio C HamanoDec 19, 2016
  123. 33/34 sequencer (rebase -i): write the progress into filesJohannes Schindelin, Dec 13, 2016
  124. 34/34 sequencer (rebase -i): write out the final messageJohannes Schindelin, Dec 13, 2016
  125. 31/34 sequencer (rebase -i): suggest --edit-todo upon unknown commandJohannes Schindelin, Dec 13, 2016
  126. 01/34 sequencer: support a new action: 'interactive rebase'Johannes Schindelin, Dec 13, 2016
  127. Junio C HamanoDec 13, 2016
  128. Johannes SchindelinDec 19, 2016
  129. Junio C HamanoDec 14, 2016
  130. Stephan BeyerDec 17, 2016
  131. Johannes SchindelinDec 19, 2016
  132. Stephan BeyerDec 19, 2016
  133. 02/34 sequencer (rebase -i): implement the 'noop' commandJohannes Schindelin, Dec 13, 2016
  134. Junio C HamanoDec 13, 2016
  135. Linus TorvaldsDec 13, 2016
  136. Junio C HamanoDec 13, 2016
  137. Johannes SchindelinDec 19, 2016
  138. Junio C HamanoDec 19, 2016
  139. Johannes SchindelinDec 19, 2016
  140. 08/34 sequencer (rebase -i): implement the short commandsJohannes Schindelin, Dec 13, 2016
  141. Junio C HamanoDec 15, 2016
  142. 09/34 sequencer (rebase -i): write an author-script fileJohannes Schindelin, Dec 13, 2016
  143. Junio C HamanoDec 15, 2016
  144. Johannes SchindelinDec 19, 2016
  145. Junio C HamanoDec 20, 2016
  146. Junio C HamanoDec 20, 2016
  147. 10/34 sequencer (rebase -i): allow continuing with staged changesJohannes Schindelin, Dec 13, 2016
  148. Junio C HamanoDec 15, 2016
  149. 11/34 sequencer (rebase -i): remove CHERRY_PICK_HEAD when no longer neededJohannes Schindelin, Dec 13, 2016
  150. Junio C HamanoDec 16, 2016
  151. Johannes SchindelinDec 19, 2016
  152. 30/34 sequencer (rebase -i): show only failed cherry-picks' outputJohannes Schindelin, Dec 13, 2016
  153. 29/34 sequencer (rebase -i): show only failed `git commit`'s outputJohannes Schindelin, Dec 13, 2016
  154. Junio C HamanoDec 13, 2016
  155. Johannes SchindelinDec 19, 2016
  156. Johannes SixtDec 14, 2016
  157. Johannes SchindelinDec 19, 2016
  158. 00/38 Teach the sequencer to act as rebase -i's backendJohannes Schindelin, Jan 2, 2017
  159. 02/38 sequencer: move "else" keyword onto the same line as preceding braceJohannes Schindelin, Jan 2, 2017
  160. Junio C HamanoJan 12, 2017
  161. 01/38 sequencer: avoid unnecessary curly bracesJohannes Schindelin, Jan 2, 2017
  162. Junio C HamanoJan 12, 2017
  163. Johannes SchindelinJan 14, 2017
  164. Jeff KingJan 14, 2017
  165. Jacob KellerJan 16, 2017
  166. 03/38 sequencer: use a helper to find the commit messageJohannes Schindelin, Jan 2, 2017
  167. Junio C HamanoJan 12, 2017
  168. 04/38 sequencer: support a new action: 'interactive rebase'Johannes Schindelin, Jan 2, 2017
  169. 05/38 sequencer (rebase -i): implement the 'noop' commandJohannes Schindelin, Jan 2, 2017
  170. 06/38 sequencer (rebase -i): implement the 'edit' commandJohannes Schindelin, Jan 2, 2017
  171. Junio C HamanoJan 12, 2017
  172. Johannes SchindelinJan 14, 2017
  173. 07/38 sequencer (rebase -i): implement the 'exec' commandJohannes Schindelin, Jan 2, 2017
  174. 08/38 sequencer (rebase -i): learn about the 'verbose' modeJohannes Schindelin, Jan 2, 2017
  175. 09/38 sequencer (rebase -i): write the 'done' fileJohannes Schindelin, Jan 2, 2017
  176. 11/38 sequencer (rebase -i): implement the short commandsJohannes Schindelin, Jan 2, 2017
  177. 10/38 sequencer (rebase -i): add support for the 'fixup' and 'squash' commandsJohannes Schindelin, Jan 2, 2017
  178. 12/38 sequencer (rebase -i): write an author-script fileJohannes Schindelin, Jan 2, 2017
  179. 15/38 sequencer (rebase -i): skip some revert/cherry-pick specific code pathJohannes Schindelin, Jan 2, 2017
  180. 14/38 sequencer (rebase -i): remove CHERRY_PICK_HEAD when no longer neededJohannes Schindelin, Jan 2, 2017
  181. 13/38 sequencer (rebase -i): allow continuing with staged changesJohannes Schindelin, Jan 2, 2017
  182. 16/38 sequencer (rebase -i): the todo can be empty when continuingJohannes Schindelin, Jan 2, 2017
  183. 18/38 sequencer (rebase -i): leave a patch upon errorJohannes Schindelin, Jan 2, 2017
  184. 17/38 sequencer (rebase -i): update refs after a successful rebaseJohannes Schindelin, Jan 2, 2017
  185. 19/38 sequencer (rebase -i): implement the 'reword' commandJohannes Schindelin, Jan 2, 2017
  186. 21/38 sequencer (rebase -i): refactor setting the reflog messageJohannes Schindelin, Jan 2, 2017
  187. 23/38 sequencer (rebase -i): copy commit notes at endJohannes Schindelin, Jan 2, 2017
  188. 20/38 sequencer (rebase -i): allow fast-forwarding for edit/rewordJohannes Schindelin, Jan 2, 2017
  189. 24/38 sequencer (rebase -i): record interrupted commits in rewritten, tooJohannes Schindelin, Jan 2, 2017
  190. 25/38 sequencer (rebase -i): run the post-rewrite hook, if neededJohannes Schindelin, Jan 2, 2017
  191. 22/38 sequencer (rebase -i): set the reflog message consistentlyJohannes Schindelin, Jan 2, 2017
  192. 26/38 sequencer (rebase -i): respect the rebase.autostash settingJohannes Schindelin, Jan 2, 2017
  193. 27/38 sequencer (rebase -i): respect strategy/strategy_opts settingsJohannes Schindelin, Jan 2, 2017
  194. 28/38 sequencer (rebase -i): allow rescheduling commandsJohannes Schindelin, Jan 2, 2017
  195. 29/38 sequencer (rebase -i): implement the 'drop' commandJohannes Schindelin, Jan 2, 2017
  196. 30/38 sequencer (rebase -i): differentiate between comments and 'noop'Johannes Schindelin, Jan 2, 2017
  197. 32/38 sequencer: use run_command() directlyJohannes Schindelin, Jan 2, 2017
  198. 33/38 sequencer (rebase -i): show only failed `git commit`'s outputJohannes Schindelin, Jan 2, 2017
  199. 31/38 sequencer: make reading author-script more elegantJohannes Schindelin, Jan 2, 2017
  200. 34/38 sequencer (rebase -i): show only failed cherry-picks' outputJohannes Schindelin, Jan 2, 2017
  201. 35/38 sequencer (rebase -i): suggest --edit-todo upon unknown commandJohannes Schindelin, Jan 2, 2017
  202. 36/38 sequencer (rebase -i): show the progressJohannes Schindelin, Jan 2, 2017
  203. 37/38 sequencer (rebase -i): write the progress into filesJohannes Schindelin, Jan 2, 2017
  204. 38/38 sequencer (rebase -i): write out the final messageJohannes Schindelin, Jan 2, 2017
  205. Junio C HamanoJan 9, 2017
  206. Junio C HamanoJan 9, 2017
  207. Johannes SchindelinJan 14, 2017
  208. Junio C HamanoJan 15, 2017
  209. Johannes SchindelinJan 14, 2017
  210. Junio C HamanoJan 15, 2017
  211. Johannes SchindelinJan 16, 2017
  212. Junio C HamanoJan 17, 2017

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.