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

[PATCH 6/8] revert: Introduce head, todo, done files to persist state

From
Ramkumar Ramachandra <artagnon@gmail.com>
Date
May 11, 2011, 08:00 UTC
Message-ID
<1305100822-20470-7-git-send-email-artagnon@gmail.com>
In-Reply-To
<1305100822-20470-1-git-send-email-artagnon@gmail.com>

A cherry-pick/ revert operation consists of several smaller steps. Later in the series, we would like to be able to resume a failed operation. As a prelude, we first need to persist the current state of operation. Introduce a "head" file to make note of the HEAD when the operation stated (so that the operation can be aborted), a "todo" file to keep the list of the steps to be performed, and a "done" file to keep a list of steps that have completed successfully. The format of these files is similar to the one used by the "rebase -i" process.

Helped-by: Christian Couder <chriscool@tuxfamily.org>
Signed-off-by: Ramkumar Ramachandra <artagnon@gmail.com>
---
 Note how I've used the words "operation" and "step" to differentiate
 between a picking/ reverting a single commit versus the entire
 operation in the commit message.  In one discussion involving
 Jonathan and Daniel, it was discussed that multiple meta-picking/
 reverting levels is a goal that is tangential to this project.  I
 only intend to support two levels: the overall "operation", and the
 composite "steps".
 builtin/revert.c |  117 +++++++++++++++++++++++++++++++++++++++++++++++++++---
 1 files changed, 111 insertions(+), 6 deletions(-)
diff --git a/builtin/revert.c b/builtin/revert.c
index 0fe87e8..13569c2 100644
--- a/builtin/revert.c
+++ b/builtin/revert.c
@@ -13,6 +13,7 @@
 #include "rerere.h"
 #include "merge-recursive.h"
 #include "refs.h"
+#include "dir.h"
 
 /*
  * This implements the builtins revert and cherry-pick.
@@ -25,6 +26,13 @@
  * Copyright (c) 2005 Junio C Hamano
  */
 
+#define SEQ_DIR "sequencer"
+
+#define SEQ_PATH	git_path(SEQ_DIR)
+#define HEAD_FILE	git_path(SEQ_DIR "/head")
+#define TODO_FILE	git_path(SEQ_DIR "/todo")
+#define DONE_FILE	git_path(SEQ_DIR "/done")
+
 static const char * const revert_usage[] = {
 	"git revert [options] <commit-ish>",
 	NULL
@@ -629,21 +637,118 @@ static int read_and_refresh_cache(struct replay_opts *opts)
 	return 0;
 }
 
+static int format_todo(struct strbuf *buf, struct commit_list *list,
+			struct replay_opts *opts)
+{
+	struct commit_list *cur = NULL;
+	struct commit_message msg = { NULL, NULL, NULL, NULL, NULL };
+	const char *sha1 = NULL;
+	const char *action;
+
+	action = (opts->action == REVERT ? "revert" : "pick");
+	for (cur = list; cur; cur = cur->next) {
+		sha1 = find_unique_abbrev(cur->item->object.sha1, DEFAULT_ABBREV);
+		if (get_message(cur->item, cur->item->buffer, &msg))
+			return error(_("Cannot get commit message for %s"), sha1);
+		strbuf_addf(buf, "%s %s %s\n", action, sha1, msg.subject);
+	}
+	return 0;
+}
+
+static int persist_initialize(unsigned char *head)
+{
+	struct strbuf buf = STRBUF_INIT;
+	int fd;
+
+	if (!file_exists(SEQ_PATH) && mkdir(SEQ_PATH, 0777)) {
+		int err = errno;
+		strbuf_release(&buf);
+		error(_("Could not create sequencer directory '%s': %s"),
+			SEQ_PATH, strerror(err));
+		return -err;
+	}
+
+	if ((fd = open(HEAD_FILE, O_WRONLY | O_CREAT | O_TRUNC, 0666)) < 0) {
+		int err = errno;
+		strbuf_release(&buf);
+		error(_("Could not open '%s' for writing: %s"),
+			HEAD_FILE, strerror(err));
+		return -err;
+	}
+
+	strbuf_addf(&buf, "%s", find_unique_abbrev(head, DEFAULT_ABBREV));
+	write_or_whine(fd, buf.buf, buf.len, HEAD_FILE);
+	close(fd);
+	strbuf_release(&buf);
+	return 0;
+}
+
+static int persist_todo_done(int res, struct commit_list *todo_list,
+			struct commit_list *done_list, struct replay_opts *opts)
+{
+	struct strbuf buf = STRBUF_INIT;
+	int fd, res2;
+
+	if (!res)
+		return 0;
+
+	/* TODO file */
+	if ((fd = open(TODO_FILE, O_WRONLY | O_CREAT | O_TRUNC, 0666)) < 0) {
+		int err = errno;
+		strbuf_release(&buf);
+		error(_("Could not open '%s' for writing: %s"),
+			TODO_FILE, strerror(err));
+		return -err;
+	}
+
+	if ((res2 = format_todo(&buf, todo_list, opts)))
+		return res2;
+	write_or_whine(fd, buf.buf, buf.len, TODO_FILE);
+	close(fd);
+
+	/* DONE file */
+	strbuf_reset(&buf);
+	if ((fd = open(DONE_FILE, O_WRONLY | O_CREAT | O_TRUNC, 0666)) < 0) {
+		int err = errno;
+		strbuf_release(&buf);
+		error(_("Could not open '%s' for writing: %s"),
+			DONE_FILE, strerror(err));
+		return -err;
+	}
+
+	if ((res2 = format_todo(&buf, done_list, opts)))
+		return res2;
+	write_or_whine(fd, buf.buf, buf.len, DONE_FILE);
+	close(fd);
+	strbuf_release(&buf);
+	return res;
+}
+
 static int pick_commits(struct replay_opts *opts)
 {
+	struct commit_list *done_list = NULL;
 	struct rev_info revs;
 	struct commit *commit;
+	unsigned char head[20];
 	int res;
 
+	if (get_sha1("HEAD", head))
+		return error(_("You do not have a valid HEAD"));
+
 	if ((res = read_and_refresh_cache(opts)) ||
-		(res = prepare_revs(&revs, opts)))
+		(res = prepare_revs(&revs, opts)) ||
+		(res = persist_initialize(head)))
 		return res;
 
-	while ((commit = get_revision(&revs)) &&
-		!(res = do_pick_commit(commit, opts)))
-		;
-
-	return res;
+	while ((commit = get_revision(&revs))) {
+		if (!(res = do_pick_commit(commit, opts)))
+			commit_list_insert(commit, &done_list);
+		else {
+			commit_list_insert(commit, &revs.commits);
+			break;
+		}
+	}
+	return persist_todo_done(res, revs.commits, done_list, opts);
 }
 
 int cmd_revert(int argc, const char **argv, const char *prefix)
-- 
1.7.5.GIT
Previous: Ramkumar RamachandraNext: Jonathan Nieder
Message 23 of 39 in “Sequencer Foundations”
  1. 0/8 Sequencer FoundationsRamkumar Ramachandra, May 11, 2011
  2. 1/8 revert: Improve error handling by cascading errors upwardsRamkumar Ramachandra, May 11, 2011
  3. Jonathan NiederMay 11, 2011
  4. Ramkumar RamachandraMay 13, 2011
  5. Ramkumar RamachandraMay 19, 2011
  6. 2/8 revert: Make "commit" and "me" local variablesRamkumar Ramachandra, May 11, 2011
  7. Jonathan NiederMay 11, 2011
  8. Ramkumar RamachandraMay 13, 2011
  9. Daniel BarkalowMay 13, 2011
  10. 3/8 revert: Introduce a struct to parse command-line options intoRamkumar Ramachandra, May 11, 2011
  11. Jonathan NiederMay 11, 2011
  12. Ramkumar RamachandraMay 13, 2011
  13. Jonathan NiederMay 13, 2011
  14. Ramkumar RamachandraMay 13, 2011
  15. 4/8 revert: Separate cmdline argument handling from the functional codeRamkumar Ramachandra, May 11, 2011
  16. Jonathan NiederMay 11, 2011
  17. Ramkumar RamachandraMay 13, 2011
  18. Ramkumar RamachandraMay 13, 2011
  19. Jonathan NiederMay 13, 2011
  20. 5/8 revert: Catch incompatible command-line options earlyRamkumar Ramachandra, May 11, 2011
  21. Jonathan NiederMay 11, 2011
  22. Ramkumar RamachandraMay 13, 2011
  23. 6/8 revert: Introduce head, todo, done files to persist stateRamkumar Ramachandra, May 11, 2011
  24. Jonathan NiederMay 11, 2011
  25. Ramkumar RamachandraMay 13, 2011
  26. 7/8 revert: Implement parsing --continue, --abort and --skipRamkumar Ramachandra, May 11, 2011
  27. Jonathan NiederMay 11, 2011
  28. Ramkumar RamachandraMay 13, 2011
  29. Jonathan NiederMay 13, 2011
  30. 8/8 revert: Implement --abort processingRamkumar Ramachandra, May 11, 2011
  31. Jonathan NiederMay 11, 2011
  32. Christian CouderMay 12, 2011
  33. Jonathan NiederMay 12, 2011
  34. Jonathan NiederMay 12, 2011
  35. Christian CouderMay 13, 2011
  36. Jonathan NiederMay 13, 2011
  37. Christian CouderMay 16, 2011
  38. Jonathan NiederMay 19, 2011
  39. Ramkumar RamachandraMay 20, 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.