Merge branch 'pw/rebase-i-regression-fix'
authorJunio C Hamano <gitster@pobox.com>
Mon, 29 May 2017 03:34:51 +0000 (12:34 +0900)
committerJunio C Hamano <gitster@pobox.com>
Mon, 29 May 2017 03:34:51 +0000 (12:34 +0900)
Regression fix to topic recently merged to 'master'.

* pw/rebase-i-regression-fix:
rebase -i: add missing newline to end of message
rebase -i: silence stash apply
rebase -i: fix reflog message

1  2 
sequencer.c
diff --combined sequencer.c
index 9dfedbc2431e4d6fd2055e9f5689f1c530e34e57,dc7573940ac8c992f01901845112343462728a99..a23b948ac148304dbebfe38955ec8b40cab3e1e5
@@@ -344,7 -344,7 +344,7 @@@ static int read_oneliner(struct strbuf 
  
  static struct tree *empty_tree(void)
  {
 -      return lookup_tree(EMPTY_TREE_SHA1_BIN);
 +      return lookup_tree(&empty_tree_oid);
  }
  
  static int error_dirty_index(struct replay_opts *opts)
@@@ -374,7 -374,7 +374,7 @@@ static void update_abort_safety_file(vo
                write_file(git_path_abort_safety_file(), "%s", "");
  }
  
 -static int fast_forward_to(const unsigned char *to, const unsigned char *from,
 +static int fast_forward_to(const struct object_id *to, const struct object_id *from,
                        int unborn, struct replay_opts *opts)
  {
        struct ref_transaction *transaction;
        transaction = ref_transaction_begin(&err);
        if (!transaction ||
            ref_transaction_update(transaction, "HEAD",
 -                                 to, unborn ? null_sha1 : from,
 +                                 to->hash, unborn ? null_sha1 : from->hash,
                                   0, sb.buf, &err) ||
            ref_transaction_commit(transaction, &err)) {
                ref_transaction_free(transaction);
@@@ -426,7 -426,7 +426,7 @@@ void append_conflicts_hint(struct strbu
  
  static int do_recursive_merge(struct commit *base, struct commit *next,
                              const char *base_label, const char *next_label,
 -                            unsigned char *head, struct strbuf *msgbuf,
 +                            struct object_id *head, struct strbuf *msgbuf,
                              struct replay_opts *opts)
  {
        struct merge_options o;
  
  static int is_index_unchanged(void)
  {
 -      unsigned char head_sha1[20];
 +      struct object_id head_oid;
        struct commit *head_commit;
  
 -      if (!resolve_ref_unsafe("HEAD", RESOLVE_REF_READING, head_sha1, NULL))
 +      if (!resolve_ref_unsafe("HEAD", RESOLVE_REF_READING, head_oid.hash, NULL))
                return error(_("could not resolve HEAD commit\n"));
  
 -      head_commit = lookup_commit(head_sha1);
 +      head_commit = lookup_commit(&head_oid);
  
        /*
         * If head_commit is NULL, check_commit, called from
                if (cache_tree_update(&the_index, 0))
                        return error(_("unable to update cache tree\n"));
  
 -      return !hashcmp(active_cache_tree->sha1, head_commit->tree->object.oid.hash);
 +      return !oidcmp(&active_cache_tree->oid,
 +                     &head_commit->tree->object.oid);
  }
  
  static int write_author_script(const char *message)
@@@ -603,12 -602,6 +603,12 @@@ N_("you have staged changes in your wor
  "\n"
  "  git rebase --continue\n");
  
 +#define ALLOW_EMPTY (1<<0)
 +#define EDIT_MSG    (1<<1)
 +#define AMEND_MSG   (1<<2)
 +#define CLEANUP_MSG (1<<3)
 +#define VERIFY_MSG  (1<<4)
 +
  /*
   * If we are cherry-pick, and if the merge did not result in
   * hand-editing, we will hit this commit and inherit the original
   * author metadata.
   */
  static int run_git_commit(const char *defmsg, struct replay_opts *opts,
 -                        int allow_empty, int edit, int amend,
 -                        int cleanup_commit_message)
 +                        unsigned int flags)
  {
        struct child_process cmd = CHILD_PROCESS_INIT;
        const char *value;
        cmd.git_cmd = 1;
  
        if (is_rebase_i(opts)) {
 -              if (!edit) {
 +              if (!(flags & EDIT_MSG)) {
                        cmd.stdout_to_stderr = 1;
                        cmd.err = -1;
                }
        }
  
        argv_array_push(&cmd.args, "commit");
 -      argv_array_push(&cmd.args, "-n");
  
 -      if (amend)
 +      if (!(flags & VERIFY_MSG))
 +              argv_array_push(&cmd.args, "-n");
 +      if ((flags & AMEND_MSG))
                argv_array_push(&cmd.args, "--amend");
        if (opts->gpg_sign)
                argv_array_pushf(&cmd.args, "-S%s", opts->gpg_sign);
                argv_array_push(&cmd.args, "-s");
        if (defmsg)
                argv_array_pushl(&cmd.args, "-F", defmsg, NULL);
 -      if (cleanup_commit_message)
 +      if ((flags & CLEANUP_MSG))
                argv_array_push(&cmd.args, "--cleanup=strip");
 -      if (edit)
 +      if ((flags & EDIT_MSG))
                argv_array_push(&cmd.args, "-e");
 -      else if (!cleanup_commit_message &&
 +      else if (!(flags & CLEANUP_MSG) &&
                 !opts->signoff && !opts->record_origin &&
                 git_config_get_value("commit.cleanup", &value))
                argv_array_push(&cmd.args, "--cleanup=verbatim");
  
 -      if (allow_empty)
 +      if ((flags & ALLOW_EMPTY))
                argv_array_push(&cmd.args, "--allow-empty");
  
        if (opts->allow_empty_message)
@@@ -835,13 -828,13 +835,13 @@@ static int update_squash_messages(enum 
                strbuf_splice(&buf, 0, eol - buf.buf, header.buf, header.len);
                strbuf_release(&header);
        } else {
 -              unsigned char head[20];
 +              struct object_id head;
                struct commit *head_commit;
                const char *head_message, *body;
  
 -              if (get_sha1("HEAD", head))
 +              if (get_oid("HEAD", &head))
                        return error(_("need a HEAD to fixup"));
 -              if (!(head_commit = lookup_commit_reference(head)))
 +              if (!(head_commit = lookup_commit_reference(&head)))
                        return error(_("could not read HEAD"));
                if (!(head_message = get_commit_buffer(head_commit, NULL)))
                        return error(_("could not read HEAD's commit message"));
@@@ -933,14 -926,14 +933,14 @@@ static void record_in_rewritten(struct 
  static int do_pick_commit(enum todo_command command, struct commit *commit,
                struct replay_opts *opts, int final_fixup)
  {
 -      int edit = opts->edit, cleanup_commit_message = 0;
 -      const char *msg_file = edit ? NULL : git_path_merge_msg();
 -      unsigned char head[20];
 +      unsigned int flags = opts->edit ? EDIT_MSG : 0;
 +      const char *msg_file = opts->edit ? NULL : git_path_merge_msg();
 +      struct object_id head;
        struct commit *base, *next, *parent;
        const char *base_label, *next_label;
        struct commit_message msg = { NULL, NULL, NULL, NULL };
        struct strbuf msgbuf = STRBUF_INIT;
 -      int res, unborn = 0, amend = 0, allow = 0;
 +      int res, unborn = 0, allow;
  
        if (opts->no_commit) {
                /*
                 * that represents the "current" state for merge-recursive
                 * to work on.
                 */
 -              if (write_cache_as_tree(head, 0, NULL))
 +              if (write_cache_as_tree(head.hash, 0, NULL))
                        return error(_("your index file is unmerged."));
        } else {
 -              unborn = get_sha1("HEAD", head);
 +              unborn = get_oid("HEAD", &head);
                if (unborn)
 -                      hashcpy(head, EMPTY_TREE_SHA1_BIN);
 +                      oidcpy(&head, &empty_tree_oid);
                if (index_differs_from(unborn ? EMPTY_TREE_SHA1_HEX : "HEAD", 0, 0))
                        return error_dirty_index(opts);
        }
                        oid_to_hex(&commit->object.oid));
  
        if (opts->allow_ff && !is_fixup(command) &&
 -          ((parent && !hashcmp(parent->object.oid.hash, head)) ||
 +          ((parent && !oidcmp(&parent->object.oid, &head)) ||
             (!parent && unborn))) {
                if (is_rebase_i(opts))
                        write_author_script(msg.message);
 -              res = fast_forward_to(commit->object.oid.hash, head, unborn,
 +              res = fast_forward_to(&commit->object.oid, &head, unborn,
                        opts);
                if (res || command != TODO_REWORD)
                        goto leave;
 -              edit = amend = 1;
 +              flags |= EDIT_MSG | AMEND_MSG;
 +              if (command == TODO_REWORD)
 +                      flags |= VERIFY_MSG;
                msg_file = NULL;
                goto fast_forward_edit;
        }
                        strbuf_addstr(&msgbuf, p);
  
                if (opts->record_origin) {
 +                      strbuf_complete_line(&msgbuf);
                        if (!has_conforming_footer(&msgbuf, NULL, 0))
                                strbuf_addch(&msgbuf, '\n');
                        strbuf_addstr(&msgbuf, cherry_picked_prefix);
        }
  
        if (command == TODO_REWORD)
 -              edit = 1;
 +              flags |= EDIT_MSG | VERIFY_MSG;
        else if (is_fixup(command)) {
                if (update_squash_messages(command, commit, opts))
                        return -1;
 -              amend = 1;
 +              flags |= AMEND_MSG;
                if (!final_fixup)
                        msg_file = rebase_path_squash_msg();
                else if (file_exists(rebase_path_fixup_msg())) {
 -                      cleanup_commit_message = 1;
 +                      flags |= CLEANUP_MSG;
                        msg_file = rebase_path_fixup_msg();
                } else {
 -                      const char *dest = git_path("SQUASH_MSG");
 +                      const char *dest = git_path_squash_msg();
                        unlink(dest);
                        if (copy_file(dest, rebase_path_squash_msg(), 0666))
                                return error(_("could not rename '%s' to '%s'"),
                                             rebase_path_squash_msg(), dest);
 -                      unlink(git_path("MERGE_MSG"));
 +                      unlink(git_path_merge_msg());
                        msg_file = dest;
 -                      edit = 1;
 +                      flags |= EDIT_MSG;
                }
        }
  
                res = -1;
        else if (!opts->strategy || !strcmp(opts->strategy, "recursive") || command == TODO_REVERT) {
                res = do_recursive_merge(base, next, base_label, next_label,
 -                                       head, &msgbuf, opts);
 +                                       &head, &msgbuf, opts);
                if (res < 0)
                        return res;
                res |= write_message(msgbuf.buf, msgbuf.len,
                commit_list_insert(next, &remotes);
                res |= try_merge_command(opts->strategy,
                                         opts->xopts_nr, (const char **)opts->xopts,
 -                                      common, sha1_to_hex(head), remotes);
 +                                      common, oid_to_hex(&head), remotes);
                free_commit_list(common);
                free_commit_list(remotes);
        }
        if (allow < 0) {
                res = allow;
                goto leave;
 -      }
 +      } else if (allow)
 +              flags |= ALLOW_EMPTY;
        if (!opts->no_commit)
  fast_forward_edit:
 -              res = run_git_commit(msg_file, opts, allow, edit, amend,
 -                                   cleanup_commit_message);
 +              res = run_git_commit(msg_file, opts, flags);
  
        if (!res && final_fixup) {
                unlink(rebase_path_fixup_msg());
@@@ -1202,7 -1192,6 +1202,7 @@@ struct todo_list 
        struct todo_item *items;
        int nr, alloc, current;
        int done_nr, total_nr;
 +      struct stat_data stat;
  };
  
  #define TODO_LIST_INIT { STRBUF_INIT }
@@@ -1223,7 -1212,7 +1223,7 @@@ static struct todo_item *append_new_tod
  
  static int parse_insn_line(struct todo_item *item, const char *bol, char *eol)
  {
 -      unsigned char commit_sha1[20];
 +      struct object_id commit_oid;
        char *end_of_object_name;
        int i, saved, status, padding;
  
        end_of_object_name = (char *) bol + strcspn(bol, " \t\n");
        saved = *end_of_object_name;
        *end_of_object_name = '\0';
 -      status = get_sha1(bol, commit_sha1);
 +      status = get_oid(bol, &commit_oid);
        *end_of_object_name = saved;
  
        item->arg = end_of_object_name + strspn(end_of_object_name, " \t");
        if (status < 0)
                return -1;
  
 -      item->commit = lookup_commit_reference(commit_sha1);
 +      item->commit = lookup_commit_reference(&commit_oid);
        return !item->commit;
  }
  
@@@ -1333,7 -1322,6 +1333,7 @@@ static int count_commands(struct todo_l
  static int read_populate_todo(struct todo_list *todo_list,
                        struct replay_opts *opts)
  {
 +      struct stat st;
        const char *todo_file = get_todo_path(opts);
        int fd, res;
  
        }
        close(fd);
  
 +      res = stat(todo_file, &st);
 +      if (res)
 +              return error(_("could not stat '%s'"), todo_file);
 +      fill_stat_data(&todo_list->stat, &st);
 +
        res = parse_insn_buffer(todo_list->buf.buf, todo_list);
        if (res) {
                if (is_rebase_i(opts))
@@@ -1829,10 -1812,10 +1829,10 @@@ static int error_failed_squash(struct c
                return error(_("could not rename '%s' to '%s'"),
                        rebase_path_squash_msg(), rebase_path_message());
        unlink(rebase_path_fixup_msg());
 -      unlink(git_path("MERGE_MSG"));
 -      if (copy_file(git_path("MERGE_MSG"), rebase_path_message(), 0666))
 +      unlink(git_path_merge_msg());
 +      if (copy_file(git_path_merge_msg(), rebase_path_message(), 0666))
                return error(_("could not copy '%s' to '%s'"),
 -                           rebase_path_message(), git_path("MERGE_MSG"));
 +                           rebase_path_message(), git_path_merge_msg());
        return error_with_patch(commit, subject, subject_len, opts, 1, 0);
  }
  
@@@ -1915,11 -1898,13 +1915,13 @@@ static int apply_autostash(struct repla
        strbuf_trim(&stash_sha1);
  
        child.git_cmd = 1;
+       child.no_stdout = 1;
+       child.no_stderr = 1;
        argv_array_push(&child.args, "stash");
        argv_array_push(&child.args, "apply");
        argv_array_push(&child.args, stash_sha1.buf);
        if (!run_command(&child))
-               printf(_("Applied autostash."));
+               printf(_("Applied autostash.\n"));
        else {
                struct child_process store = CHILD_PROCESS_INIT;
  
@@@ -2037,25 -2022,10 +2039,25 @@@ static int pick_commits(struct todo_lis
                } else if (item->command == TODO_EXEC) {
                        char *end_of_arg = (char *)(item->arg + item->arg_len);
                        int saved = *end_of_arg;
 +                      struct stat st;
  
                        *end_of_arg = '\0';
                        res = do_exec(item->arg);
                        *end_of_arg = saved;
 +
 +                      /* Reread the todo file if it has changed. */
 +                      if (res)
 +                              ; /* fall through */
 +                      else if (stat(get_todo_path(opts), &st))
 +                              res = error_errno(_("could not stat '%s'"),
 +                                                get_todo_path(opts));
 +                      else if (match_stat_data(&todo_list->stat, &st)) {
 +                              todo_list_release(todo_list);
 +                              if (read_populate_todo(todo_list, opts))
 +                                      res = -1; /* message was printed */
 +                              /* `current` will be incremented below */
 +                              todo_list->current = -1;
 +                      }
                } else if (!is_noop(item->command))
                        return error(_("unknown command %d"), item->command);
  
@@@ -2090,6 -2060,7 +2092,7 @@@ cleanup_head_ref
                                res = error(_("could not read orig-head"));
                                goto cleanup_head_ref;
                        }
+                       strbuf_reset(&buf);
                        if (!read_oneliner(&buf, rebase_path_onto(), 0)) {
                                res = error(_("could not read 'onto'"));
                                goto cleanup_head_ref;
@@@ -2186,12 -2157,12 +2189,12 @@@ static int continue_single_pick(void
  
  static int commit_staged_changes(struct replay_opts *opts)
  {
 -      int amend = 0;
 +      unsigned int flags = ALLOW_EMPTY | EDIT_MSG;
  
        if (has_unstaged_changes(1))
                return error(_("cannot rebase: You have unstaged changes."));
        if (!has_uncommitted_changes(0)) {
 -              const char *cherry_pick_head = git_path("CHERRY_PICK_HEAD");
 +              const char *cherry_pick_head = git_path_cherry_pick_head();
  
                if (file_exists(cherry_pick_head) && unlink(cherry_pick_head))
                        return error(_("could not remove CHERRY_PICK_HEAD"));
                                       "--continue' again."));
  
                strbuf_release(&rev);
 -              amend = 1;
 +              flags |= AMEND_MSG;
        }
  
 -      if (run_git_commit(rebase_path_message(), opts, 1, 1, amend, 0))
 +      if (run_git_commit(rebase_path_message(), opts, flags))
                return error(_("could not commit staged changes."));
        unlink(rebase_path_amend());
        return 0;
@@@ -2282,7 -2253,7 +2285,7 @@@ static int single_pick(struct commit *c
  int sequencer_pick_revisions(struct replay_opts *opts)
  {
        struct todo_list todo_list = TODO_LIST_INIT;
 -      unsigned char sha1[20];
 +      struct object_id oid;
        int i, res;
  
        assert(opts->revs);
                return -1;
  
        for (i = 0; i < opts->revs->pending.nr; i++) {
 -              unsigned char sha1[20];
 +              struct object_id oid;
                const char *name = opts->revs->pending.objects[i].name;
  
                /* This happens when using --stdin. */
                if (!strlen(name))
                        continue;
  
 -              if (!get_sha1(name, sha1)) {
 -                      if (!lookup_commit_reference_gently(sha1, 1)) {
 -                              enum object_type type = sha1_object_info(sha1, NULL);
 +              if (!get_oid(name, &oid)) {
 +                      if (!lookup_commit_reference_gently(&oid, 1)) {
 +                              enum object_type type = sha1_object_info(oid.hash, NULL);
                                return error(_("%s: can't cherry-pick a %s"),
                                        name, typename(type));
                        }
        if (walk_revs_populate_todo(&todo_list, opts) ||
                        create_seq_dir() < 0)
                return -1;
 -      if (get_sha1("HEAD", sha1) && (opts->action == REPLAY_REVERT))
 +      if (get_oid("HEAD", &oid) && (opts->action == REPLAY_REVERT))
                return error(_("can't revert as initial commit"));
 -      if (save_head(sha1_to_hex(sha1)))
 +      if (save_head(oid_to_hex(&oid)))
                return -1;
        if (save_opts(opts))
                return -1;
@@@ -2359,9 -2330,6 +2362,9 @@@ void append_signoff(struct strbuf *msgb
                                getenv("GIT_COMMITTER_EMAIL")));
        strbuf_addch(&sob, '\n');
  
 +      if (!ignore_footer)
 +              strbuf_complete_line(msgbuf);
 +
        /*
         * If the whole message buffer is equal to the sob, pretend that we
         * found a conforming footer with a matching sob
                         * the title and body to be filled in by the user.
                         */
                        append_newlines = "\n\n";
 -              } else if (msgbuf->buf[len - 1] != '\n') {
 -                      /*
 -                       * Incomplete line.  Complete the line and add a
 -                       * blank one so that there is an empty line between
 -                       * the message body and the sob.
 -                       */
 -                      append_newlines = "\n\n";
                } else if (len == 1) {
                        /*
                         * Buffer contains a single newline.  Add another