Merge branch 'nd/cherry-pick-quit-fix'
[gitweb.git] / sequencer.c
index af204d0cf118070b037120eec3a02c6ac2a59ca8..65d371c7461c1f8098e0334532ae7804c30f66d6 100644 (file)
@@ -654,6 +654,7 @@ static int write_author_script(const char *message)
                        strbuf_addch(&buf, *(message++));
                else
                        strbuf_addf(&buf, "'\\\\%c'", *(message++));
+       strbuf_addch(&buf, '\'');
        res = write_message(buf.buf, buf.len, rebase_path_author_script(), 1);
        strbuf_release(&buf);
        return res;
@@ -708,14 +709,16 @@ static const char *read_author_ident(struct strbuf *buf)
        const char *keys[] = {
                "GIT_AUTHOR_NAME=", "GIT_AUTHOR_EMAIL=", "GIT_AUTHOR_DATE="
        };
-       char *in, *out, *eol;
-       int i = 0, len;
+       struct strbuf out = STRBUF_INIT;
+       char *in, *eol;
+       const char *val[3];
+       int i = 0;
 
        if (strbuf_read_file(buf, rebase_path_author_script(), 256) <= 0)
                return NULL;
 
        /* dequote values and construct ident line in-place */
-       for (in = out = buf->buf; i < 3 && in - buf->buf < buf->len; i++) {
+       for (in = buf->buf; i < 3 && in - buf->buf < buf->len; i++) {
                if (!skip_prefix(in, keys[i], (const char **)&in)) {
                        warning(_("could not parse '%s' (looking for '%s'"),
                                rebase_path_author_script(), keys[i]);
@@ -724,17 +727,12 @@ static const char *read_author_ident(struct strbuf *buf)
 
                eol = strchrnul(in, '\n');
                *eol = '\0';
-               sq_dequote(in);
-               len = strlen(in);
-
-               if (i > 0) /* separate values by spaces */
-                       *(out++) = ' ';
-               if (i == 1) /* email needs to be surrounded by <...> */
-                       *(out++) = '<';
-               memmove(out, in, len);
-               out += len;
-               if (i == 1) /* email needs to be surrounded by <...> */
-                       *(out++) = '>';
+               if (!sq_dequote(in)) {
+                       warning(_("bad quoting on %s value in '%s'"),
+                               keys[i], rebase_path_author_script());
+                       return NULL;
+               }
+               val[i] = in;
                in = eol + 1;
        }
 
@@ -744,7 +742,18 @@ static const char *read_author_ident(struct strbuf *buf)
                return NULL;
        }
 
-       buf->len = out - buf->buf;
+       /* validate date since fmt_ident() will die() on bad value */
+       if (parse_date(val[2], &out)){
+               warning(_("invalid date format '%s' in '%s'"),
+                       val[2], rebase_path_author_script());
+               strbuf_release(&out);
+               return NULL;
+       }
+
+       strbuf_reset(&out);
+       strbuf_addstr(&out, fmt_ident(val[0], val[1], val[2], 0));
+       strbuf_swap(buf, &out);
+       strbuf_release(&out);
        return buf->buf;
 }
 
@@ -1244,7 +1253,7 @@ static int try_to_commit(struct strbuf *msg, const char *author,
                commit_list_insert(current_head, &parents);
        }
 
-       if (write_cache_as_tree(&tree, 0, NULL)) {
+       if (write_index_as_tree(&tree, &the_index, get_index_file(), 0, NULL)) {
                res = error(_("git write-tree failed to write a tree"));
                goto out;
        }
@@ -1543,13 +1552,13 @@ static int update_squash_messages(enum todo_command command,
                unlink(rebase_path_fixup_msg());
                strbuf_addf(&buf, "\n%c ", comment_line_char);
                strbuf_addf(&buf, _("This is the commit message #%d:"),
-                           ++opts->current_fixup_count);
+                           ++opts->current_fixup_count + 1);
                strbuf_addstr(&buf, "\n\n");
                strbuf_addstr(&buf, body);
        } else if (command == TODO_FIXUP) {
                strbuf_addf(&buf, "\n%c ", comment_line_char);
                strbuf_addf(&buf, _("The commit message #%d will be skipped:"),
-                           ++opts->current_fixup_count);
+                           ++opts->current_fixup_count + 1);
                strbuf_addstr(&buf, "\n\n");
                strbuf_add_commented_lines(&buf, body, strlen(body));
        } else
@@ -1630,7 +1639,7 @@ static int do_pick_commit(enum todo_command command, struct commit *commit,
                 * that represents the "current" state for merge-recursive
                 * to work on.
                 */
-               if (write_cache_as_tree(&head, 0, NULL))
+               if (write_index_as_tree(&head, &the_index, get_index_file(), 0, NULL))
                        return error(_("your index file is unmerged."));
        } else {
                unborn = get_oid("HEAD", &head);
@@ -2601,8 +2610,13 @@ static int error_with_patch(struct commit *commit,
        const char *subject, int subject_len,
        struct replay_opts *opts, int exit_code, int to_amend)
 {
-       if (make_patch(commit, opts))
-               return -1;
+       if (commit) {
+               if (make_patch(commit, opts))
+                       return -1;
+       } else if (copy_file(rebase_path_message(),
+                            git_path_merge_msg(the_repository), 0666))
+               return error(_("unable to copy '%s' to '%s'"),
+                            git_path_merge_msg(the_repository), rebase_path_message());
 
        if (to_amend) {
                if (intend_to_amend())
@@ -2617,9 +2631,18 @@ static int error_with_patch(struct commit *commit,
                          "\n"
                          "  git rebase --continue\n"),
                        gpg_sign_opt_quoted(opts));
-       } else if (exit_code)
-               fprintf_ln(stderr, _("Could not apply %s... %.*s"),
-                       short_commit_name(commit), subject_len, subject);
+       } else if (exit_code) {
+               if (commit)
+                       fprintf_ln(stderr, _("Could not apply %s... %.*s"),
+                                  short_commit_name(commit), subject_len, subject);
+               else
+                       /*
+                        * We don't have the hash of the parent so
+                        * just print the line from the todo file.
+                        */
+                       fprintf_ln(stderr, _("Could not merge %.*s"),
+                                  subject_len, subject);
+       }
 
        return exit_code;
 }
@@ -4246,10 +4269,9 @@ int sequencer_add_exec_commands(const char *commands)
 {
        const char *todo_file = rebase_path_todo();
        struct todo_list todo_list = TODO_LIST_INIT;
-       struct todo_item *item;
        struct strbuf *buf = &todo_list.buf;
        size_t offset = 0, commands_len = strlen(commands);
-       int i, first;
+       int i, insert;
 
        if (strbuf_read_file(&todo_list.buf, todo_file, 0) < 0)
                return error(_("could not read '%s'."), todo_file);
@@ -4259,19 +4281,40 @@ int sequencer_add_exec_commands(const char *commands)
                return error(_("unusable todo list: '%s'"), todo_file);
        }
 
-       first = 1;
-       /* insert <commands> before every pick except the first one */
-       for (item = todo_list.items, i = 0; i < todo_list.nr; i++, item++) {
-               if (item->command == TODO_PICK && !first) {
-                       strbuf_insert(buf, item->offset_in_buf + offset,
-                                     commands, commands_len);
+       /*
+        * Insert <commands> after every pick. Here, fixup/squash chains
+        * are considered part of the pick, so we insert the commands *after*
+        * those chains if there are any.
+        */
+       insert = -1;
+       for (i = 0; i < todo_list.nr; i++) {
+               enum todo_command command = todo_list.items[i].command;
+
+               if (insert >= 0) {
+                       /* skip fixup/squash chains */
+                       if (command == TODO_COMMENT)
+                               continue;
+                       else if (is_fixup(command)) {
+                               insert = i + 1;
+                               continue;
+                       }
+                       strbuf_insert(buf,
+                                     todo_list.items[insert].offset_in_buf +
+                                     offset, commands, commands_len);
                        offset += commands_len;
+                       insert = -1;
                }
-               first = 0;
+
+               if (command == TODO_PICK || command == TODO_MERGE)
+                       insert = i + 1;
        }
 
-       /* append final <commands> */
-       strbuf_add(buf, commands, commands_len);
+       /* insert or append final <commands> */
+       if (insert >= 0 && insert < todo_list.nr)
+               strbuf_insert(buf, todo_list.items[insert].offset_in_buf +
+                             offset, commands, commands_len);
+       else if (insert >= 0 || !offset)
+               strbuf_add(buf, commands, commands_len);
 
        i = write_message(buf->buf, buf->len, todo_file, 0);
        todo_list_release(&todo_list);