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

[RFC PATCH 13/13] revert: Introduce --continue to continue the operation

From
Ramkumar Ramachandra <artagnon@gmail.com>
Date
Jun 21, 2011, 13:04 UTC
Message-ID
<1308661489-20080-14-git-send-email-artagnon@gmail.com>
In-Reply-To
<1308661489-20080-1-git-send-email-artagnon@gmail.com>

After resolving a conflict, the user has the option to continue the operation. Mixing operations (cherry-pick and revert in the same todo_list) and command-line options are unsupported at this stage.

Signed-off-by: Ramkumar Ramachandra <artagnon@gmail.com>
---
 builtin/revert.c                |  127 +++++++++++++++++++++++++++++++++++++-
 t/t3510-cherry-pick-sequence.sh |   28 +++++++++
 2 files changed, 151 insertions(+), 4 deletions(-)
diff --git a/builtin/revert.c b/builtin/revert.c
index eb68068..7c28268 100644
--- a/builtin/revert.c
+++ b/builtin/revert.c
@@ -46,8 +46,9 @@ enum replay_action { REVERT, CHERRY_PICK };
 struct replay_opts {
 	enum replay_action action;
 
-	/* --skip-all */
+	/* --skip-all and --continue */
 	int skipall_oper;
+	int continue_oper;
 
 	/* Boolean options */
 	int edit;
@@ -106,12 +107,37 @@ static void verify_opt_compatible(const char *me, const char *base_opt, ...)
 	va_end(ap);
 }
 
+static void verify_opt_mutually_compatible(const char *me, ...)
+{
+	const char *opt1, *opt2;
+	va_list ap;
+	int set;
+
+	va_start(ap, me);
+	while ((opt1 = va_arg(ap, const char *))) {
+		set = va_arg(ap, int);
+		if (set)
+			break;
+	}
+	if (!opt1)
+		goto ok;
+	while ((opt2 = va_arg(ap, const char *))) {
+		set = va_arg(ap, int);
+		if (set)
+			die(_("%s: %s cannot be used with %s"),
+				me, opt1, opt2);
+	}
+ok:
+	va_end(ap);
+}
+
 static void parse_args(int argc, const char **argv, struct replay_opts *opts)
 {
 	const char * const * usage_str = revert_or_cherry_pick_usage(opts);
 	int noop;
 	struct option options[] = {
 		OPT_BOOLEAN(0, "skip-all", &opts->skipall_oper, "skip remaining instructions"),
+		OPT_BOOLEAN(0, "continue", &opts->continue_oper, "continue the current operation"),
 		OPT_BOOLEAN('n', "no-commit", &opts->no_commit, "don't automatically commit"),
 		OPT_BOOLEAN('e', "edit", &opts->edit, "edit the commit message"),
 		{ OPTION_BOOLEAN, 'r', NULL, &noop, NULL, "no-op (backward compatibility)",
@@ -141,9 +167,21 @@ static void parse_args(int argc, const char **argv, struct replay_opts *opts)
 					PARSE_OPT_KEEP_ARGV0 |
 					PARSE_OPT_KEEP_UNKNOWN);
 
+	/* Check for mutually incompatible command line arguments */
+	verify_opt_mutually_compatible(me,
+				"--skip-all", opts->skipall_oper,
+				"--continue", opts->continue_oper,
+				NULL);
+
 	/* Check for incompatible command line arguments */
-	if (opts->skipall_oper) {
-		verify_opt_compatible(me, "--skip-all",
+	if (opts->skipall_oper || opts->continue_oper) {
+		char *this_oper;
+		if (opts->skipall_oper)
+			this_oper = "--skip-all";
+		else
+			this_oper = "--continue";
+
+		verify_opt_compatible(me, this_oper,
 				"--no-commit", opts->no_commit,
 				"--signoff", opts->signoff,
 				"--mainline", opts->mainline,
@@ -614,6 +652,78 @@ static void format_todo(struct strbuf *buf, struct commit_list *todo_list,
 	}
 }
 
+static void read_populate_todo(struct commit_list **todo_list,
+			struct replay_opts *opts)
+{
+	struct strbuf buf = STRBUF_INIT;
+	enum replay_action action;
+	struct commit *commit;
+	struct commit_list *new_item;
+	struct commit_list *cur = NULL;
+	unsigned char commit_sha1[20];
+	char sha1_abbrev[40];
+	char *p;
+	int insn_len = 0;
+	char *insn;
+	int fd;
+
+	fd = open(TODO_FILE, O_RDONLY);
+	if (fd < 0) {
+		strbuf_release(&buf);
+		die_errno(_("Could not open %s."), TODO_FILE);
+	}
+	if (strbuf_read(&buf, fd, 0) < buf.len) {
+		close(fd);
+		strbuf_release(&buf);
+		die(_("Could not read %s."), TODO_FILE);
+	}
+	close(fd);
+
+	for (p = buf.buf; *p; p = strchr(p, '\n') + 1) {
+		insn = p;
+		if (!(p = strchr(p, ' ')))
+			goto error;
+		insn_len = p - insn;
+		if (!(p = strchr(p + 1, ' ')))
+			goto error;
+		p += 1;
+		strlcpy(sha1_abbrev, insn + insn_len + 1,
+			p - (insn + insn_len + 1));
+
+		if (!strncmp(insn, "pick", insn_len))
+			action = CHERRY_PICK;
+		else if (!strncmp(insn, "revert", insn_len))
+			action = REVERT;
+		else
+			goto error;
+
+		/* Verify that the action matches up with the one in
+		   opts; we don't support arbitrary instructions */
+		if (action != opts->action)
+			goto error;
+
+		/* Now create a commit corresponding to sha1_abbrev
+		   and put it into the todo_list */
+		if ((get_sha1(sha1_abbrev, commit_sha1) < 0)
+			|| !(commit = lookup_commit_reference(commit_sha1)))
+			goto error;
+		new_item = xmalloc(sizeof(struct commit_list));
+		new_item->item = commit;
+		if (cur)
+			cur->next = new_item;
+		else
+			*todo_list = new_item;
+		cur = new_item;
+	}
+	cur->next = NULL;
+	strbuf_release(&buf);
+
+	return;
+error:
+	strbuf_release(&buf);
+	die(_("Malformed instruction sheet: %s"), TODO_FILE);
+}
+
 static void walk_revs_populate_todo(struct commit_list **todo_list,
 				struct replay_opts *opts)
 {
@@ -720,13 +830,22 @@ static int process_continuation(struct replay_opts *opts)
 		if (!file_exists(TODO_FILE))
 			goto error;
 		return cleanup_sequencer_data();
+	} else if (opts->continue_oper) {
+		if (!file_exists(TODO_FILE))
+			goto error;
+		read_populate_todo(&todo_list, opts);
+
+		/* Verify that the conflict has been resolved */
+		if (!index_differs_from("HEAD", 0))
+			todo_list = todo_list->next;
 	} else {
 		/* Start a new cherry-pick/ revert sequence; but
 		   first, make sure that an existing one isn't in
 		   progress */
 		if (file_exists(TODO_FILE)) {
 			error(_("A %s is already in progress"), me);
-			advise(_("Use %s --skip-all to forget about it"), me);
+			advise(_("Use %s --continue to continue the operation"), me);
+			advise(_("or --skip-all to skip all the remaining instructions"), me);
 			return -1;
 		}
 
diff --git a/t/t3510-cherry-pick-sequence.sh b/t/t3510-cherry-pick-sequence.sh
index a797ae3..159be55 100644
--- a/t/t3510-cherry-pick-sequence.sh
+++ b/t/t3510-cherry-pick-sequence.sh
@@ -48,4 +48,32 @@ test_expect_success '--skip-all cleans up sequencer directory' '
 	test_must_fail test -d .git/sequencer
 '
 
+test_expect_success '--continue complains when no cherry-pick is in progress' '
+	pristine_detach initial &&
+	test_must_fail git cherry-pick --continue >actual 2>&1 &&
+	test_i18ngrep "error" actual
+'
+
+test_expect_success '--continue complains when there are unresolved conflicts' '
+	pristine_detach initial &&
+	head=$(git rev-parse HEAD) &&
+	test_must_fail git cherry-pick base..picked &&
+	test_must_fail git cherry-pick --continue &&
+	git cherry-pick --skip-all
+'
+
+test_expect_success '--continue continues after conflicts are resolved' '
+	pristine_detach initial &&
+	head=$(git rev-parse HEAD) &&
+	test_must_fail git cherry-pick base..picked &&
+	echo "resolved" >foo &&
+	git add foo &&
+	git commit &&
+	git cherry-pick --continue &&
+	test_must_fail test -d .git/sequencer &&
+	git rev-list --count HEAD >actual &&
+	echo 3 >expect &&
+	test_cmp expect actual
+'
+
 test_done
-- 
1.7.5.GIT
Previous: Ramkumar RamachandraNext: Jonathan Nieder
Message 45 of 47 in “Sequencer with continuation features”
  1. 00/13 Sequencer with continuation featuresRamkumar Ramachandra, Jun 21, 2011
  2. 01/13 advice: Introduce error_resolve_conflictRamkumar Ramachandra, Jun 21, 2011
  3. Jonathan NiederJun 21, 2011
  4. Junio C HamanoJun 21, 2011
  5. Ramkumar RamachandraJul 2, 2011
  6. Jonathan NiederJul 2, 2011
  7. 02/13 revert: Factor out add_message_to_msg functionRamkumar Ramachandra, Jun 21, 2011
  8. Jonathan NiederJun 21, 2011
  9. Junio C HamanoJun 21, 2011
  10. 03/13 revert: Don't check lone argument in get_encodingRamkumar Ramachandra, Jun 21, 2011
  11. Jonathan NiederJun 21, 2011
  12. 04/13 revert: Propogate errors upwards from do_pick_commitRamkumar Ramachandra, Jun 21, 2011
  13. Jonathan NiederJun 21, 2011
  14. Junio C HamanoJun 21, 2011
  15. Jonathan NiederJun 21, 2011
  16. Junio C HamanoJun 21, 2011
  17. Ramkumar RamachandraJul 2, 2011
  18. 05/13 revert: Eliminate global "commit" variableRamkumar Ramachandra, Jun 21, 2011
  19. Jonathan NiederJun 21, 2011
  20. Junio C HamanoJun 21, 2011
  21. 06/13 revert: Rename no_replay to record_originRamkumar Ramachandra, Jun 21, 2011
  22. 07/13 revert: Introduce struct to keep command-line optionsRamkumar Ramachandra, Jun 21, 2011
  23. Jonathan NiederJun 21, 2011
  24. Junio C HamanoJun 21, 2011
  25. 08/13 revert: Separate cmdline parsing from functional codeRamkumar Ramachandra, Jun 21, 2011
  26. Jonathan NiederJun 21, 2011
  27. 09/13 revert: Catch incompatible command-line options earlyRamkumar Ramachandra, Jun 21, 2011
  28. Jonathan NiederJun 21, 2011
  29. Ramkumar RamachandraJul 2, 2011
  30. Jonathan NiederJul 2, 2011
  31. Jonathan NiederJul 2, 2011
  32. Ramkumar RamachandraJul 2, 2011
  33. Jonathan NiederJul 2, 2011
  34. Jonathan NiederJul 2, 2011
  35. 10/13 revert: Persist data for continuationRamkumar Ramachandra, Jun 21, 2011
  36. Jonathan NiederJun 21, 2011
  37. Junio C HamanoJun 21, 2011
  38. 11/13 revert: Introduce a layer of indirection over pick_commitsRamkumar Ramachandra, Jun 21, 2011
  39. Junio C HamanoJun 21, 2011
  40. 12/13 revert: Introduce skip-all to cleanup sequencer dataRamkumar Ramachandra, Jun 21, 2011
  41. Junio C HamanoJun 21, 2011
  42. Ramkumar RamachandraJul 2, 2011
  43. Miles BaderJul 4, 2011
  44. Ramkumar RamachandraJul 5, 2011
  45. 13/13 revert: Introduce --continue to continue the operationRamkumar Ramachandra, Jun 21, 2011
  46. Jonathan NiederJun 21, 2011
  47. Jonathan NiederJun 21, 2011

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.