Merge branch 'pw/rebase-i-regression-fix-tests' into maint
authorJunio C Hamano <gitster@pobox.com>
Mon, 10 Jul 2017 20:58:59 +0000 (13:58 -0700)
committerJunio C Hamano <gitster@pobox.com>
Mon, 10 Jul 2017 20:59:00 +0000 (13:59 -0700)
Fix a recent regression to "git rebase -i" and add tests that would
have caught it and others.

* pw/rebase-i-regression-fix-tests:
  t3420: fix under GETTEXT_POISON build
  rebase: add more regression tests for console output
  rebase: add regression tests for console output
  rebase -i: add test for reflog message
  sequencer: print autostash messages to stderr

1  2 
git-rebase.sh
sequencer.c
t/t3404-rebase-interactive.sh

diff --combined git-rebase.sh
@@@ -34,7 -34,6 +34,7 @@@ root!              rebase all reachabl
  autosquash         move commits that begin with squash!/fixup! under -i
  committer-date-is-author-date! passed to 'git am'
  ignore-date!       passed to 'git am'
 +signoff            passed to 'git am'
  whitespace=!       passed to 'git apply'
  ignore-whitespace! passed to 'git apply'
  C=!                passed to 'git apply'
@@@ -166,14 -165,14 +166,14 @@@ apply_autostash () 
                stash_sha1=$(cat "$state_dir/autostash")
                if git stash apply $stash_sha1 2>&1 >/dev/null
                then
-                       echo "$(gettext 'Applied autostash.')"
+                       echo "$(gettext 'Applied autostash.')" >&2
                else
                        git stash store -m "autostash" -q $stash_sha1 ||
                        die "$(eval_gettext "Cannot store \$stash_sha1")"
                        gettext 'Applying autostash resulted in conflicts.
  Your changes are safe in the stash.
  You can run "git stash pop" or "git stash drop" at any time.
- '
+ ' >&2
                fi
        fi
  }
@@@ -322,7 -321,7 +322,7 @@@ d
        --ignore-whitespace)
                git_am_opt="$git_am_opt $1"
                ;;
 -      --committer-date-is-author-date|--ignore-date)
 +      --committer-date-is-author-date|--ignore-date|--signoff|--no-signoff)
                git_am_opt="$git_am_opt $1"
                force_rebase=t
                ;;
diff --combined sequencer.c
@@@ -464,8 -464,7 +464,8 @@@ static int do_recursive_merge(struct co
  
        if (active_cache_changed &&
            write_locked_index(&the_index, &index_lock, COMMIT_LOCK))
 -              /* TRANSLATORS: %s will be "revert", "cherry-pick" or
 +              /*
 +               * TRANSLATORS: %s will be "revert", "cherry-pick" or
                 * "rebase -i".
                 */
                return error(_("%s: Unable to write new index file"),
@@@ -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)
@@@ -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 int flags = opts->edit ? EDIT_MSG : 0;
 +      const char *msg_file = opts->edit ? NULL : git_path_merge_msg();
        unsigned char head[20];
        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) {
                /*
                        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;
                }
        }
  
        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 }
@@@ -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);
  }
  
@@@ -1921,7 -1904,7 +1921,7 @@@ static int apply_autostash(struct repla
        argv_array_push(&child.args, "apply");
        argv_array_push(&child.args, stash_sha1.buf);
        if (!run_command(&child))
-               printf(_("Applied autostash.\n"));
+               fprintf(stderr, _("Applied autostash.\n"));
        else {
                struct child_process store = CHILD_PROCESS_INIT;
  
                if (run_command(&store))
                        ret = error(_("cannot store %s"), stash_sha1.buf);
                else
-                       printf(_("Applying autostash resulted in conflicts.\n"
-                               "Your changes are safe in the stash.\n"
-                               "You can run \"git stash pop\" or"
-                               " \"git stash drop\" at any time.\n"));
+                       fprintf(stderr,
+                               _("Applying autostash resulted in conflicts.\n"
+                                 "Your changes are safe in the stash.\n"
+                                 "You can run \"git stash pop\" or"
+                                 " \"git stash drop\" at any time.\n"));
        }
  
        strbuf_release(&stash_sha1);
@@@ -2039,25 -2023,10 +2040,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);
  
@@@ -2189,12 -2158,12 +2190,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;
@@@ -2362,9 -2331,6 +2363,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
@@@ -169,6 -169,13 +169,13 @@@ test_expect_success 'reflog for the bra
        test $(git rev-parse branch1@{1}) = $(git rev-parse original-branch1)
  '
  
+ test_expect_success 'reflog for the branch shows correct finish message' '
+       printf "rebase -i (finish): refs/heads/branch1 onto %s\n" \
+               "$(git rev-parse branch2)" >expected &&
+       git log -g --pretty=%gs -1 refs/heads/branch1 >actual &&
+       test_cmp expected actual
+ '
  test_expect_success 'exchange two commits' '
        set_fake_editor &&
        FAKE_LINES="2 1" git rebase -i HEAD~2 &&
@@@ -366,7 -373,7 +373,7 @@@ test_expect_success 'verbose flag is he
        grep "^ file1 | 2 +-$" output
  '
  
 -test_expect_success 'multi-squash only fires up editor once' '
 +test_expect_success C_LOCALE_OUTPUT 'multi-squash only fires up editor once' '
        base=$(git rev-parse HEAD~4) &&
        set_fake_editor &&
        FAKE_COMMIT_AMEND="ONCE" FAKE_LINES="1 squash 2 squash 3 squash 4" \
        test 1 = $(git show | grep ONCE | wc -l)
  '
  
 -test_expect_success 'multi-fixup does not fire up editor' '
 +test_expect_success C_LOCALE_OUTPUT 'multi-fixup does not fire up editor' '
        git checkout -b multi-fixup E &&
        base=$(git rev-parse HEAD~4) &&
        set_fake_editor &&
  ONCE
  EOF
  
 -test_expect_success 'squash and fixup generate correct log messages' '
 +test_expect_success C_LOCALE_OUTPUT 'squash and fixup generate correct log messages' '
        git checkout -b squash-fixup E &&
        base=$(git rev-parse HEAD~4) &&
        set_fake_editor &&
        git branch -D squash-fixup
  '
  
 -test_expect_success 'squash ignores comments' '
 +test_expect_success C_LOCALE_OUTPUT 'squash ignores comments' '
        git checkout -b skip-comments E &&
        base=$(git rev-parse HEAD~4) &&
        set_fake_editor &&
        git branch -D skip-comments
  '
  
 -test_expect_success 'squash ignores blank lines' '
 +test_expect_success C_LOCALE_OUTPUT 'squash ignores blank lines' '
        git checkout -b skip-blank-lines E &&
        base=$(git rev-parse HEAD~4) &&
        set_fake_editor &&
@@@ -860,7 -867,7 +867,7 @@@ test_expect_success 'rebase -ix with se
        test_cmp expected actual
  '
  
 -test_expect_success 'rebase -ix with --autosquash' '
 +test_expect_success C_LOCALE_OUTPUT 'rebase -ix with --autosquash' '
        git reset --hard execute &&
        git checkout -b autosquash &&
        echo second >second.txt &&
@@@ -943,7 -950,7 +950,7 @@@ test_expect_success 'rebase -i --root f
        test 0 = $(git cat-file commit HEAD | grep -c ^parent\ )
  '
  
 -test_expect_success 'rebase --edit-todo does not works on non-interactive rebase' '
 +test_expect_success C_LOCALE_OUTPUT 'rebase --edit-todo does not work on non-interactive rebase' '
        git reset --hard &&
        git checkout conflict-branch &&
        set_fake_editor &&