Thread (1 message) 1 message, 1 author, 2016-06-15

Re: [PATCH 10/13] revert: Persist data for continuation

From: Junio C Hamano <hidden>
Date: 2016-06-15 22:51:30

Ramkumar Ramachandra [off-list ref] writes:
...  Don't touch
CHERRY_PICK_HEAD -- it will still be useful when a conflict is
encountered.
What does "Don't touch" here mean? Keep doing the same thing as before so
that people can rely on it? Or stop touching it? I presume the former, but
the description is suboptimal.
quoted hunk
@@ -25,6 +26,10 @@
  * Copyright (c) 2005 Junio C Hamano
  */
 
+#define SEQ_DIR		git_path("sequencer")
+#define HEAD_FILE	git_path("sequencer/head")
+#define TODO_FILE	git_path("sequencer/todo")
HEAD is to keep track of the original, or does it get updated during a
sequencer run?
+static void walk_revs_populate_todo(struct commit_list **todo_list,
+				struct replay_opts *opts)
 {
 	struct rev_info revs;
 	struct commit *commit;
+	struct commit_list *new_item;
+	struct commit_list *cur = NULL;
+
+	/* Insert into todo_list in the same order */
+	prepare_revs(&revs, opts);
+	while ((commit = get_revision(&revs))) {
+		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;
+}
Yuck; you do not want if/else to do this (I am _not_ saying "you can do
that but here is a better way"). Have a variable that points at a pointer
of type "struct commit_list *", initialize it to where todo_list points
at, and then update to point at the next field of the new object.

Something like this:

	next = todo_list;
	while ((commit = ...) != NULL) {
		new = xcalloc(1, sizeof(struct commit_list));
                new->item = commit;
                *next = new;
                next = &new->next;
	}
	*next = NULL;

Doing it this way would avoid a segfault when get_revision() returned
nothing as an added bonus ;-).
+static void persist_head(const char *head)
s/persist/save/ perhaps?
+{
+	static struct lock_file head_lock;
+	struct strbuf buf = STRBUF_INIT;
+	int fd;
+
+	if (file_exists(SEQ_DIR)) {
+		if (!is_directory(SEQ_DIR) && remove_path(SEQ_DIR) < 0) {
+			strbuf_release(&buf);
+			die(_("Could not remove %s"), SEQ_DIR);
+		}
+	} else {
+		if (mkdir(SEQ_DIR, 0777) < 0) {
+			strbuf_release(&buf);
+			die_errno(_("Could not create sequencer directory '%s'."), SEQ_DIR);
+		}
+	}
Split this part into a separate helper.
+	fd = hold_lock_file_for_update(&head_lock, HEAD_FILE, LOCK_DIE_ON_ERROR);
+	strbuf_addf(&buf, "%s\n", head);
+	if (write_in_full(fd, buf.buf, buf.len) < 0)
+		die_errno(_("Could not write to %s."), HEAD_FILE);
+	if (commit_lock_file(&head_lock) < 0)
+		die(_("Error wrapping up %s"), HEAD_FILE);
+}
Is it sufficient to write the object name of the commit HEAD points at?
Would it be useful to also record the branch if the HEAD points at one?
+static void persist_todo(struct commit_list *todo_list, struct replay_opts *opts)
s/persist/save/ perhaps?
+{
+	static struct lock_file todo_lock;
+	struct strbuf buf = STRBUF_INIT;
+	int fd;
+	fd = hold_lock_file_for_update(&todo_lock, TODO_FILE, LOCK_DIE_ON_ERROR);
The current set of callers might always save head and then todo, but it
probably is a good idea to lift that restriction (which is why I suggested
to separate the initialization of seq-dir into a separate helper).
+static int pick_commits(struct replay_opts *opts)
+{
+	struct commit_list *todo_list = NULL;
+	unsigned char sha1[20];
+	struct commit_list *cur;
+	int res;
 
-	setenv(GIT_REFLOG_ACTION, me, 0);
 	read_and_refresh_cache(me, opts);
+	setenv(GIT_REFLOG_ACTION, me, 0);
Why?
-	prepare_revs(&revs, opts);
+	walk_revs_populate_todo(&todo_list, opts);
+	if (!get_sha1("HEAD", sha1))
+		persist_head(sha1_to_hex(sha1));
+	persist_todo(todo_list, opts);
 
-	while ((commit = get_revision(&revs))) {
-		int res = do_pick_commit(commit, opts);
+	for (cur = todo_list; cur; cur = cur->next) {
+		persist_todo(cur, opts);
+		res = do_pick_commit(cur->item, opts);
 		if (res)
 			return res;
 	}
 
-	return 0;
+	/* Sequence of picks finished successfully; cleanup by
+	   removing the .git/sequencer directory */
Just a style nit.

        /*
         * We write our multi-line comments
         * this way.
         */
+	return cleanup_sequencer_data();
 }
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help