Merge branch 'js/rebase-merges-exec-fix'
authorJunio C Hamano <gitster@pobox.com>
Mon, 20 Aug 2018 18:33:48 +0000 (11:33 -0700)
committerJunio C Hamano <gitster@pobox.com>
Mon, 20 Aug 2018 18:33:48 +0000 (11:33 -0700)
The "--exec" option to "git rebase --rebase-merges" placed the exec
commands at wrong places, which has been corrected.

* js/rebase-merges-exec-fix:
rebase --exec: make it work with --rebase-merges
t3430: demonstrate what -r, --autosquash & --exec should do

1  2 
sequencer.c
diff --combined sequencer.c
index f74dafb3259771571a67e6cbeaf22c4129a020d9,278d34ce9d6006bee42dfb115dd2b2fbf13b2897..b8f274bdec7aca3b93b13f985b6083f95ea5cfac
@@@ -307,7 -307,7 +307,7 @@@ static const char *action_name(const st
        case REPLAY_INTERACTIVE_REBASE:
                return N_("rebase -i");
        }
 -      die(_("Unknown action: %d"), opts->action);
 +      die(_("unknown action: %d"), opts->action);
  }
  
  struct commit_message {
@@@ -654,7 -654,6 +654,7 @@@ missing_author
                        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;
@@@ -709,51 -708,43 +709,51 @@@ static const char *read_author_ident(st
        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'",
 +                      warning(_("could not parse '%s' (looking for '%s'"),
                                rebase_path_author_script(), keys[i]);
                        return NULL;
                }
  
                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;
        }
  
        if (i < 3) {
 -              warning("could not parse '%s' (looking for '%s')",
 +              warning(_("could not parse '%s' (looking for '%s')"),
                        rebase_path_author_script(), keys[i]);
                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;
  }
  
@@@ -1454,7 -1445,7 +1454,7 @@@ static const char *command_to_string(co
  {
        if (command < TODO_COMMENT)
                return todo_command_info[command].str;
 -      die("Unknown command: %d", command);
 +      die(_("unknown command: %d"), command);
  }
  
  static char command_to_char(const enum todo_command command)
@@@ -2617,17 -2608,15 +2617,17 @@@ static int error_with_patch(struct comm
                if (intend_to_amend())
                        return -1;
  
 -              fprintf(stderr, "You can amend the commit now, with\n"
 -                      "\n"
 -                      "  git commit --amend %s\n"
 -                      "\n"
 -                      "Once you are satisfied with your changes, run\n"
 -                      "\n"
 -                      "  git rebase --continue\n", gpg_sign_opt_quoted(opts));
 +              fprintf(stderr,
 +                      _("You can amend the commit now, with\n"
 +                        "\n"
 +                        "  git commit --amend %s\n"
 +                        "\n"
 +                        "Once you are satisfied with your changes, run\n"
 +                        "\n"
 +                        "  git rebase --continue\n"),
 +                      gpg_sign_opt_quoted(opts));
        } else if (exit_code)
 -              fprintf(stderr, "Could not apply %s... %.*s\n",
 +              fprintf_ln(stderr, _("Could not apply %s... %.*s"),
                        short_commit_name(commit), subject_len, subject);
  
        return exit_code;
@@@ -2741,7 -2730,7 +2741,7 @@@ static int do_label(const char *name, i
        struct object_id head_oid;
  
        if (len == 1 && *name == '#')
 -              return error("Illegal label name: '%.*s'", len, name);
 +              return error(_("illegal label name: '%.*s'"), len, name);
  
        strbuf_addf(&ref_name, "refs/rewritten/%.*s", len, name);
        strbuf_addf(&msg, "rebase -i (label) '%.*s'", len, name);
@@@ -4255,10 -4244,9 +4255,9 @@@ int sequencer_add_exec_commands(const c
  {
        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);
                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);