sequencer (rebase -i): copy commit notes at end
[gitweb.git] / sequencer.c
index 95ae4bcd1e90cad5d4937c17276348aa01fbf949..50380a15b83d7df54cdc489bfff50e33dab7afe7 100644 (file)
@@ -95,6 +95,15 @@ static GIT_PATH_FUNC(rebase_path_amend, "rebase-merge/amend")
  * the abbreviated commit name of the corresponding patch.
  */
 static GIT_PATH_FUNC(rebase_path_stopped_sha, "rebase-merge/stopped-sha")
+/*
+ * For the post-rewrite hook, we make a list of rewritten commits and
+ * their new sha1s.  The rewritten-pending list keeps the sha1s of
+ * commits that have been processed, but not committed yet,
+ * e.g. because they are waiting for a 'squash' command.
+ */
+static GIT_PATH_FUNC(rebase_path_rewritten_list, "rebase-merge/rewritten-list")
+static GIT_PATH_FUNC(rebase_path_rewritten_pending,
+       "rebase-merge/rewritten-pending")
 /*
  * The following files are written by git-rebase just after parsing the
  * command-line (and are only consumed, not modified, by the sequencer).
@@ -850,6 +859,44 @@ static int update_squash_messages(enum todo_command command,
        return res;
 }
 
+static void flush_rewritten_pending(void) {
+       struct strbuf buf = STRBUF_INIT;
+       unsigned char newsha1[20];
+       FILE *out;
+
+       if (strbuf_read_file(&buf, rebase_path_rewritten_pending(), 82) > 0 &&
+                       !get_sha1("HEAD", newsha1) &&
+                       (out = fopen(rebase_path_rewritten_list(), "a"))) {
+               char *bol = buf.buf, *eol;
+
+               while (*bol) {
+                       eol = strchrnul(bol, '\n');
+                       fprintf(out, "%.*s %s\n", (int)(eol - bol),
+                                       bol, sha1_to_hex(newsha1));
+                       if (!*eol)
+                               break;
+                       bol = eol + 1;
+               }
+               fclose(out);
+               unlink(rebase_path_rewritten_pending());
+       }
+       strbuf_release(&buf);
+}
+
+static void record_in_rewritten(struct object_id *oid,
+               enum todo_command next_command) {
+       FILE *out = fopen(rebase_path_rewritten_pending(), "a");
+
+       if (!out)
+               return;
+
+       fprintf(out, "%s\n", oid_to_hex(oid));
+       fclose(out);
+
+       if (!is_fixup(next_command))
+               flush_rewritten_pending();
+}
+
 static int do_pick_commit(enum todo_command command, struct commit *commit,
                struct replay_opts *opts, int final_fixup)
 {
@@ -1743,6 +1790,17 @@ static int is_final_fixup(struct todo_list *todo_list)
        return 1;
 }
 
+static enum todo_command peek_command(struct todo_list *todo_list, int offset)
+{
+       int i;
+
+       for (i = todo_list->current + offset; i < todo_list->nr; i++)
+               if (!is_noop(todo_list->items[i].command))
+                       return todo_list->items[i].command;
+
+       return -1;
+}
+
 static const char *reflog_message(struct replay_opts *opts,
        const char *sub_action, const char *fmt, ...)
 {
@@ -1801,6 +1859,9 @@ static int pick_commits(struct todo_list *todo_list, struct replay_opts *opts)
                                        item->arg, item->arg_len, opts, res,
                                        !res);
                        }
+                       if (is_rebase_i(opts) && !res)
+                               record_in_rewritten(&item->commit->object.oid,
+                                       peek_command(todo_list, 1));
                        if (res && is_fixup(item->command)) {
                                if (res == 1)
                                        intend_to_amend();
@@ -1827,6 +1888,7 @@ static int pick_commits(struct todo_list *todo_list, struct replay_opts *opts)
 
        if (is_rebase_i(opts)) {
                struct strbuf head_ref = STRBUF_INIT, buf = STRBUF_INIT;
+               struct stat st;
 
                /* Stopped in the middle, as planned? */
                if (todo_list->current < todo_list->nr)
@@ -1891,6 +1953,20 @@ static int pick_commits(struct todo_list *todo_list, struct replay_opts *opts)
                                log_tree_diff_flush(&log_tree_opt);
                        }
                }
+               flush_rewritten_pending();
+               if (!stat(rebase_path_rewritten_list(), &st) &&
+                               st.st_size > 0) {
+                       struct child_process child = CHILD_PROCESS_INIT;
+
+                       child.in = open(rebase_path_rewritten_list(), O_RDONLY);
+                       child.git_cmd = 1;
+                       argv_array_push(&child.args, "notes");
+                       argv_array_push(&child.args, "copy");
+                       argv_array_push(&child.args, "--for-rewrite=rebase");
+                       /* we don't care if this copying failed */
+                       run_command(&child);
+               }
+
                strbuf_release(&buf);
                strbuf_release(&head_ref);
        }