{"thread":{"id":"50780","subject":"[RFC PATCH 00/11] rebase -i run without forking rebase--interactive","startedAt":"2019-03-19T19:03:59Z","lastAt":"2019-04-25T17:47:15Z","messageCount":40,"participants":["Phillip Wood","Ævar Arnfjörð Bjarmason","Duy Nguyen","Josh Steadmon","Junio C Hamano","Alban Gruin"],"isPatch":true,"patchVersion":1,"patchTotal":11},"messages":[{"id":"371917","messageId":"20190319190317.6632-1-phillip.wood123@gmail.com","threadId":"50780","inReplyTo":null,"subject":"[RFC PATCH 00/11] rebase -i run without forking rebase--interactive","fromName":"Phillip Wood","fromEmail":"phillip.wood123@gmail.com","sentAt":"2019-03-19T19:03:06Z","receivedAt":"2019-03-19T19:03:59Z","isPatch":true,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"From: Phillip Wood <phillip.wood@dunelm.org.uk>\n\nWhen the builtin rebase starts an interactive rebase it parses the\noptions and then repackages them and forks `rebase--interactive`. This\nseries refactors rebase--interactive so that interactive rebases can\nbe started by the builtin rebase without forking. My motivation was to\nmake it easier to debug the sequencer but this should help future\nmaintainability.\n\nThis series involves some code movement so viewing the diffs with\n--color-moved is recommended.\n\nThese patches are based on a merge of master [e902e9bcae (\"The second\nbatch\", 2019-03-11)] and ag/sequencer-reduce-rewriting-todo ed35d18841\n(\"rebase--interactive: move transform_todo_file()\", 2019-03-05). They\ncan be fetched from the tag rebase-i-no-fork/rfc at\nhttps://github.com/phillipwood/git.git\n\nPhillip Wood (11):\n  sequencer: always discard index after checkout\n  rebase: rename write_basic_state()\n  rebase: use OPT_RERERE_AUTOUPDATE()\n  rebase -i: combine rebase--interactive.c with rebase.c\n  rebase -i: remove duplication\n  rebase -i: use struct commit when parsing options\n  rebase -i: use struct object_id for squash_onto\n  rebase -i: use struct rebase_options to parse args\n  rebase -i: use struct rebase_options in do_interactive_rebase()\n  rebase: use a common action enum\n  rebase -i: run without forking rebase--interactive\n\n Makefile                      |   1 -\n builtin/rebase--interactive.c | 377 --------------------\n builtin/rebase.c              | 625 ++++++++++++++++++++++++++--------\n parse-options-cb.c            |  34 ++\n parse-options.h               |   4 +\n sequencer.c                   |  42 ++-\n sequencer.h                   |   7 +-\n 7 files changed, 556 insertions(+), 534 deletions(-)\n delete mode 100644 builtin/rebase--interactive.c\n\n-- \n2.21.0\n\n"},{"id":"371918","messageId":"20190319190317.6632-3-phillip.wood123@gmail.com","threadId":"50780","inReplyTo":"20190319190317.6632-1-phillip.wood123@gmail.com","subject":"[RFC PATCH 02/11] rebase: rename write_basic_state()","fromName":"Phillip Wood","fromEmail":"phillip.wood123@gmail.com","sentAt":"2019-03-19T19:03:08Z","receivedAt":"2019-03-19T19:04:00Z","isPatch":true,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"From: Phillip Wood <phillip.wood@dunelm.org.uk>\n\nThis clashes with a function in sequencer.c\n\nSigned-off-by: Phillip Wood <phillip.wood@dunelm.org.uk>\n---\n builtin/rebase.c | 4 ++--\n 1 file changed, 2 insertions(+), 2 deletions(-)\n\ndiff --git a/builtin/rebase.c b/builtin/rebase.c\nindex 52114cbf0d..b634879c5b 100644\n--- a/builtin/rebase.c\n+++ b/builtin/rebase.c\n@@ -245,7 +245,7 @@ static int read_basic_state(struct rebase_options *opts)\n \treturn 0;\n }\n \n-static int write_basic_state(struct rebase_options *opts)\n+static int rebase_write_basic_state(struct rebase_options *opts)\n {\n \twrite_file(state_dir_path(\"head-name\", opts), \"%s\",\n \t\t   opts->head_name ? opts->head_name : \"detached HEAD\");\n@@ -640,7 +640,7 @@ static int run_am(struct rebase_options *opts)\n \t}\n \n \tif (is_directory(opts->state_dir))\n-\t\twrite_basic_state(opts);\n+\t\trebase_write_basic_state(opts);\n \n \treturn status;\n }\n-- \n2.21.0\n\n"},{"id":"371919","messageId":"20190319190317.6632-2-phillip.wood123@gmail.com","threadId":"50780","inReplyTo":"20190319190317.6632-1-phillip.wood123@gmail.com","subject":"[RFC PATCH 01/11] sequencer: always discard index after checkout","fromName":"Phillip Wood","fromEmail":"phillip.wood123@gmail.com","sentAt":"2019-03-19T19:03:07Z","receivedAt":"2019-03-19T19:04:02Z","isPatch":true,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"From: Phillip Wood <phillip.wood@dunelm.org.uk>\n\nAs the checkout runs in a separate process our index will be out of date\nso it should be discarded. The existing callers are not doing this\nconsistently so do it here to avoid the callers having to worry about\nit.\n\nThis fixes some test failures that happen if do_interactive_rebase() is\ncalled without forking rebase--interactive which we will implement\nshortly. Running\n\n  git rebase -i master topic\n\nstarting on master created empty todo lists because all the commits in\ntopic were marked as cherry-picks. After topic was checked out in\nprepare_branch_to_be_rebased() the working tree contained the contents\nfrom topic but the index contained master and the cache entries were\nstill valid. This meant that diff_populate_filespec() which loads the\nblobs when calculating patch-id's ended up reading the contents for\nmaster from the working tree which actually contained topic.\n\nSigned-off-by: Phillip Wood <phillip.wood@dunelm.org.uk>\n---\n\nNotes:\n    It would perhaps be better to pass around the_index rather than\n    the_repository\n\n builtin/rebase--interactive.c |  2 +-\n sequencer.c                   | 27 +++++++++++++++++----------\n sequencer.h                   |  3 ++-\n 3 files changed, 20 insertions(+), 12 deletions(-)\n\ndiff --git a/builtin/rebase--interactive.c b/builtin/rebase--interactive.c\nindex 4535523bf5..d1a4ac1b84 100644\n--- a/builtin/rebase--interactive.c\n+++ b/builtin/rebase--interactive.c\n@@ -171,7 +171,7 @@ static int do_interactive_rebase(struct replay_opts *opts, unsigned flags,\n \tstruct argv_array make_script_args = ARGV_ARRAY_INIT;\n \tstruct todo_list todo_list = TODO_LIST_INIT;\n \n-\tif (prepare_branch_to_be_rebased(opts, switch_to))\n+\tif (prepare_branch_to_be_rebased(the_repository, opts, switch_to))\n \t\treturn -1;\n \n \tif (get_revision_ranges(upstream, onto, &head_hash,\ndiff --git a/sequencer.c b/sequencer.c\nindex 281a8ade19..ccc0160800 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -3418,10 +3418,11 @@ static const char *reflog_message(struct replay_opts *opts,\n \treturn buf.buf;\n }\n \n-static int run_git_checkout(struct replay_opts *opts, const char *commit,\n-\t\t\t    const char *action)\n+static int run_git_checkout(struct repository *r, struct replay_opts *opts,\n+\t\t\t    const char *commit, const char *action)\n {\n \tstruct child_process cmd = CHILD_PROCESS_INIT;\n+\tint ret;\n \n \tcmd.git_cmd = 1;\n \n@@ -3430,25 +3431,31 @@ static int run_git_checkout(struct replay_opts *opts, const char *commit,\n \targv_array_pushf(&cmd.env_array, GIT_REFLOG_ACTION \"=%s\", action);\n \n \tif (opts->verbose)\n-\t\treturn run_command(&cmd);\n+\t\tret = run_command(&cmd);\n \telse\n-\t\treturn run_command_silent_on_success(&cmd);\n+\t\tret = run_command_silent_on_success(&cmd);\n+\n+\tif (!ret)\n+\t\tdiscard_index(r->index);\n+\n+\treturn ret;\n }\n \n-int prepare_branch_to_be_rebased(struct replay_opts *opts, const char *commit)\n+int prepare_branch_to_be_rebased(struct repository *r, struct replay_opts *opts,\n+\t\t\t\t const char *commit)\n {\n \tconst char *action;\n \n \tif (commit && *commit) {\n \t\taction = reflog_message(opts, \"start\", \"checkout %s\", commit);\n-\t\tif (run_git_checkout(opts, commit, action))\n+\t\tif (run_git_checkout(r, opts, commit, action))\n \t\t\treturn error(_(\"could not checkout %s\"), commit);\n \t}\n \n \treturn 0;\n }\n \n-static int checkout_onto(struct replay_opts *opts,\n+static int checkout_onto(struct repository *r, struct replay_opts *opts,\n \t\t\t const char *onto_name, const char *onto,\n \t\t\t const char *orig_head)\n {\n@@ -3458,7 +3465,7 @@ static int checkout_onto(struct replay_opts *opts,\n \tif (get_oid(orig_head, &oid))\n \t\treturn error(_(\"%s: not a valid OID\"), orig_head);\n \n-\tif (run_git_checkout(opts, onto, action)) {\n+\tif (run_git_checkout(r, opts, onto, action)) {\n \t\tapply_autostash(opts);\n \t\tsequencer_remove_state(opts);\n \t\treturn error(_(\"could not detach HEAD\"));\n@@ -4786,7 +4793,7 @@ int complete_action(struct repository *r, struct replay_opts *opts, unsigned fla\n \tif (todo_list_parse_insn_buffer(r, new_todo.buf.buf, &new_todo) ||\n \t    todo_list_check(todo_list, &new_todo)) {\n \t\tfprintf(stderr, _(edit_todo_list_advice));\n-\t\tcheckout_onto(opts, onto_name, onto, orig_head);\n+\t\tcheckout_onto(r, opts, onto_name, onto, orig_head);\n \t\ttodo_list_release(&new_todo);\n \n \t\treturn -1;\n@@ -4805,7 +4812,7 @@ int complete_action(struct repository *r, struct replay_opts *opts, unsigned fla\n \n \ttodo_list_release(&new_todo);\n \n-\tif (checkout_onto(opts, onto_name, oid_to_hex(&oid), orig_head))\n+\tif (checkout_onto(r, opts, onto_name, oid_to_hex(&oid), orig_head))\n \t\treturn -1;\n \n \tif (require_clean_work_tree(r, \"rebase\", \"\", 1, 1))\ndiff --git a/sequencer.h b/sequencer.h\nindex a515ee4457..6c55aa4200 100644\n--- a/sequencer.h\n+++ b/sequencer.h\n@@ -175,7 +175,8 @@ void commit_post_rewrite(struct repository *r,\n \t\t\t const struct commit *current_head,\n \t\t\t const struct object_id *new_head);\n \n-int prepare_branch_to_be_rebased(struct replay_opts *opts, const char *commit);\n+int prepare_branch_to_be_rebased(struct repository *r, struct replay_opts *opts,\n+\t\t\t\t const char *commit);\n \n #define SUMMARY_INITIAL_COMMIT   (1 << 0)\n #define SUMMARY_SHOW_AUTHOR_DATE (1 << 1)\n-- \n2.21.0\n\n"},{"id":"371920","messageId":"20190319190317.6632-4-phillip.wood123@gmail.com","threadId":"50780","inReplyTo":"20190319190317.6632-1-phillip.wood123@gmail.com","subject":"[RFC PATCH 03/11] rebase: use OPT_RERERE_AUTOUPDATE()","fromName":"Phillip Wood","fromEmail":"phillip.wood123@gmail.com","sentAt":"2019-03-19T19:03:09Z","receivedAt":"2019-03-19T19:04:03Z","isPatch":true,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"From: Phillip Wood <phillip.wood@dunelm.org.uk>\n\nAs we have a macro for this it makes sense to use it. Having\ncmd_rebase() and cmd_rebase__interactive() use the same values for\nthis option will be helpful when we start running interactive rebases\nwithout forking rebase--interactive.\n\nSigned-off-by: Phillip Wood <phillip.wood@dunelm.org.uk>\n---\n builtin/rebase.c | 30 +++++++++++++-----------------\n 1 file changed, 13 insertions(+), 17 deletions(-)\n\ndiff --git a/builtin/rebase.c b/builtin/rebase.c\nindex b634879c5b..ccf178326c 100644\n--- a/builtin/rebase.c\n+++ b/builtin/rebase.c\n@@ -206,14 +206,13 @@ static int read_basic_state(struct rebase_options *opts)\n \t\t\t    &buf))\n \t\t\treturn -1;\n \t\tif (!strcmp(buf.buf, \"--rerere-autoupdate\"))\n-\t\t\topts->allow_rerere_autoupdate = 1;\n+\t\t\topts->allow_rerere_autoupdate = RERERE_AUTOUPDATE;\n \t\telse if (!strcmp(buf.buf, \"--no-rerere-autoupdate\"))\n-\t\t\topts->allow_rerere_autoupdate = 0;\n+\t\t\topts->allow_rerere_autoupdate = RERERE_NOAUTOUPDATE;\n \t\telse\n \t\t\twarning(_(\"ignoring invalid allow_rerere_autoupdate: \"\n \t\t\t\t  \"'%s'\"), buf.buf);\n-\t} else\n-\t\topts->allow_rerere_autoupdate = -1;\n+\t}\n \n \tif (file_exists(state_dir_path(\"gpg_sign_opt\", opts))) {\n \t\tstrbuf_reset(&buf);\n@@ -263,10 +262,11 @@ static int rebase_write_basic_state(struct rebase_options *opts)\n \tif (opts->strategy_opts)\n \t\twrite_file(state_dir_path(\"strategy_opts\", opts), \"%s\",\n \t\t\t   opts->strategy_opts);\n-\tif (opts->allow_rerere_autoupdate >= 0)\n+\tif (opts->allow_rerere_autoupdate > 0)\n \t\twrite_file(state_dir_path(\"allow_rerere_autoupdate\", opts),\n \t\t\t   \"-%s-rerere-autoupdate\",\n-\t\t\t   opts->allow_rerere_autoupdate ? \"\" : \"-no\");\n+\t\t\t   opts->allow_rerere_autoupdate == RERERE_AUTOUPDATE ?\n+\t\t\t\t\"\" : \"-no\");\n \tif (opts->gpg_sign_opt)\n \t\twrite_file(state_dir_path(\"gpg_sign_opt\", opts), \"%s\",\n \t\t\t   opts->gpg_sign_opt);\n@@ -625,9 +625,9 @@ static int run_am(struct rebase_options *opts)\n \targv_array_push(&am.args, \"--rebasing\");\n \targv_array_pushf(&am.args, \"--resolvemsg=%s\", resolvemsg);\n \targv_array_push(&am.args, \"--patch-format=mboxrd\");\n-\tif (opts->allow_rerere_autoupdate > 0)\n+\tif (opts->allow_rerere_autoupdate == RERERE_AUTOUPDATE)\n \t\targv_array_push(&am.args, \"--rerere-autoupdate\");\n-\telse if (opts->allow_rerere_autoupdate == 0)\n+\telse if (opts->allow_rerere_autoupdate == RERERE_NOAUTOUPDATE)\n \t\targv_array_push(&am.args, \"--no-rerere-autoupdate\");\n \tif (opts->gpg_sign_opt)\n \t\targv_array_push(&am.args, opts->gpg_sign_opt);\n@@ -713,9 +713,9 @@ static int run_specific_rebase(struct rebase_options *opts)\n \t\t\targv_array_pushf(&child.args, \"--cmd=%s\", opts->cmd);\n \t\tif (opts->allow_empty_message)\n \t\t\targv_array_push(&child.args, \"--allow-empty-message\");\n-\t\tif (opts->allow_rerere_autoupdate > 0)\n+\t\tif (opts->allow_rerere_autoupdate == RERERE_AUTOUPDATE)\n \t\t\targv_array_push(&child.args, \"--rerere-autoupdate\");\n-\t\telse if (opts->allow_rerere_autoupdate == 0)\n+\t\telse if (opts->allow_rerere_autoupdate == RERERE_NOAUTOUPDATE)\n \t\t\targv_array_push(&child.args, \"--no-rerere-autoupdate\");\n \t\tif (opts->gpg_sign_opt)\n \t\t\targv_array_push(&child.args, opts->gpg_sign_opt);\n@@ -764,9 +764,9 @@ static int run_specific_rebase(struct rebase_options *opts)\n \tadd_var(&script_snippet, \"action\", opts->action ? opts->action : \"\");\n \tadd_var(&script_snippet, \"signoff\", opts->signoff ? \"--signoff\" : \"\");\n \tadd_var(&script_snippet, \"allow_rerere_autoupdate\",\n-\t\topts->allow_rerere_autoupdate < 0 ? \"\" :\n \t\topts->allow_rerere_autoupdate ?\n-\t\t\"--rerere-autoupdate\" : \"--no-rerere-autoupdate\");\n+\t\t\topts->allow_rerere_autoupdate == RERERE_AUTOUPDATE ?\n+\t\t\t\"--rerere-autoupdate\" : \"--no-rerere-autoupdate\" : \"\");\n \tadd_var(&script_snippet, \"keep_empty\", opts->keep_empty ? \"yes\" : \"\");\n \tadd_var(&script_snippet, \"autosquash\", opts->autosquash ? \"t\" : \"\");\n \tadd_var(&script_snippet, \"gpg_sign_opt\", opts->gpg_sign_opt);\n@@ -1007,7 +1007,6 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \t\t.type = REBASE_UNSPECIFIED,\n \t\t.flags = REBASE_NO_QUIET,\n \t\t.git_am_opts = ARGV_ARRAY_INIT,\n-\t\t.allow_rerere_autoupdate  = -1,\n \t\t.allow_empty_message = 1,\n \t\t.git_format_patch_opt = STRBUF_INIT,\n \t};\n@@ -1102,10 +1101,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \t\tOPT_SET_INT('p', \"preserve-merges\", &options.type,\n \t\t\t    N_(\"try to recreate merges instead of ignoring \"\n \t\t\t       \"them\"), REBASE_PRESERVE_MERGES),\n-\t\tOPT_BOOL(0, \"rerere-autoupdate\",\n-\t\t\t &options.allow_rerere_autoupdate,\n-\t\t\t N_(\"allow rerere to update index with resolved \"\n-\t\t\t    \"conflict\")),\n+\t\tOPT_RERERE_AUTOUPDATE(&options.allow_rerere_autoupdate),\n \t\tOPT_BOOL('k', \"keep-empty\", &options.keep_empty,\n \t\t\t N_(\"preserve empty commits during rebase\")),\n \t\tOPT_BOOL(0, \"autosquash\", &options.autosquash,\n-- \n2.21.0\n\n"},{"id":"371921","messageId":"20190319190317.6632-6-phillip.wood123@gmail.com","threadId":"50780","inReplyTo":"20190319190317.6632-1-phillip.wood123@gmail.com","subject":"[RFC PATCH 05/11] rebase -i: remove duplication","fromName":"Phillip Wood","fromEmail":"phillip.wood123@gmail.com","sentAt":"2019-03-19T19:03:11Z","receivedAt":"2019-03-19T19:04:05Z","isPatch":true,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"From: Phillip Wood <phillip.wood@dunelm.org.uk>\n\npath_state_dir() and merge_dir() refer to the same path so remove one of\nthem.\n\nSigned-off-by: Phillip Wood <phillip.wood@dunelm.org.uk>\n---\n builtin/rebase.c | 5 ++---\n 1 file changed, 2 insertions(+), 3 deletions(-)\n\ndiff --git a/builtin/rebase.c b/builtin/rebase.c\nindex 80252d72df..e55bd0348a 100644\n--- a/builtin/rebase.c\n+++ b/builtin/rebase.c\n@@ -37,7 +37,6 @@ static char const * const builtin_rebase_usage[] = {\n \tNULL\n };\n \n-static GIT_PATH_FUNC(path_state_dir, \"rebase-merge/\")\n static GIT_PATH_FUNC(path_squash_onto, \"rebase-merge/squash-onto\")\n static GIT_PATH_FUNC(path_interactive, \"rebase-merge/interactive\")\n static GIT_PATH_FUNC(apply_dir, \"rebase-apply\")\n@@ -182,8 +181,8 @@ static int init_basic_state(struct replay_opts *opts, const char *head_name,\n {\n \tFILE *interactive;\n \n-\tif (!is_directory(path_state_dir()) && mkdir_in_gitdir(path_state_dir()))\n-\t\treturn error_errno(_(\"could not create temporary %s\"), path_state_dir());\n+\tif (!is_directory(merge_dir()) && mkdir_in_gitdir(merge_dir()))\n+\t\treturn error_errno(_(\"could not create temporary %s\"), merge_dir());\n \n \tdelete_reflog(\"REBASE_HEAD\");\n \n-- \n2.21.0\n\n"},{"id":"371922","messageId":"20190319190317.6632-7-phillip.wood123@gmail.com","threadId":"50780","inReplyTo":"20190319190317.6632-1-phillip.wood123@gmail.com","subject":"[RFC PATCH 06/11] rebase -i: use struct commit when parsing options","fromName":"Phillip Wood","fromEmail":"phillip.wood123@gmail.com","sentAt":"2019-03-19T19:03:12Z","receivedAt":"2019-03-19T19:04:06Z","isPatch":true,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"From: Phillip Wood <phillip.wood@dunelm.org.uk>\n\nThis is in preparation for using `struct rebase_options` when parsing\noptions in cmd_rebase__interactive(). Using a string for onto,\nrestrict_revision and upstream, was a hangover from the scripted version\nof rebase. The functions that use these variables are updated to take a\n`struct commit`.\n\nSigned-off-by: Phillip Wood <phillip.wood@dunelm.org.uk>\n---\n\nNotes:\n    I'm not sure if parse_opt_commit() should be in parse-options-cb.c or\n    not, it depends if it is going to be useful elsewhere.\n\n builtin/rebase.c   | 42 ++++++++++++++++++++++++------------------\n parse-options-cb.c | 17 +++++++++++++++++\n parse-options.h    |  1 +\n sequencer.c        | 21 +++++++++++----------\n sequencer.h        |  4 ++--\n 5 files changed, 55 insertions(+), 30 deletions(-)\n\ndiff --git a/builtin/rebase.c b/builtin/rebase.c\nindex e55bd0348a..0584b331bf 100644\n--- a/builtin/rebase.c\n+++ b/builtin/rebase.c\n@@ -147,27 +147,28 @@ static int edit_todo_file(unsigned flags)\n \treturn res;\n }\n \n-static int get_revision_ranges(const char *upstream, const char *onto,\n+static int get_revision_ranges(struct commit *upstream, struct commit *onto,\n \t\t\t       const char **head_hash,\n \t\t\t       char **revisions, char **shortrevisions)\n {\n-\tconst char *base_rev = upstream ? upstream : onto, *shorthead;\n+\tstruct commit *base_rev = upstream ? upstream : onto;\n+\tconst char *shorthead;\n \tstruct object_id orig_head;\n \n \tif (get_oid(\"HEAD\", &orig_head))\n \t\treturn error(_(\"no HEAD?\"));\n \n \t*head_hash = find_unique_abbrev(&orig_head, GIT_MAX_HEXSZ);\n-\t*revisions = xstrfmt(\"%s...%s\", base_rev, *head_hash);\n+\t*revisions = xstrfmt(\"%s...%s\", oid_to_hex(&base_rev->object.oid),\n+\t\t\t\t\t\t   *head_hash);\n \n \tshorthead = find_unique_abbrev(&orig_head, DEFAULT_ABBREV);\n \n \tif (upstream) {\n \t\tconst char *shortrev;\n-\t\tstruct object_id rev_oid;\n \n-\t\tget_oid(base_rev, &rev_oid);\n-\t\tshortrev = find_unique_abbrev(&rev_oid, DEFAULT_ABBREV);\n+\t\tshortrev = find_unique_abbrev(&base_rev->object.oid,\n+\t\t\t\t\t      DEFAULT_ABBREV);\n \n \t\t*shortrevisions = xstrfmt(\"%s..%s\", shortrev, shorthead);\n \t} else\n@@ -177,7 +178,7 @@ static int get_revision_ranges(const char *upstream, const char *onto,\n }\n \n static int init_basic_state(struct replay_opts *opts, const char *head_name,\n-\t\t\t    const char *onto, const char *orig_head)\n+\t\t\t    struct commit *onto, const char *orig_head)\n {\n \tFILE *interactive;\n \n@@ -195,10 +196,10 @@ static int init_basic_state(struct replay_opts *opts, const char *head_name,\n }\n \n static int do_interactive_rebase(struct replay_opts *opts, unsigned flags,\n-\t\t\t\t const char *switch_to, const char *upstream,\n-\t\t\t\t const char *onto, const char *onto_name,\n+\t\t\t\t const char *switch_to, struct commit *upstream,\n+\t\t\t\t struct commit *onto, const char *onto_name,\n \t\t\t\t const char *squash_onto, const char *head_name,\n-\t\t\t\t const char *restrict_revision, char *raw_strategies,\n+\t\t\t\t struct commit *restrict_revision, char *raw_strategies,\n \t\t\t\t struct string_list *commands, unsigned autosquash)\n {\n \tint ret;\n@@ -229,7 +230,8 @@ static int do_interactive_rebase(struct replay_opts *opts, unsigned flags,\n \n \targv_array_pushl(&make_script_args, \"\", revisions, NULL);\n \tif (restrict_revision)\n-\t\targv_array_push(&make_script_args, restrict_revision);\n+\t\targv_array_push(&make_script_args,\n+\t\t\t\toid_to_hex(&restrict_revision->object.oid));\n \n \tret = sequencer_make_script(the_repository, &todo_list.buf,\n \t\t\t\t    make_script_args.argc, make_script_args.argv,\n@@ -265,9 +267,10 @@ int cmd_rebase__interactive(int argc, const char **argv, const char *prefix)\n \tstruct replay_opts opts = REPLAY_OPTS_INIT;\n \tunsigned flags = 0, keep_empty = 0, rebase_merges = 0, autosquash = 0;\n \tint abbreviate_commands = 0, rebase_cousins = -1, ret = 0;\n-\tconst char *onto = NULL, *onto_name = NULL, *restrict_revision = NULL,\n-\t\t*squash_onto = NULL, *upstream = NULL, *head_name = NULL,\n+\tconst char *onto_name = NULL,\n+\t\t*squash_onto = NULL, *head_name = NULL,\n \t\t*switch_to = NULL, *cmd = NULL;\n+\tstruct commit *onto = NULL, *upstream = NULL, *restrict_revision = NULL;\n \tstruct string_list commands = STRING_LIST_INIT_DUP;\n \tchar *raw_strategies = NULL;\n \tenum {\n@@ -303,13 +306,16 @@ int cmd_rebase__interactive(int argc, const char **argv, const char *prefix)\n \t\t\tN_(\"rearrange fixup/squash lines\"), REARRANGE_SQUASH),\n \t\tOPT_CMDMODE(0, \"add-exec-commands\", &command,\n \t\t\tN_(\"insert exec commands in todo list\"), ADD_EXEC),\n-\t\tOPT_STRING(0, \"onto\", &onto, N_(\"onto\"), N_(\"onto\")),\n-\t\tOPT_STRING(0, \"restrict-revision\", &restrict_revision,\n-\t\t\t   N_(\"restrict-revision\"), N_(\"restrict revision\")),\n+\t\t{ OPTION_CALLBACK, 0, \"onto\", &onto, N_(\"onto\"), N_(\"onto\"),\n+\t\t  PARSE_OPT_NONEG, parse_opt_commit, 0 },\n+\t\t{ OPTION_CALLBACK, 0, \"restrict-revision\", &restrict_revision,\n+\t\t  N_(\"restrict-revision\"), N_(\"restrict revision\"),\n+\t\t  PARSE_OPT_NONEG, parse_opt_commit, 0 },\n \t\tOPT_STRING(0, \"squash-onto\", &squash_onto, N_(\"squash-onto\"),\n \t\t\t   N_(\"squash onto\")),\n-\t\tOPT_STRING(0, \"upstream\", &upstream, N_(\"upstream\"),\n-\t\t\t   N_(\"the upstream commit\")),\n+\t\t{ OPTION_CALLBACK, 0, \"upstream\", &upstream, N_(\"upstream\"),\n+\t\t  N_(\"the upstream commit\"), PARSE_OPT_NONEG, parse_opt_commit,\n+\t\t  0 },\n \t\tOPT_STRING(0, \"head-name\", &head_name, N_(\"head-name\"), N_(\"head name\")),\n \t\t{ OPTION_STRING, 'S', \"gpg-sign\", &opts.gpg_sign, N_(\"key-id\"),\n \t\t\tN_(\"GPG-sign commits\"),\ndiff --git a/parse-options-cb.c b/parse-options-cb.c\nindex 2733393546..2206eb763c 100644\n--- a/parse-options-cb.c\n+++ b/parse-options-cb.c\n@@ -96,6 +96,23 @@ int parse_opt_commits(const struct option *opt, const char *arg, int unset)\n \treturn 0;\n }\n \n+int parse_opt_commit(const struct option *opt, const char *arg, int unset)\n+{\n+\tstruct object_id oid;\n+\tstruct commit *commit;\n+\tstruct commit **target = opt->value;\n+\n+\tif (!arg)\n+\t\treturn -1;\n+\tif (get_oid(arg, &oid))\n+\t\treturn error(\"malformed object name %s\", arg);\n+\tcommit = lookup_commit_reference(the_repository, &oid);\n+\tif (!commit)\n+\t\treturn error(\"no such commit %s\", arg);\n+\t*target = commit;\n+\treturn 0;\n+}\n+\n int parse_opt_object_name(const struct option *opt, const char *arg, int unset)\n {\n \tstruct object_id oid;\ndiff --git a/parse-options.h b/parse-options.h\nindex 7d83e2971d..5a75646618 100644\n--- a/parse-options.h\n+++ b/parse-options.h\n@@ -266,6 +266,7 @@ int parse_opt_color_flag_cb(const struct option *, const char *, int);\n int parse_opt_verbosity_cb(const struct option *, const char *, int);\n int parse_opt_object_name(const struct option *, const char *, int);\n int parse_opt_commits(const struct option *, const char *, int);\n+int parse_opt_commit(const struct option *, const char *, int);\n int parse_opt_tertiary(const struct option *, const char *, int);\n int parse_opt_string_list(const struct option *, const char *, int);\n int parse_opt_noop_cb(const struct option *, const char *, int);\ndiff --git a/sequencer.c b/sequencer.c\nindex ccc0160800..610b7ece14 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -2418,14 +2418,15 @@ static void write_strategy_opts(struct replay_opts *opts)\n }\n \n int write_basic_state(struct replay_opts *opts, const char *head_name,\n-\t\t      const char *onto, const char *orig_head)\n+\t\t      struct commit *onto, const char *orig_head)\n {\n \tconst char *quiet = getenv(\"GIT_QUIET\");\n \n \tif (head_name)\n \t\twrite_file(rebase_path_head_name(), \"%s\\n\", head_name);\n \tif (onto)\n-\t\twrite_file(rebase_path_onto(), \"%s\\n\", onto);\n+\t\twrite_file(rebase_path_onto(), \"%s\\n\",\n+\t\t\t   oid_to_hex(&onto->object.oid));\n \tif (orig_head)\n \t\twrite_file(rebase_path_orig_head(), \"%s\\n\", orig_head);\n \n@@ -3456,7 +3457,7 @@ int prepare_branch_to_be_rebased(struct repository *r, struct replay_opts *opts,\n }\n \n static int checkout_onto(struct repository *r, struct replay_opts *opts,\n-\t\t\t const char *onto_name, const char *onto,\n+\t\t\t const char *onto_name, const struct object_id *onto,\n \t\t\t const char *orig_head)\n {\n \tstruct object_id oid;\n@@ -3465,7 +3466,7 @@ static int checkout_onto(struct repository *r, struct replay_opts *opts,\n \tif (get_oid(orig_head, &oid))\n \t\treturn error(_(\"%s: not a valid OID\"), orig_head);\n \n-\tif (run_git_checkout(r, opts, onto, action)) {\n+\tif (run_git_checkout(r, opts, oid_to_hex(onto), action)) {\n \t\tapply_autostash(opts);\n \t\tsequencer_remove_state(opts);\n \t\treturn error(_(\"could not detach HEAD\"));\n@@ -4741,16 +4742,16 @@ static int skip_unnecessary_picks(struct repository *r,\n \n int complete_action(struct repository *r, struct replay_opts *opts, unsigned flags,\n \t\t    const char *shortrevisions, const char *onto_name,\n-\t\t    const char *onto, const char *orig_head, struct string_list *commands,\n-\t\t    unsigned autosquash, struct todo_list *todo_list)\n+\t\t    struct commit *onto, const char *orig_head,\n+\t\t    struct string_list *commands, unsigned autosquash,\n+\t\t    struct todo_list *todo_list)\n {\n \tconst char *shortonto, *todo_file = rebase_path_todo();\n \tstruct todo_list new_todo = TODO_LIST_INIT;\n \tstruct strbuf *buf = &todo_list->buf;\n-\tstruct object_id oid;\n+\tstruct object_id oid = onto->object.oid;\n \tint res;\n \n-\tget_oid(onto, &oid);\n \tshortonto = find_unique_abbrev(&oid, DEFAULT_ABBREV);\n \n \tif (buf->len == 0) {\n@@ -4793,7 +4794,7 @@ int complete_action(struct repository *r, struct replay_opts *opts, unsigned fla\n \tif (todo_list_parse_insn_buffer(r, new_todo.buf.buf, &new_todo) ||\n \t    todo_list_check(todo_list, &new_todo)) {\n \t\tfprintf(stderr, _(edit_todo_list_advice));\n-\t\tcheckout_onto(r, opts, onto_name, onto, orig_head);\n+\t\tcheckout_onto(r, opts, onto_name, &onto->object.oid, orig_head);\n \t\ttodo_list_release(&new_todo);\n \n \t\treturn -1;\n@@ -4812,7 +4813,7 @@ int complete_action(struct repository *r, struct replay_opts *opts, unsigned fla\n \n \ttodo_list_release(&new_todo);\n \n-\tif (checkout_onto(r, opts, onto_name, oid_to_hex(&oid), orig_head))\n+\tif (checkout_onto(r, opts, onto_name, &oid, orig_head))\n \t\treturn -1;\n \n \tif (require_clean_work_tree(r, \"rebase\", \"\", 1, 1))\ndiff --git a/sequencer.h b/sequencer.h\nindex 6c55aa4200..e640ca21f2 100644\n--- a/sequencer.h\n+++ b/sequencer.h\n@@ -150,7 +150,7 @@ void todo_list_add_exec_commands(struct todo_list *todo_list,\n int check_todo_list_from_file(struct repository *r);\n int complete_action(struct repository *r, struct replay_opts *opts, unsigned flags,\n \t\t    const char *shortrevisions, const char *onto_name,\n-\t\t    const char *onto, const char *orig_head, struct string_list *commands,\n+\t\t    struct commit *onto, const char *orig_head, struct string_list *commands,\n \t\t    unsigned autosquash, struct todo_list *todo_list);\n int todo_list_rearrange_squash(struct todo_list *todo_list);\n \n@@ -191,4 +191,4 @@ int read_author_script(const char *path, char **name, char **email, char **date,\n \n void parse_strategy_opts(struct replay_opts *opts, char *raw_opts);\n int write_basic_state(struct replay_opts *opts, const char *head_name,\n-\t\t      const char *onto, const char *orig_head);\n+\t\t      struct commit *onto, const char *orig_head);\n-- \n2.21.0\n\n"},{"id":"371923","messageId":"20190319190317.6632-5-phillip.wood123@gmail.com","threadId":"50780","inReplyTo":"20190319190317.6632-1-phillip.wood123@gmail.com","subject":"[RFC PATCH 04/11] rebase -i: combine rebase--interactive.c with rebase.c","fromName":"Phillip Wood","fromEmail":"phillip.wood123@gmail.com","sentAt":"2019-03-19T19:03:10Z","receivedAt":"2019-03-19T19:04:07Z","isPatch":true,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"From: Phillip Wood <phillip.wood@dunelm.org.uk>\n\nIn order to run `rebase -i` without forking `rebase--interactive` it\nwill be convenient to have all the code from rebase--interactive.c in\nrebase.c. This is a straight forward copy of the code from\nrebase--interactive.c, it will be simplified slightly in the next\ncommit.\n\nSigned-off-by: Phillip Wood <phillip.wood@dunelm.org.uk>\n---\n Makefile                      |   1 -\n builtin/rebase--interactive.c | 377 ----------------------------------\n builtin/rebase.c              | 367 +++++++++++++++++++++++++++++++++\n 3 files changed, 367 insertions(+), 378 deletions(-)\n delete mode 100644 builtin/rebase--interactive.c\n\ndiff --git a/Makefile b/Makefile\nindex 537493822b..c644089244 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -1130,7 +1130,6 @@ BUILTIN_OBJS += builtin/push.o\n BUILTIN_OBJS += builtin/range-diff.o\n BUILTIN_OBJS += builtin/read-tree.o\n BUILTIN_OBJS += builtin/rebase.o\n-BUILTIN_OBJS += builtin/rebase--interactive.o\n BUILTIN_OBJS += builtin/receive-pack.o\n BUILTIN_OBJS += builtin/reflog.o\n BUILTIN_OBJS += builtin/remote.o\ndiff --git a/builtin/rebase--interactive.c b/builtin/rebase--interactive.c\ndeleted file mode 100644\nindex d1a4ac1b84..0000000000\n--- a/builtin/rebase--interactive.c\n+++ /dev/null\n@@ -1,377 +0,0 @@\n-#define USE_THE_INDEX_COMPATIBILITY_MACROS\n-#include \"builtin.h\"\n-#include \"cache.h\"\n-#include \"config.h\"\n-#include \"parse-options.h\"\n-#include \"sequencer.h\"\n-#include \"rebase-interactive.h\"\n-#include \"argv-array.h\"\n-#include \"refs.h\"\n-#include \"rerere.h\"\n-#include \"run-command.h\"\n-\n-static GIT_PATH_FUNC(path_state_dir, \"rebase-merge/\")\n-static GIT_PATH_FUNC(path_squash_onto, \"rebase-merge/squash-onto\")\n-static GIT_PATH_FUNC(path_interactive, \"rebase-merge/interactive\")\n-\n-static int add_exec_commands(struct string_list *commands)\n-{\n-\tconst char *todo_file = rebase_path_todo();\n-\tstruct todo_list todo_list = TODO_LIST_INIT;\n-\tint res;\n-\n-\tif (strbuf_read_file(&todo_list.buf, todo_file, 0) < 0)\n-\t\treturn error_errno(_(\"could not read '%s'.\"), todo_file);\n-\n-\tif (todo_list_parse_insn_buffer(the_repository, todo_list.buf.buf,\n-\t\t\t\t\t&todo_list)) {\n-\t\ttodo_list_release(&todo_list);\n-\t\treturn error(_(\"unusable todo list: '%s'\"), todo_file);\n-\t}\n-\n-\ttodo_list_add_exec_commands(&todo_list, commands);\n-\tres = todo_list_write_to_file(the_repository, &todo_list,\n-\t\t\t\t      todo_file, NULL, NULL, -1, 0);\n-\ttodo_list_release(&todo_list);\n-\n-\tif (res)\n-\t\treturn error_errno(_(\"could not write '%s'.\"), todo_file);\n-\treturn 0;\n-}\n-\n-static int rearrange_squash_in_todo_file(void)\n-{\n-\tconst char *todo_file = rebase_path_todo();\n-\tstruct todo_list todo_list = TODO_LIST_INIT;\n-\tint res = 0;\n-\n-\tif (strbuf_read_file(&todo_list.buf, todo_file, 0) < 0)\n-\t\treturn error_errno(_(\"could not read '%s'.\"), todo_file);\n-\tif (todo_list_parse_insn_buffer(the_repository, todo_list.buf.buf,\n-\t\t\t\t\t&todo_list)) {\n-\t\ttodo_list_release(&todo_list);\n-\t\treturn error(_(\"unusable todo list: '%s'\"), todo_file);\n-\t}\n-\n-\tres = todo_list_rearrange_squash(&todo_list);\n-\tif (!res)\n-\t\tres = todo_list_write_to_file(the_repository, &todo_list,\n-\t\t\t\t\t      todo_file, NULL, NULL, -1, 0);\n-\n-\ttodo_list_release(&todo_list);\n-\n-\tif (res)\n-\t\treturn error_errno(_(\"could not write '%s'.\"), todo_file);\n-\treturn 0;\n-}\n-\n-static int transform_todo_file(unsigned flags)\n-{\n-\tconst char *todo_file = rebase_path_todo();\n-\tstruct todo_list todo_list = TODO_LIST_INIT;\n-\tint res;\n-\n-\tif (strbuf_read_file(&todo_list.buf, todo_file, 0) < 0)\n-\t\treturn error_errno(_(\"could not read '%s'.\"), todo_file);\n-\n-\tif (todo_list_parse_insn_buffer(the_repository, todo_list.buf.buf,\n-\t\t\t\t\t&todo_list)) {\n-\t\ttodo_list_release(&todo_list);\n-\t\treturn error(_(\"unusable todo list: '%s'\"), todo_file);\n-\t}\n-\n-\tres = todo_list_write_to_file(the_repository, &todo_list, todo_file,\n-\t\t\t\t      NULL, NULL, -1, flags);\n-\ttodo_list_release(&todo_list);\n-\n-\tif (res)\n-\t\treturn error_errno(_(\"could not write '%s'.\"), todo_file);\n-\treturn 0;\n-}\n-\n-static int edit_todo_file(unsigned flags)\n-{\n-\tconst char *todo_file = rebase_path_todo();\n-\tstruct todo_list todo_list = TODO_LIST_INIT,\n-\t\tnew_todo = TODO_LIST_INIT;\n-\tint res = 0;\n-\n-\tif (strbuf_read_file(&todo_list.buf, todo_file, 0) < 0)\n-\t\treturn error_errno(_(\"could not read '%s'.\"), todo_file);\n-\n-\tstrbuf_stripspace(&todo_list.buf, 1);\n-\tres = edit_todo_list(the_repository, &todo_list, &new_todo, NULL, NULL, flags);\n-\tif (!res && todo_list_write_to_file(the_repository, &new_todo, todo_file,\n-\t\t\t\t\t    NULL, NULL, -1, flags & ~(TODO_LIST_SHORTEN_IDS)))\n-\t\tres = error_errno(_(\"could not write '%s'\"), todo_file);\n-\n-\ttodo_list_release(&todo_list);\n-\ttodo_list_release(&new_todo);\n-\n-\treturn res;\n-}\n-\n-static int get_revision_ranges(const char *upstream, const char *onto,\n-\t\t\t       const char **head_hash,\n-\t\t\t       char **revisions, char **shortrevisions)\n-{\n-\tconst char *base_rev = upstream ? upstream : onto, *shorthead;\n-\tstruct object_id orig_head;\n-\n-\tif (get_oid(\"HEAD\", &orig_head))\n-\t\treturn error(_(\"no HEAD?\"));\n-\n-\t*head_hash = find_unique_abbrev(&orig_head, GIT_MAX_HEXSZ);\n-\t*revisions = xstrfmt(\"%s...%s\", base_rev, *head_hash);\n-\n-\tshorthead = find_unique_abbrev(&orig_head, DEFAULT_ABBREV);\n-\n-\tif (upstream) {\n-\t\tconst char *shortrev;\n-\t\tstruct object_id rev_oid;\n-\n-\t\tget_oid(base_rev, &rev_oid);\n-\t\tshortrev = find_unique_abbrev(&rev_oid, DEFAULT_ABBREV);\n-\n-\t\t*shortrevisions = xstrfmt(\"%s..%s\", shortrev, shorthead);\n-\t} else\n-\t\t*shortrevisions = xstrdup(shorthead);\n-\n-\treturn 0;\n-}\n-\n-static int init_basic_state(struct replay_opts *opts, const char *head_name,\n-\t\t\t    const char *onto, const char *orig_head)\n-{\n-\tFILE *interactive;\n-\n-\tif (!is_directory(path_state_dir()) && mkdir_in_gitdir(path_state_dir()))\n-\t\treturn error_errno(_(\"could not create temporary %s\"), path_state_dir());\n-\n-\tdelete_reflog(\"REBASE_HEAD\");\n-\n-\tinteractive = fopen(path_interactive(), \"w\");\n-\tif (!interactive)\n-\t\treturn error_errno(_(\"could not mark as interactive\"));\n-\tfclose(interactive);\n-\n-\treturn write_basic_state(opts, head_name, onto, orig_head);\n-}\n-\n-static int do_interactive_rebase(struct replay_opts *opts, unsigned flags,\n-\t\t\t\t const char *switch_to, const char *upstream,\n-\t\t\t\t const char *onto, const char *onto_name,\n-\t\t\t\t const char *squash_onto, const char *head_name,\n-\t\t\t\t const char *restrict_revision, char *raw_strategies,\n-\t\t\t\t struct string_list *commands, unsigned autosquash)\n-{\n-\tint ret;\n-\tconst char *head_hash = NULL;\n-\tchar *revisions = NULL, *shortrevisions = NULL;\n-\tstruct argv_array make_script_args = ARGV_ARRAY_INIT;\n-\tstruct todo_list todo_list = TODO_LIST_INIT;\n-\n-\tif (prepare_branch_to_be_rebased(the_repository, opts, switch_to))\n-\t\treturn -1;\n-\n-\tif (get_revision_ranges(upstream, onto, &head_hash,\n-\t\t\t\t&revisions, &shortrevisions))\n-\t\treturn -1;\n-\n-\tif (raw_strategies)\n-\t\tparse_strategy_opts(opts, raw_strategies);\n-\n-\tif (init_basic_state(opts, head_name, onto, head_hash)) {\n-\t\tfree(revisions);\n-\t\tfree(shortrevisions);\n-\n-\t\treturn -1;\n-\t}\n-\n-\tif (!upstream && squash_onto)\n-\t\twrite_file(path_squash_onto(), \"%s\\n\", squash_onto);\n-\n-\targv_array_pushl(&make_script_args, \"\", revisions, NULL);\n-\tif (restrict_revision)\n-\t\targv_array_push(&make_script_args, restrict_revision);\n-\n-\tret = sequencer_make_script(the_repository, &todo_list.buf,\n-\t\t\t\t    make_script_args.argc, make_script_args.argv,\n-\t\t\t\t    flags);\n-\n-\tif (ret)\n-\t\terror(_(\"could not generate todo list\"));\n-\telse {\n-\t\tdiscard_cache();\n-\t\tif (todo_list_parse_insn_buffer(the_repository, todo_list.buf.buf,\n-\t\t\t\t\t\t&todo_list))\n-\t\t\tBUG(\"unusable todo list\");\n-\n-\t\tret = complete_action(the_repository, opts, flags, shortrevisions, onto_name,\n-\t\t\t\t      onto, head_hash, commands, autosquash, &todo_list);\n-\t}\n-\n-\tfree(revisions);\n-\tfree(shortrevisions);\n-\ttodo_list_release(&todo_list);\n-\targv_array_clear(&make_script_args);\n-\n-\treturn ret;\n-}\n-\n-static const char * const builtin_rebase_interactive_usage[] = {\n-\tN_(\"git rebase--interactive [<options>]\"),\n-\tNULL\n-};\n-\n-int cmd_rebase__interactive(int argc, const char **argv, const char *prefix)\n-{\n-\tstruct replay_opts opts = REPLAY_OPTS_INIT;\n-\tunsigned flags = 0, keep_empty = 0, rebase_merges = 0, autosquash = 0;\n-\tint abbreviate_commands = 0, rebase_cousins = -1, ret = 0;\n-\tconst char *onto = NULL, *onto_name = NULL, *restrict_revision = NULL,\n-\t\t*squash_onto = NULL, *upstream = NULL, *head_name = NULL,\n-\t\t*switch_to = NULL, *cmd = NULL;\n-\tstruct string_list commands = STRING_LIST_INIT_DUP;\n-\tchar *raw_strategies = NULL;\n-\tenum {\n-\t\tNONE = 0, CONTINUE, SKIP, EDIT_TODO, SHOW_CURRENT_PATCH,\n-\t\tSHORTEN_OIDS, EXPAND_OIDS, CHECK_TODO_LIST, REARRANGE_SQUASH, ADD_EXEC\n-\t} command = 0;\n-\tstruct option options[] = {\n-\t\tOPT_BOOL(0, \"ff\", &opts.allow_ff, N_(\"allow fast-forward\")),\n-\t\tOPT_BOOL(0, \"keep-empty\", &keep_empty, N_(\"keep empty commits\")),\n-\t\tOPT_BOOL(0, \"allow-empty-message\", &opts.allow_empty_message,\n-\t\t\t N_(\"allow commits with empty messages\")),\n-\t\tOPT_BOOL(0, \"rebase-merges\", &rebase_merges, N_(\"rebase merge commits\")),\n-\t\tOPT_BOOL(0, \"rebase-cousins\", &rebase_cousins,\n-\t\t\t N_(\"keep original branch points of cousins\")),\n-\t\tOPT_BOOL(0, \"autosquash\", &autosquash,\n-\t\t\t N_(\"move commits that begin with squash!/fixup!\")),\n-\t\tOPT_BOOL(0, \"signoff\", &opts.signoff, N_(\"sign commits\")),\n-\t\tOPT__VERBOSE(&opts.verbose, N_(\"be verbose\")),\n-\t\tOPT_CMDMODE(0, \"continue\", &command, N_(\"continue rebase\"),\n-\t\t\t    CONTINUE),\n-\t\tOPT_CMDMODE(0, \"skip\", &command, N_(\"skip commit\"), SKIP),\n-\t\tOPT_CMDMODE(0, \"edit-todo\", &command, N_(\"edit the todo list\"),\n-\t\t\t    EDIT_TODO),\n-\t\tOPT_CMDMODE(0, \"show-current-patch\", &command, N_(\"show the current patch\"),\n-\t\t\t    SHOW_CURRENT_PATCH),\n-\t\tOPT_CMDMODE(0, \"shorten-ids\", &command,\n-\t\t\tN_(\"shorten commit ids in the todo list\"), SHORTEN_OIDS),\n-\t\tOPT_CMDMODE(0, \"expand-ids\", &command,\n-\t\t\tN_(\"expand commit ids in the todo list\"), EXPAND_OIDS),\n-\t\tOPT_CMDMODE(0, \"check-todo-list\", &command,\n-\t\t\tN_(\"check the todo list\"), CHECK_TODO_LIST),\n-\t\tOPT_CMDMODE(0, \"rearrange-squash\", &command,\n-\t\t\tN_(\"rearrange fixup/squash lines\"), REARRANGE_SQUASH),\n-\t\tOPT_CMDMODE(0, \"add-exec-commands\", &command,\n-\t\t\tN_(\"insert exec commands in todo list\"), ADD_EXEC),\n-\t\tOPT_STRING(0, \"onto\", &onto, N_(\"onto\"), N_(\"onto\")),\n-\t\tOPT_STRING(0, \"restrict-revision\", &restrict_revision,\n-\t\t\t   N_(\"restrict-revision\"), N_(\"restrict revision\")),\n-\t\tOPT_STRING(0, \"squash-onto\", &squash_onto, N_(\"squash-onto\"),\n-\t\t\t   N_(\"squash onto\")),\n-\t\tOPT_STRING(0, \"upstream\", &upstream, N_(\"upstream\"),\n-\t\t\t   N_(\"the upstream commit\")),\n-\t\tOPT_STRING(0, \"head-name\", &head_name, N_(\"head-name\"), N_(\"head name\")),\n-\t\t{ OPTION_STRING, 'S', \"gpg-sign\", &opts.gpg_sign, N_(\"key-id\"),\n-\t\t\tN_(\"GPG-sign commits\"),\n-\t\t\tPARSE_OPT_OPTARG, NULL, (intptr_t) \"\" },\n-\t\tOPT_STRING(0, \"strategy\", &opts.strategy, N_(\"strategy\"),\n-\t\t\t   N_(\"rebase strategy\")),\n-\t\tOPT_STRING(0, \"strategy-opts\", &raw_strategies, N_(\"strategy-opts\"),\n-\t\t\t   N_(\"strategy options\")),\n-\t\tOPT_STRING(0, \"switch-to\", &switch_to, N_(\"switch-to\"),\n-\t\t\t   N_(\"the branch or commit to checkout\")),\n-\t\tOPT_STRING(0, \"onto-name\", &onto_name, N_(\"onto-name\"), N_(\"onto name\")),\n-\t\tOPT_STRING(0, \"cmd\", &cmd, N_(\"cmd\"), N_(\"the command to run\")),\n-\t\tOPT_RERERE_AUTOUPDATE(&opts.allow_rerere_auto),\n-\t\tOPT_BOOL(0, \"reschedule-failed-exec\", &opts.reschedule_failed_exec,\n-\t\t\t N_(\"automatically re-schedule any `exec` that fails\")),\n-\t\tOPT_END()\n-\t};\n-\n-\tsequencer_init_config(&opts);\n-\tgit_config_get_bool(\"rebase.abbreviatecommands\", &abbreviate_commands);\n-\n-\topts.action = REPLAY_INTERACTIVE_REBASE;\n-\topts.allow_ff = 1;\n-\topts.allow_empty = 1;\n-\n-\tif (argc == 1)\n-\t\tusage_with_options(builtin_rebase_interactive_usage, options);\n-\n-\targc = parse_options(argc, argv, NULL, options,\n-\t\t\tbuiltin_rebase_interactive_usage, PARSE_OPT_KEEP_ARGV0);\n-\n-\topts.gpg_sign = xstrdup_or_null(opts.gpg_sign);\n-\n-\tflags |= keep_empty ? TODO_LIST_KEEP_EMPTY : 0;\n-\tflags |= abbreviate_commands ? TODO_LIST_ABBREVIATE_CMDS : 0;\n-\tflags |= rebase_merges ? TODO_LIST_REBASE_MERGES : 0;\n-\tflags |= rebase_cousins > 0 ? TODO_LIST_REBASE_COUSINS : 0;\n-\tflags |= command == SHORTEN_OIDS ? TODO_LIST_SHORTEN_IDS : 0;\n-\n-\tif (rebase_cousins >= 0 && !rebase_merges)\n-\t\twarning(_(\"--[no-]rebase-cousins has no effect without \"\n-\t\t\t  \"--rebase-merges\"));\n-\n-\tif (cmd && *cmd) {\n-\t\tstring_list_split(&commands, cmd, '\\n', -1);\n-\n-\t\t/* rebase.c adds a new line to cmd after every command,\n-\t\t * so here the last command is always empty */\n-\t\tstring_list_remove_empty_items(&commands, 0);\n-\t}\n-\n-\tswitch (command) {\n-\tcase NONE:\n-\t\tif (!onto && !upstream)\n-\t\t\tdie(_(\"a base commit must be provided with --upstream or --onto\"));\n-\n-\t\tret = do_interactive_rebase(&opts, flags, switch_to, upstream, onto,\n-\t\t\t\t\t    onto_name, squash_onto, head_name, restrict_revision,\n-\t\t\t\t\t    raw_strategies, &commands, autosquash);\n-\t\tbreak;\n-\tcase SKIP: {\n-\t\tstruct string_list merge_rr = STRING_LIST_INIT_DUP;\n-\n-\t\trerere_clear(the_repository, &merge_rr);\n-\t\t/* fallthrough */\n-\tcase CONTINUE:\n-\t\tret = sequencer_continue(the_repository, &opts);\n-\t\tbreak;\n-\t}\n-\tcase EDIT_TODO:\n-\t\tret = edit_todo_file(flags);\n-\t\tbreak;\n-\tcase SHOW_CURRENT_PATCH: {\n-\t\tstruct child_process cmd = CHILD_PROCESS_INIT;\n-\n-\t\tcmd.git_cmd = 1;\n-\t\targv_array_pushl(&cmd.args, \"show\", \"REBASE_HEAD\", \"--\", NULL);\n-\t\tret = run_command(&cmd);\n-\n-\t\tbreak;\n-\t}\n-\tcase SHORTEN_OIDS:\n-\tcase EXPAND_OIDS:\n-\t\tret = transform_todo_file(flags);\n-\t\tbreak;\n-\tcase CHECK_TODO_LIST:\n-\t\tret = check_todo_list_from_file(the_repository);\n-\t\tbreak;\n-\tcase REARRANGE_SQUASH:\n-\t\tret = rearrange_squash_in_todo_file();\n-\t\tbreak;\n-\tcase ADD_EXEC:\n-\t\tret = add_exec_commands(&commands);\n-\t\tbreak;\n-\tdefault:\n-\t\tBUG(\"invalid command '%d'\", command);\n-\t}\n-\n-\tstring_list_clear(&commands, 0);\n-\treturn !!ret;\n-}\ndiff --git a/builtin/rebase.c b/builtin/rebase.c\nindex ccf178326c..80252d72df 100644\n--- a/builtin/rebase.c\n+++ b/builtin/rebase.c\n@@ -25,6 +25,8 @@\n #include \"commit-reach.h\"\n #include \"rerere.h\"\n #include \"branch.h\"\n+#include \"sequencer.h\"\n+#include \"rebase-interactive.h\"\n \n static char const * const builtin_rebase_usage[] = {\n \tN_(\"git rebase [-i] [options] [--exec <cmd>] [--onto <newbase>] \"\n@@ -35,6 +37,9 @@ static char const * const builtin_rebase_usage[] = {\n \tNULL\n };\n \n+static GIT_PATH_FUNC(path_state_dir, \"rebase-merge/\")\n+static GIT_PATH_FUNC(path_squash_onto, \"rebase-merge/squash-onto\")\n+static GIT_PATH_FUNC(path_interactive, \"rebase-merge/interactive\")\n static GIT_PATH_FUNC(apply_dir, \"rebase-apply\")\n static GIT_PATH_FUNC(merge_dir, \"rebase-merge\")\n \n@@ -46,6 +51,368 @@ enum rebase_type {\n \tREBASE_PRESERVE_MERGES\n };\n \n+static int add_exec_commands(struct string_list *commands)\n+{\n+\tconst char *todo_file = rebase_path_todo();\n+\tstruct todo_list todo_list = TODO_LIST_INIT;\n+\tint res;\n+\n+\tif (strbuf_read_file(&todo_list.buf, todo_file, 0) < 0)\n+\t\treturn error_errno(_(\"could not read '%s'.\"), todo_file);\n+\n+\tif (todo_list_parse_insn_buffer(the_repository, todo_list.buf.buf,\n+\t\t\t\t\t&todo_list)) {\n+\t\ttodo_list_release(&todo_list);\n+\t\treturn error(_(\"unusable todo list: '%s'\"), todo_file);\n+\t}\n+\n+\ttodo_list_add_exec_commands(&todo_list, commands);\n+\tres = todo_list_write_to_file(the_repository, &todo_list,\n+\t\t\t\t      todo_file, NULL, NULL, -1, 0);\n+\ttodo_list_release(&todo_list);\n+\n+\tif (res)\n+\t\treturn error_errno(_(\"could not write '%s'.\"), todo_file);\n+\treturn 0;\n+}\n+\n+static int rearrange_squash_in_todo_file(void)\n+{\n+\tconst char *todo_file = rebase_path_todo();\n+\tstruct todo_list todo_list = TODO_LIST_INIT;\n+\tint res = 0;\n+\n+\tif (strbuf_read_file(&todo_list.buf, todo_file, 0) < 0)\n+\t\treturn error_errno(_(\"could not read '%s'.\"), todo_file);\n+\tif (todo_list_parse_insn_buffer(the_repository, todo_list.buf.buf,\n+\t\t\t\t\t&todo_list)) {\n+\t\ttodo_list_release(&todo_list);\n+\t\treturn error(_(\"unusable todo list: '%s'\"), todo_file);\n+\t}\n+\n+\tres = todo_list_rearrange_squash(&todo_list);\n+\tif (!res)\n+\t\tres = todo_list_write_to_file(the_repository, &todo_list,\n+\t\t\t\t\t      todo_file, NULL, NULL, -1, 0);\n+\n+\ttodo_list_release(&todo_list);\n+\n+\tif (res)\n+\t\treturn error_errno(_(\"could not write '%s'.\"), todo_file);\n+\treturn 0;\n+}\n+\n+static int transform_todo_file(unsigned flags)\n+{\n+\tconst char *todo_file = rebase_path_todo();\n+\tstruct todo_list todo_list = TODO_LIST_INIT;\n+\tint res;\n+\n+\tif (strbuf_read_file(&todo_list.buf, todo_file, 0) < 0)\n+\t\treturn error_errno(_(\"could not read '%s'.\"), todo_file);\n+\n+\tif (todo_list_parse_insn_buffer(the_repository, todo_list.buf.buf,\n+\t\t\t\t\t&todo_list)) {\n+\t\ttodo_list_release(&todo_list);\n+\t\treturn error(_(\"unusable todo list: '%s'\"), todo_file);\n+\t}\n+\n+\tres = todo_list_write_to_file(the_repository, &todo_list, todo_file,\n+\t\t\t\t      NULL, NULL, -1, flags);\n+\ttodo_list_release(&todo_list);\n+\n+\tif (res)\n+\t\treturn error_errno(_(\"could not write '%s'.\"), todo_file);\n+\treturn 0;\n+}\n+\n+static int edit_todo_file(unsigned flags)\n+{\n+\tconst char *todo_file = rebase_path_todo();\n+\tstruct todo_list todo_list = TODO_LIST_INIT,\n+\t\tnew_todo = TODO_LIST_INIT;\n+\tint res = 0;\n+\n+\tif (strbuf_read_file(&todo_list.buf, todo_file, 0) < 0)\n+\t\treturn error_errno(_(\"could not read '%s'.\"), todo_file);\n+\n+\tstrbuf_stripspace(&todo_list.buf, 1);\n+\tres = edit_todo_list(the_repository, &todo_list, &new_todo, NULL, NULL, flags);\n+\tif (!res && todo_list_write_to_file(the_repository, &new_todo, todo_file,\n+\t\t\t\t\t    NULL, NULL, -1, flags & ~(TODO_LIST_SHORTEN_IDS)))\n+\t\tres = error_errno(_(\"could not write '%s'\"), todo_file);\n+\n+\ttodo_list_release(&todo_list);\n+\ttodo_list_release(&new_todo);\n+\n+\treturn res;\n+}\n+\n+static int get_revision_ranges(const char *upstream, const char *onto,\n+\t\t\t       const char **head_hash,\n+\t\t\t       char **revisions, char **shortrevisions)\n+{\n+\tconst char *base_rev = upstream ? upstream : onto, *shorthead;\n+\tstruct object_id orig_head;\n+\n+\tif (get_oid(\"HEAD\", &orig_head))\n+\t\treturn error(_(\"no HEAD?\"));\n+\n+\t*head_hash = find_unique_abbrev(&orig_head, GIT_MAX_HEXSZ);\n+\t*revisions = xstrfmt(\"%s...%s\", base_rev, *head_hash);\n+\n+\tshorthead = find_unique_abbrev(&orig_head, DEFAULT_ABBREV);\n+\n+\tif (upstream) {\n+\t\tconst char *shortrev;\n+\t\tstruct object_id rev_oid;\n+\n+\t\tget_oid(base_rev, &rev_oid);\n+\t\tshortrev = find_unique_abbrev(&rev_oid, DEFAULT_ABBREV);\n+\n+\t\t*shortrevisions = xstrfmt(\"%s..%s\", shortrev, shorthead);\n+\t} else\n+\t\t*shortrevisions = xstrdup(shorthead);\n+\n+\treturn 0;\n+}\n+\n+static int init_basic_state(struct replay_opts *opts, const char *head_name,\n+\t\t\t    const char *onto, const char *orig_head)\n+{\n+\tFILE *interactive;\n+\n+\tif (!is_directory(path_state_dir()) && mkdir_in_gitdir(path_state_dir()))\n+\t\treturn error_errno(_(\"could not create temporary %s\"), path_state_dir());\n+\n+\tdelete_reflog(\"REBASE_HEAD\");\n+\n+\tinteractive = fopen(path_interactive(), \"w\");\n+\tif (!interactive)\n+\t\treturn error_errno(_(\"could not mark as interactive\"));\n+\tfclose(interactive);\n+\n+\treturn write_basic_state(opts, head_name, onto, orig_head);\n+}\n+\n+static int do_interactive_rebase(struct replay_opts *opts, unsigned flags,\n+\t\t\t\t const char *switch_to, const char *upstream,\n+\t\t\t\t const char *onto, const char *onto_name,\n+\t\t\t\t const char *squash_onto, const char *head_name,\n+\t\t\t\t const char *restrict_revision, char *raw_strategies,\n+\t\t\t\t struct string_list *commands, unsigned autosquash)\n+{\n+\tint ret;\n+\tconst char *head_hash = NULL;\n+\tchar *revisions = NULL, *shortrevisions = NULL;\n+\tstruct argv_array make_script_args = ARGV_ARRAY_INIT;\n+\tstruct todo_list todo_list = TODO_LIST_INIT;\n+\n+\tif (prepare_branch_to_be_rebased(the_repository, opts, switch_to))\n+\t\treturn -1;\n+\n+\tif (get_revision_ranges(upstream, onto, &head_hash,\n+\t\t\t\t&revisions, &shortrevisions))\n+\t\treturn -1;\n+\n+\tif (raw_strategies)\n+\t\tparse_strategy_opts(opts, raw_strategies);\n+\n+\tif (init_basic_state(opts, head_name, onto, head_hash)) {\n+\t\tfree(revisions);\n+\t\tfree(shortrevisions);\n+\n+\t\treturn -1;\n+\t}\n+\n+\tif (!upstream && squash_onto)\n+\t\twrite_file(path_squash_onto(), \"%s\\n\", squash_onto);\n+\n+\targv_array_pushl(&make_script_args, \"\", revisions, NULL);\n+\tif (restrict_revision)\n+\t\targv_array_push(&make_script_args, restrict_revision);\n+\n+\tret = sequencer_make_script(the_repository, &todo_list.buf,\n+\t\t\t\t    make_script_args.argc, make_script_args.argv,\n+\t\t\t\t    flags);\n+\n+\tif (ret)\n+\t\terror(_(\"could not generate todo list\"));\n+\telse {\n+\t\tdiscard_cache();\n+\t\tif (todo_list_parse_insn_buffer(the_repository, todo_list.buf.buf,\n+\t\t\t\t\t\t&todo_list))\n+\t\t\tBUG(\"unusable todo list\");\n+\n+\t\tret = complete_action(the_repository, opts, flags, shortrevisions, onto_name,\n+\t\t\t\t      onto, head_hash, commands, autosquash, &todo_list);\n+\t}\n+\n+\tfree(revisions);\n+\tfree(shortrevisions);\n+\ttodo_list_release(&todo_list);\n+\targv_array_clear(&make_script_args);\n+\n+\treturn ret;\n+}\n+\n+static const char * const builtin_rebase_interactive_usage[] = {\n+\tN_(\"git rebase--interactive [<options>]\"),\n+\tNULL\n+};\n+\n+int cmd_rebase__interactive(int argc, const char **argv, const char *prefix)\n+{\n+\tstruct replay_opts opts = REPLAY_OPTS_INIT;\n+\tunsigned flags = 0, keep_empty = 0, rebase_merges = 0, autosquash = 0;\n+\tint abbreviate_commands = 0, rebase_cousins = -1, ret = 0;\n+\tconst char *onto = NULL, *onto_name = NULL, *restrict_revision = NULL,\n+\t\t*squash_onto = NULL, *upstream = NULL, *head_name = NULL,\n+\t\t*switch_to = NULL, *cmd = NULL;\n+\tstruct string_list commands = STRING_LIST_INIT_DUP;\n+\tchar *raw_strategies = NULL;\n+\tenum {\n+\t\tNONE = 0, CONTINUE, SKIP, EDIT_TODO, SHOW_CURRENT_PATCH,\n+\t\tSHORTEN_OIDS, EXPAND_OIDS, CHECK_TODO_LIST, REARRANGE_SQUASH, ADD_EXEC\n+\t} command = 0;\n+\tstruct option options[] = {\n+\t\tOPT_BOOL(0, \"ff\", &opts.allow_ff, N_(\"allow fast-forward\")),\n+\t\tOPT_BOOL(0, \"keep-empty\", &keep_empty, N_(\"keep empty commits\")),\n+\t\tOPT_BOOL(0, \"allow-empty-message\", &opts.allow_empty_message,\n+\t\t\t N_(\"allow commits with empty messages\")),\n+\t\tOPT_BOOL(0, \"rebase-merges\", &rebase_merges, N_(\"rebase merge commits\")),\n+\t\tOPT_BOOL(0, \"rebase-cousins\", &rebase_cousins,\n+\t\t\t N_(\"keep original branch points of cousins\")),\n+\t\tOPT_BOOL(0, \"autosquash\", &autosquash,\n+\t\t\t N_(\"move commits that begin with squash!/fixup!\")),\n+\t\tOPT_BOOL(0, \"signoff\", &opts.signoff, N_(\"sign commits\")),\n+\t\tOPT__VERBOSE(&opts.verbose, N_(\"be verbose\")),\n+\t\tOPT_CMDMODE(0, \"continue\", &command, N_(\"continue rebase\"),\n+\t\t\t    CONTINUE),\n+\t\tOPT_CMDMODE(0, \"skip\", &command, N_(\"skip commit\"), SKIP),\n+\t\tOPT_CMDMODE(0, \"edit-todo\", &command, N_(\"edit the todo list\"),\n+\t\t\t    EDIT_TODO),\n+\t\tOPT_CMDMODE(0, \"show-current-patch\", &command, N_(\"show the current patch\"),\n+\t\t\t    SHOW_CURRENT_PATCH),\n+\t\tOPT_CMDMODE(0, \"shorten-ids\", &command,\n+\t\t\tN_(\"shorten commit ids in the todo list\"), SHORTEN_OIDS),\n+\t\tOPT_CMDMODE(0, \"expand-ids\", &command,\n+\t\t\tN_(\"expand commit ids in the todo list\"), EXPAND_OIDS),\n+\t\tOPT_CMDMODE(0, \"check-todo-list\", &command,\n+\t\t\tN_(\"check the todo list\"), CHECK_TODO_LIST),\n+\t\tOPT_CMDMODE(0, \"rearrange-squash\", &command,\n+\t\t\tN_(\"rearrange fixup/squash lines\"), REARRANGE_SQUASH),\n+\t\tOPT_CMDMODE(0, \"add-exec-commands\", &command,\n+\t\t\tN_(\"insert exec commands in todo list\"), ADD_EXEC),\n+\t\tOPT_STRING(0, \"onto\", &onto, N_(\"onto\"), N_(\"onto\")),\n+\t\tOPT_STRING(0, \"restrict-revision\", &restrict_revision,\n+\t\t\t   N_(\"restrict-revision\"), N_(\"restrict revision\")),\n+\t\tOPT_STRING(0, \"squash-onto\", &squash_onto, N_(\"squash-onto\"),\n+\t\t\t   N_(\"squash onto\")),\n+\t\tOPT_STRING(0, \"upstream\", &upstream, N_(\"upstream\"),\n+\t\t\t   N_(\"the upstream commit\")),\n+\t\tOPT_STRING(0, \"head-name\", &head_name, N_(\"head-name\"), N_(\"head name\")),\n+\t\t{ OPTION_STRING, 'S', \"gpg-sign\", &opts.gpg_sign, N_(\"key-id\"),\n+\t\t\tN_(\"GPG-sign commits\"),\n+\t\t\tPARSE_OPT_OPTARG, NULL, (intptr_t) \"\" },\n+\t\tOPT_STRING(0, \"strategy\", &opts.strategy, N_(\"strategy\"),\n+\t\t\t   N_(\"rebase strategy\")),\n+\t\tOPT_STRING(0, \"strategy-opts\", &raw_strategies, N_(\"strategy-opts\"),\n+\t\t\t   N_(\"strategy options\")),\n+\t\tOPT_STRING(0, \"switch-to\", &switch_to, N_(\"switch-to\"),\n+\t\t\t   N_(\"the branch or commit to checkout\")),\n+\t\tOPT_STRING(0, \"onto-name\", &onto_name, N_(\"onto-name\"), N_(\"onto name\")),\n+\t\tOPT_STRING(0, \"cmd\", &cmd, N_(\"cmd\"), N_(\"the command to run\")),\n+\t\tOPT_RERERE_AUTOUPDATE(&opts.allow_rerere_auto),\n+\t\tOPT_BOOL(0, \"reschedule-failed-exec\", &opts.reschedule_failed_exec,\n+\t\t\t N_(\"automatically re-schedule any `exec` that fails\")),\n+\t\tOPT_END()\n+\t};\n+\n+\tsequencer_init_config(&opts);\n+\tgit_config_get_bool(\"rebase.abbreviatecommands\", &abbreviate_commands);\n+\n+\topts.action = REPLAY_INTERACTIVE_REBASE;\n+\topts.allow_ff = 1;\n+\topts.allow_empty = 1;\n+\n+\tif (argc == 1)\n+\t\tusage_with_options(builtin_rebase_interactive_usage, options);\n+\n+\targc = parse_options(argc, argv, NULL, options,\n+\t\t\tbuiltin_rebase_interactive_usage, PARSE_OPT_KEEP_ARGV0);\n+\n+\topts.gpg_sign = xstrdup_or_null(opts.gpg_sign);\n+\n+\tflags |= keep_empty ? TODO_LIST_KEEP_EMPTY : 0;\n+\tflags |= abbreviate_commands ? TODO_LIST_ABBREVIATE_CMDS : 0;\n+\tflags |= rebase_merges ? TODO_LIST_REBASE_MERGES : 0;\n+\tflags |= rebase_cousins > 0 ? TODO_LIST_REBASE_COUSINS : 0;\n+\tflags |= command == SHORTEN_OIDS ? TODO_LIST_SHORTEN_IDS : 0;\n+\n+\tif (rebase_cousins >= 0 && !rebase_merges)\n+\t\twarning(_(\"--[no-]rebase-cousins has no effect without \"\n+\t\t\t  \"--rebase-merges\"));\n+\n+\tif (cmd && *cmd) {\n+\t\tstring_list_split(&commands, cmd, '\\n', -1);\n+\n+\t\t/* rebase.c adds a new line to cmd after every command,\n+\t\t * so here the last command is always empty */\n+\t\tstring_list_remove_empty_items(&commands, 0);\n+\t}\n+\n+\tswitch (command) {\n+\tcase NONE:\n+\t\tif (!onto && !upstream)\n+\t\t\tdie(_(\"a base commit must be provided with --upstream or --onto\"));\n+\n+\t\tret = do_interactive_rebase(&opts, flags, switch_to, upstream, onto,\n+\t\t\t\t\t    onto_name, squash_onto, head_name, restrict_revision,\n+\t\t\t\t\t    raw_strategies, &commands, autosquash);\n+\t\tbreak;\n+\tcase SKIP: {\n+\t\tstruct string_list merge_rr = STRING_LIST_INIT_DUP;\n+\n+\t\trerere_clear(the_repository, &merge_rr);\n+\t\t/* fallthrough */\n+\tcase CONTINUE:\n+\t\tret = sequencer_continue(the_repository, &opts);\n+\t\tbreak;\n+\t}\n+\tcase EDIT_TODO:\n+\t\tret = edit_todo_file(flags);\n+\t\tbreak;\n+\tcase SHOW_CURRENT_PATCH: {\n+\t\tstruct child_process cmd = CHILD_PROCESS_INIT;\n+\n+\t\tcmd.git_cmd = 1;\n+\t\targv_array_pushl(&cmd.args, \"show\", \"REBASE_HEAD\", \"--\", NULL);\n+\t\tret = run_command(&cmd);\n+\n+\t\tbreak;\n+\t}\n+\tcase SHORTEN_OIDS:\n+\tcase EXPAND_OIDS:\n+\t\tret = transform_todo_file(flags);\n+\t\tbreak;\n+\tcase CHECK_TODO_LIST:\n+\t\tret = check_todo_list_from_file(the_repository);\n+\t\tbreak;\n+\tcase REARRANGE_SQUASH:\n+\t\tret = rearrange_squash_in_todo_file();\n+\t\tbreak;\n+\tcase ADD_EXEC:\n+\t\tret = add_exec_commands(&commands);\n+\t\tbreak;\n+\tdefault:\n+\t\tBUG(\"invalid command '%d'\", command);\n+\t}\n+\n+\tstring_list_clear(&commands, 0);\n+\treturn !!ret;\n+}\n+\n static int use_builtin_rebase(void)\n {\n \tstruct child_process cp = CHILD_PROCESS_INIT;\n-- \n2.21.0\n\n"},{"id":"371924","messageId":"20190319190317.6632-8-phillip.wood123@gmail.com","threadId":"50780","inReplyTo":"20190319190317.6632-1-phillip.wood123@gmail.com","subject":"[RFC PATCH 07/11] rebase -i: use struct object_id for squash_onto","fromName":"Phillip Wood","fromEmail":"phillip.wood123@gmail.com","sentAt":"2019-03-19T19:03:13Z","receivedAt":"2019-03-19T19:04:09Z","isPatch":true,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"From: Phillip Wood <phillip.wood@dunelm.org.uk>\n\nMore preparation for using `struct rebase_options` in\ncmd_rebase__interactive(). Using a string was a hangover from the\nscripted version of rebase, update the functions that use `squash_onto`\nto take a `sturct object_id`.\n\nSigned-off-by: Phillip Wood <phillip.wood@dunelm.org.uk>\n---\n builtin/rebase.c   | 21 +++++++++++++--------\n parse-options-cb.c | 17 +++++++++++++++++\n parse-options.h    |  3 +++\n 3 files changed, 33 insertions(+), 8 deletions(-)\n\ndiff --git a/builtin/rebase.c b/builtin/rebase.c\nindex 0584b331bf..c93f2aa629 100644\n--- a/builtin/rebase.c\n+++ b/builtin/rebase.c\n@@ -198,7 +198,7 @@ static int init_basic_state(struct replay_opts *opts, const char *head_name,\n static int do_interactive_rebase(struct replay_opts *opts, unsigned flags,\n \t\t\t\t const char *switch_to, struct commit *upstream,\n \t\t\t\t struct commit *onto, const char *onto_name,\n-\t\t\t\t const char *squash_onto, const char *head_name,\n+\t\t\t\t struct object_id *squash_onto, const char *head_name,\n \t\t\t\t struct commit *restrict_revision, char *raw_strategies,\n \t\t\t\t struct string_list *commands, unsigned autosquash)\n {\n@@ -226,7 +226,8 @@ static int do_interactive_rebase(struct replay_opts *opts, unsigned flags,\n \t}\n \n \tif (!upstream && squash_onto)\n-\t\twrite_file(path_squash_onto(), \"%s\\n\", squash_onto);\n+\t\twrite_file(path_squash_onto(), \"%s\\n\",\n+\t\t\t   oid_to_hex(squash_onto));\n \n \targv_array_pushl(&make_script_args, \"\", revisions, NULL);\n \tif (restrict_revision)\n@@ -267,10 +268,11 @@ int cmd_rebase__interactive(int argc, const char **argv, const char *prefix)\n \tstruct replay_opts opts = REPLAY_OPTS_INIT;\n \tunsigned flags = 0, keep_empty = 0, rebase_merges = 0, autosquash = 0;\n \tint abbreviate_commands = 0, rebase_cousins = -1, ret = 0;\n-\tconst char *onto_name = NULL,\n-\t\t*squash_onto = NULL, *head_name = NULL,\n-\t\t*switch_to = NULL, *cmd = NULL;\n+\tconst char *onto_name = NULL, *head_name = NULL, *switch_to = NULL,\n+\t\t*cmd = NULL;\n \tstruct commit *onto = NULL, *upstream = NULL, *restrict_revision = NULL;\n+\tstruct object_id squash_onto = null_oid;\n+\tstruct object_id *squash_onto_opt = NULL;\n \tstruct string_list commands = STRING_LIST_INIT_DUP;\n \tchar *raw_strategies = NULL;\n \tenum {\n@@ -311,8 +313,8 @@ int cmd_rebase__interactive(int argc, const char **argv, const char *prefix)\n \t\t{ OPTION_CALLBACK, 0, \"restrict-revision\", &restrict_revision,\n \t\t  N_(\"restrict-revision\"), N_(\"restrict revision\"),\n \t\t  PARSE_OPT_NONEG, parse_opt_commit, 0 },\n-\t\tOPT_STRING(0, \"squash-onto\", &squash_onto, N_(\"squash-onto\"),\n-\t\t\t   N_(\"squash onto\")),\n+\t\t{ OPTION_CALLBACK, 0, \"squash-onto\", &squash_onto, N_(\"squash-onto\"),\n+\t\t  N_(\"squash onto\"), PARSE_OPT_NONEG, parse_opt_object_id, 0 },\n \t\t{ OPTION_CALLBACK, 0, \"upstream\", &upstream, N_(\"upstream\"),\n \t\t  N_(\"the upstream commit\"), PARSE_OPT_NONEG, parse_opt_commit,\n \t\t  0 },\n@@ -349,6 +351,9 @@ int cmd_rebase__interactive(int argc, const char **argv, const char *prefix)\n \n \topts.gpg_sign = xstrdup_or_null(opts.gpg_sign);\n \n+\tif (!is_null_oid(&squash_onto))\n+\t\tsquash_onto_opt = &squash_onto;\n+\n \tflags |= keep_empty ? TODO_LIST_KEEP_EMPTY : 0;\n \tflags |= abbreviate_commands ? TODO_LIST_ABBREVIATE_CMDS : 0;\n \tflags |= rebase_merges ? TODO_LIST_REBASE_MERGES : 0;\n@@ -373,7 +378,7 @@ int cmd_rebase__interactive(int argc, const char **argv, const char *prefix)\n \t\t\tdie(_(\"a base commit must be provided with --upstream or --onto\"));\n \n \t\tret = do_interactive_rebase(&opts, flags, switch_to, upstream, onto,\n-\t\t\t\t\t    onto_name, squash_onto, head_name, restrict_revision,\n+\t\t\t\t\t    onto_name, squash_onto_opt, head_name, restrict_revision,\n \t\t\t\t\t    raw_strategies, &commands, autosquash);\n \t\tbreak;\n \tcase SKIP: {\ndiff --git a/parse-options-cb.c b/parse-options-cb.c\nindex 2206eb763c..28ad5cd94b 100644\n--- a/parse-options-cb.c\n+++ b/parse-options-cb.c\n@@ -129,6 +129,23 @@ int parse_opt_object_name(const struct option *opt, const char *arg, int unset)\n \treturn 0;\n }\n \n+int parse_opt_object_id(const struct option *opt, const char *arg, int unset)\n+{\n+\tstruct object_id oid;\n+\tstruct object_id *target = opt->value;\n+\n+\tif (unset) {\n+\t\t*target = null_oid;\n+\t\treturn 0;\n+\t}\n+\tif (!arg)\n+\t\treturn -1;\n+\tif (get_oid(arg, &oid))\n+\t\treturn error(_(\"malformed object name '%s'\"), arg);\n+\t*target = oid;\n+\treturn 0;\n+}\n+\n int parse_opt_tertiary(const struct option *opt, const char *arg, int unset)\n {\n \tint *target = opt->value;\ndiff --git a/parse-options.h b/parse-options.h\nindex 5a75646618..0ab1103bc7 100644\n--- a/parse-options.h\n+++ b/parse-options.h\n@@ -264,7 +264,10 @@ int parse_opt_abbrev_cb(const struct option *, const char *, int);\n int parse_opt_expiry_date_cb(const struct option *, const char *, int);\n int parse_opt_color_flag_cb(const struct option *, const char *, int);\n int parse_opt_verbosity_cb(const struct option *, const char *, int);\n+/* value is struct oid_array* */\n int parse_opt_object_name(const struct option *, const char *, int);\n+/* value is struct object_id* */\n+int parse_opt_object_id(const struct option *, const char *, int);\n int parse_opt_commits(const struct option *, const char *, int);\n int parse_opt_commit(const struct option *, const char *, int);\n int parse_opt_tertiary(const struct option *, const char *, int);\n-- \n2.21.0\n\n"},{"id":"371925","messageId":"20190319190317.6632-9-phillip.wood123@gmail.com","threadId":"50780","inReplyTo":"20190319190317.6632-1-phillip.wood123@gmail.com","subject":"[RFC PATCH 08/11] rebase -i: use struct rebase_options to parse args","fromName":"Phillip Wood","fromEmail":"phillip.wood123@gmail.com","sentAt":"2019-03-19T19:03:14Z","receivedAt":"2019-03-19T19:04:11Z","isPatch":true,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"From: Phillip Wood <phillip.wood@dunelm.org.uk>\n\nIn order to run `rebase -i` without forking `rebase--interactive` it\nwill be convenient to use the same structure when parsing the options in\ncmd_rebase() and cmd_rebase__interactive().\n\nSigned-off-by: Phillip Wood <phillip.wood@dunelm.org.uk>\n---\n builtin/rebase.c | 203 ++++++++++++++++++++++++++---------------------\n 1 file changed, 112 insertions(+), 91 deletions(-)\n\ndiff --git a/builtin/rebase.c b/builtin/rebase.c\nindex c93f2aa629..33a2495032 100644\n--- a/builtin/rebase.c\n+++ b/builtin/rebase.c\n@@ -50,6 +50,73 @@ enum rebase_type {\n \tREBASE_PRESERVE_MERGES\n };\n \n+struct rebase_options {\n+\tenum rebase_type type;\n+\tconst char *state_dir;\n+\tstruct commit *upstream;\n+\tconst char *upstream_name;\n+\tconst char *upstream_arg;\n+\tchar *head_name;\n+\tstruct object_id orig_head;\n+\tstruct commit *onto;\n+\tconst char *onto_name;\n+\tconst char *revisions;\n+\tconst char *switch_to;\n+\tint root;\n+\tstruct object_id *squash_onto;\n+\tstruct commit *restrict_revision;\n+\tint dont_finish_rebase;\n+\tenum {\n+\t\tREBASE_NO_QUIET = 1<<0,\n+\t\tREBASE_VERBOSE = 1<<1,\n+\t\tREBASE_DIFFSTAT = 1<<2,\n+\t\tREBASE_FORCE = 1<<3,\n+\t\tREBASE_INTERACTIVE_EXPLICIT = 1<<4,\n+\t} flags;\n+\tstruct argv_array git_am_opts;\n+\tconst char *action;\n+\tint signoff;\n+\tint allow_rerere_autoupdate;\n+\tint keep_empty;\n+\tint autosquash;\n+\tchar *gpg_sign_opt;\n+\tint autostash;\n+\tchar *cmd;\n+\tint allow_empty_message;\n+\tint rebase_merges, rebase_cousins;\n+\tchar *strategy, *strategy_opts;\n+\tstruct strbuf git_format_patch_opt;\n+\tint reschedule_failed_exec;\n+};\n+\n+#define REBASE_OPTIONS_INIT {\t\t\t  \t\\\n+\t\t.type = REBASE_UNSPECIFIED,\t  \t\\\n+\t\t.flags = REBASE_NO_QUIET, \t\t\\\n+\t\t.git_am_opts = ARGV_ARRAY_INIT,\t\t\\\n+\t\t.git_format_patch_opt = STRBUF_INIT\t\\\n+\t}\n+\n+static struct replay_opts get_replay_opts(const struct rebase_options *opts)\n+{\n+\tstruct replay_opts replay = REPLAY_OPTS_INIT;\n+\n+\tsequencer_init_config(&replay);\n+\n+\treplay.action = REPLAY_INTERACTIVE_REBASE;\n+\treplay.signoff = opts->signoff;\n+\treplay.allow_ff = !(opts->flags & REBASE_FORCE);\n+\tif (opts->allow_rerere_autoupdate)\n+\t\treplay.allow_rerere_auto = opts->allow_rerere_autoupdate;\n+\treplay.allow_empty = 1;\n+\treplay.allow_empty_message = opts->allow_empty_message;\n+\treplay.verbose = opts->flags & REBASE_VERBOSE;\n+\treplay.reschedule_failed_exec = opts->reschedule_failed_exec;\n+\treplay.gpg_sign = xstrdup_or_null(opts->gpg_sign_opt);\n+\treplay.strategy = opts->strategy;\n+\n+\treturn replay;\n+}\n+\n static int add_exec_commands(struct string_list *commands)\n {\n \tconst char *todo_file = rebase_path_todo();\n@@ -265,32 +332,30 @@ static const char * const builtin_rebase_interactive_usage[] = {\n \n int cmd_rebase__interactive(int argc, const char **argv, const char *prefix)\n {\n-\tstruct replay_opts opts = REPLAY_OPTS_INIT;\n-\tunsigned flags = 0, keep_empty = 0, rebase_merges = 0, autosquash = 0;\n-\tint abbreviate_commands = 0, rebase_cousins = -1, ret = 0;\n-\tconst char *onto_name = NULL, *head_name = NULL, *switch_to = NULL,\n-\t\t*cmd = NULL;\n-\tstruct commit *onto = NULL, *upstream = NULL, *restrict_revision = NULL;\n+\tstruct rebase_options opts = REBASE_OPTIONS_INIT;\n+\tunsigned flags = 0;\n+\tint abbreviate_commands = 0, ret = 0;\n \tstruct object_id squash_onto = null_oid;\n-\tstruct object_id *squash_onto_opt = NULL;\n \tstruct string_list commands = STRING_LIST_INIT_DUP;\n-\tchar *raw_strategies = NULL;\n \tenum {\n \t\tNONE = 0, CONTINUE, SKIP, EDIT_TODO, SHOW_CURRENT_PATCH,\n \t\tSHORTEN_OIDS, EXPAND_OIDS, CHECK_TODO_LIST, REARRANGE_SQUASH, ADD_EXEC\n \t} command = 0;\n \tstruct option options[] = {\n-\t\tOPT_BOOL(0, \"ff\", &opts.allow_ff, N_(\"allow fast-forward\")),\n-\t\tOPT_BOOL(0, \"keep-empty\", &keep_empty, N_(\"keep empty commits\")),\n+\t\tOPT_NEGBIT(0, \"ff\", &opts.flags, N_(\"allow fast-forward\"),\n+\t\t\t   REBASE_FORCE),\n+\t\tOPT_BOOL(0, \"keep-empty\", &opts.keep_empty, N_(\"keep empty commits\")),\n \t\tOPT_BOOL(0, \"allow-empty-message\", &opts.allow_empty_message,\n \t\t\t N_(\"allow commits with empty messages\")),\n-\t\tOPT_BOOL(0, \"rebase-merges\", &rebase_merges, N_(\"rebase merge commits\")),\n-\t\tOPT_BOOL(0, \"rebase-cousins\", &rebase_cousins,\n+\t\tOPT_BOOL(0, \"rebase-merges\", &opts.rebase_merges, N_(\"rebase merge commits\")),\n+\t\tOPT_BOOL(0, \"rebase-cousins\", &opts.rebase_cousins,\n \t\t\t N_(\"keep original branch points of cousins\")),\n-\t\tOPT_BOOL(0, \"autosquash\", &autosquash,\n+\t\tOPT_BOOL(0, \"autosquash\", &opts.autosquash,\n \t\t\t N_(\"move commits that begin with squash!/fixup!\")),\n \t\tOPT_BOOL(0, \"signoff\", &opts.signoff, N_(\"sign commits\")),\n-\t\tOPT__VERBOSE(&opts.verbose, N_(\"be verbose\")),\n+\t\tOPT_BIT('v', \"verbose\", &opts.flags,\n+\t\t\tN_(\"display a diffstat of what changed upstream\"),\n+\t\t\tREBASE_NO_QUIET | REBASE_VERBOSE | REBASE_DIFFSTAT),\n \t\tOPT_CMDMODE(0, \"continue\", &command, N_(\"continue rebase\"),\n \t\t\t    CONTINUE),\n \t\tOPT_CMDMODE(0, \"skip\", &command, N_(\"skip commit\"), SKIP),\n@@ -308,86 +373,86 @@ int cmd_rebase__interactive(int argc, const char **argv, const char *prefix)\n \t\t\tN_(\"rearrange fixup/squash lines\"), REARRANGE_SQUASH),\n \t\tOPT_CMDMODE(0, \"add-exec-commands\", &command,\n \t\t\tN_(\"insert exec commands in todo list\"), ADD_EXEC),\n-\t\t{ OPTION_CALLBACK, 0, \"onto\", &onto, N_(\"onto\"), N_(\"onto\"),\n+\t\t{ OPTION_CALLBACK, 0, \"onto\", &opts.onto, N_(\"onto\"), N_(\"onto\"),\n \t\t  PARSE_OPT_NONEG, parse_opt_commit, 0 },\n-\t\t{ OPTION_CALLBACK, 0, \"restrict-revision\", &restrict_revision,\n+\t\t{ OPTION_CALLBACK, 0, \"restrict-revision\", &opts.restrict_revision,\n \t\t  N_(\"restrict-revision\"), N_(\"restrict revision\"),\n \t\t  PARSE_OPT_NONEG, parse_opt_commit, 0 },\n \t\t{ OPTION_CALLBACK, 0, \"squash-onto\", &squash_onto, N_(\"squash-onto\"),\n \t\t  N_(\"squash onto\"), PARSE_OPT_NONEG, parse_opt_object_id, 0 },\n-\t\t{ OPTION_CALLBACK, 0, \"upstream\", &upstream, N_(\"upstream\"),\n+\t\t{ OPTION_CALLBACK, 0, \"upstream\", &opts.upstream, N_(\"upstream\"),\n \t\t  N_(\"the upstream commit\"), PARSE_OPT_NONEG, parse_opt_commit,\n \t\t  0 },\n-\t\tOPT_STRING(0, \"head-name\", &head_name, N_(\"head-name\"), N_(\"head name\")),\n-\t\t{ OPTION_STRING, 'S', \"gpg-sign\", &opts.gpg_sign, N_(\"key-id\"),\n+\t\tOPT_STRING(0, \"head-name\", &opts.head_name, N_(\"head-name\"), N_(\"head name\")),\n+\t\t{ OPTION_STRING, 'S', \"gpg-sign\", &opts.gpg_sign_opt, N_(\"key-id\"),\n \t\t\tN_(\"GPG-sign commits\"),\n \t\t\tPARSE_OPT_OPTARG, NULL, (intptr_t) \"\" },\n \t\tOPT_STRING(0, \"strategy\", &opts.strategy, N_(\"strategy\"),\n \t\t\t   N_(\"rebase strategy\")),\n-\t\tOPT_STRING(0, \"strategy-opts\", &raw_strategies, N_(\"strategy-opts\"),\n+\t\tOPT_STRING(0, \"strategy-opts\", &opts.strategy_opts, N_(\"strategy-opts\"),\n \t\t\t   N_(\"strategy options\")),\n-\t\tOPT_STRING(0, \"switch-to\", &switch_to, N_(\"switch-to\"),\n+\t\tOPT_STRING(0, \"switch-to\", &opts.switch_to, N_(\"switch-to\"),\n \t\t\t   N_(\"the branch or commit to checkout\")),\n-\t\tOPT_STRING(0, \"onto-name\", &onto_name, N_(\"onto-name\"), N_(\"onto name\")),\n-\t\tOPT_STRING(0, \"cmd\", &cmd, N_(\"cmd\"), N_(\"the command to run\")),\n-\t\tOPT_RERERE_AUTOUPDATE(&opts.allow_rerere_auto),\n+\t\tOPT_STRING(0, \"onto-name\", &opts.onto_name, N_(\"onto-name\"), N_(\"onto name\")),\n+\t\tOPT_STRING(0, \"cmd\", &opts.cmd, N_(\"cmd\"), N_(\"the command to run\")),\n+\t\tOPT_RERERE_AUTOUPDATE(&opts.allow_rerere_autoupdate),\n \t\tOPT_BOOL(0, \"reschedule-failed-exec\", &opts.reschedule_failed_exec,\n \t\t\t N_(\"automatically re-schedule any `exec` that fails\")),\n \t\tOPT_END()\n \t};\n \n-\tsequencer_init_config(&opts);\n+\topts.rebase_cousins = -1;\n+\n \tgit_config_get_bool(\"rebase.abbreviatecommands\", &abbreviate_commands);\n \n-\topts.action = REPLAY_INTERACTIVE_REBASE;\n-\topts.allow_ff = 1;\n-\topts.allow_empty = 1;\n-\n \tif (argc == 1)\n \t\tusage_with_options(builtin_rebase_interactive_usage, options);\n \n \targc = parse_options(argc, argv, NULL, options,\n \t\t\tbuiltin_rebase_interactive_usage, PARSE_OPT_KEEP_ARGV0);\n \n-\topts.gpg_sign = xstrdup_or_null(opts.gpg_sign);\n-\n \tif (!is_null_oid(&squash_onto))\n-\t\tsquash_onto_opt = &squash_onto;\n+\t\topts.squash_onto = &squash_onto;\n \n-\tflags |= keep_empty ? TODO_LIST_KEEP_EMPTY : 0;\n+\tflags |= opts.keep_empty ? TODO_LIST_KEEP_EMPTY : 0;\n \tflags |= abbreviate_commands ? TODO_LIST_ABBREVIATE_CMDS : 0;\n-\tflags |= rebase_merges ? TODO_LIST_REBASE_MERGES : 0;\n-\tflags |= rebase_cousins > 0 ? TODO_LIST_REBASE_COUSINS : 0;\n+\tflags |= opts.rebase_merges ? TODO_LIST_REBASE_MERGES : 0;\n+\tflags |= opts.rebase_cousins > 0 ? TODO_LIST_REBASE_COUSINS : 0;\n \tflags |= command == SHORTEN_OIDS ? TODO_LIST_SHORTEN_IDS : 0;\n \n-\tif (rebase_cousins >= 0 && !rebase_merges)\n+\tif (opts.rebase_cousins >= 0 && !opts.rebase_merges)\n \t\twarning(_(\"--[no-]rebase-cousins has no effect without \"\n \t\t\t  \"--rebase-merges\"));\n \n-\tif (cmd && *cmd) {\n-\t\tstring_list_split(&commands, cmd, '\\n', -1);\n+\tif (opts.cmd && *opts.cmd) {\n+\t\tstring_list_split(&commands, opts.cmd, '\\n', -1);\n \n \t\t/* rebase.c adds a new line to cmd after every command,\n \t\t * so here the last command is always empty */\n \t\tstring_list_remove_empty_items(&commands, 0);\n \t}\n \n \tswitch (command) {\n-\tcase NONE:\n-\t\tif (!onto && !upstream)\n+\tcase NONE: {\n+\t\tstruct replay_opts replay_opts = get_replay_opts(&opts);\n+\t\tif (!opts.onto && !opts.upstream)\n \t\t\tdie(_(\"a base commit must be provided with --upstream or --onto\"));\n \n-\t\tret = do_interactive_rebase(&opts, flags, switch_to, upstream, onto,\n-\t\t\t\t\t    onto_name, squash_onto_opt, head_name, restrict_revision,\n-\t\t\t\t\t    raw_strategies, &commands, autosquash);\n+\t\tret = do_interactive_rebase(&replay_opts, flags, opts.switch_to, opts.upstream, opts.onto,\n+\t\t\t\t\t    opts.onto_name, opts.squash_onto, opts.head_name, opts.restrict_revision,\n+\t\t\t\t\t    opts.strategy_opts, &commands, opts.autosquash);\n \t\tbreak;\n+\t}\n \tcase SKIP: {\n \t\tstruct string_list merge_rr = STRING_LIST_INIT_DUP;\n \n \t\trerere_clear(the_repository, &merge_rr);\n+\t}\n \t\t/* fallthrough */\n-\tcase CONTINUE:\n-\t\tret = sequencer_continue(the_repository, &opts);\n+\tcase CONTINUE: {\n+\t\tstruct replay_opts replay_opts = get_replay_opts(&opts);\n+\n+\t\tret = sequencer_continue(the_repository, &replay_opts);\n \t\tbreak;\n \t}\n \tcase EDIT_TODO:\n@@ -446,45 +511,6 @@ static int use_builtin_rebase(void)\n \treturn ret;\n }\n \n-struct rebase_options {\n-\tenum rebase_type type;\n-\tconst char *state_dir;\n-\tstruct commit *upstream;\n-\tconst char *upstream_name;\n-\tconst char *upstream_arg;\n-\tchar *head_name;\n-\tstruct object_id orig_head;\n-\tstruct commit *onto;\n-\tconst char *onto_name;\n-\tconst char *revisions;\n-\tconst char *switch_to;\n-\tint root;\n-\tstruct object_id *squash_onto;\n-\tstruct commit *restrict_revision;\n-\tint dont_finish_rebase;\n-\tenum {\n-\t\tREBASE_NO_QUIET = 1<<0,\n-\t\tREBASE_VERBOSE = 1<<1,\n-\t\tREBASE_DIFFSTAT = 1<<2,\n-\t\tREBASE_FORCE = 1<<3,\n-\t\tREBASE_INTERACTIVE_EXPLICIT = 1<<4,\n-\t} flags;\n-\tstruct argv_array git_am_opts;\n-\tconst char *action;\n-\tint signoff;\n-\tint allow_rerere_autoupdate;\n-\tint keep_empty;\n-\tint autosquash;\n-\tchar *gpg_sign_opt;\n-\tint autostash;\n-\tchar *cmd;\n-\tint allow_empty_message;\n-\tint rebase_merges, rebase_cousins;\n-\tchar *strategy, *strategy_opts;\n-\tstruct strbuf git_format_patch_opt;\n-\tint reschedule_failed_exec;\n-};\n-\n static int is_interactive(struct rebase_options *opts)\n {\n \treturn opts->type == REBASE_INTERACTIVE ||\n@@ -1380,13 +1406,7 @@ static int check_exec_cmd(const char *cmd)\n \n int cmd_rebase(int argc, const char **argv, const char *prefix)\n {\n-\tstruct rebase_options options = {\n-\t\t.type = REBASE_UNSPECIFIED,\n-\t\t.flags = REBASE_NO_QUIET,\n-\t\t.git_am_opts = ARGV_ARRAY_INIT,\n-\t\t.allow_empty_message = 1,\n-\t\t.git_format_patch_opt = STRBUF_INIT,\n-\t};\n+\tstruct rebase_options options = REBASE_OPTIONS_INIT;\n \tconst char *branch_name;\n \tint ret, flags, total_argc, in_progress = 0;\n \tint ok_to_skip_pre_rebase = 0;\n@@ -1540,6 +1560,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \ttrace_repo_setup(prefix);\n \tsetup_work_tree();\n \n+\toptions.allow_empty_message = 1;\n \tgit_config(rebase_config, &options);\n \n \tstrbuf_reset(&buf);\n-- \n2.21.0\n\n"},{"id":"371926","messageId":"20190319190317.6632-11-phillip.wood123@gmail.com","threadId":"50780","inReplyTo":"20190319190317.6632-1-phillip.wood123@gmail.com","subject":"[RFC PATCH 10/11] rebase: use a common action enum","fromName":"Phillip Wood","fromEmail":"phillip.wood123@gmail.com","sentAt":"2019-03-19T19:03:16Z","receivedAt":"2019-03-19T19:04:11Z","isPatch":true,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"From: Phillip Wood <phillip.wood@dunelm.org.uk>\n\ncmd_rebase() and cmd_rebase__interactive() used different enums to hold\nthe current action. Change to using a common enum so the values are the\nsame when we change `rebase -i` to avoid forking `rebase--interactive`.\n\nSigned-off-by: Phillip Wood <phillip.wood@dunelm.org.uk>\n---\n\nNotes:\n    I'm not sure what to do with action_names, I moved it to keep it near\n    the definition of the enum. The extra commands in the enum are not\n    traced so they don't need to be in action_names but it looks odd to\n    leave them out. Also I don't understand why action_names in NULL\n    terminated or the names are marked for translation as it is used in\n    \ttrace2_cmd_mode(action_names[action]);\n    so we don't use the NULL termination or translate the names (I'd be\n    surprised if we did for tracing)\n\n builtin/rebase.c | 93 +++++++++++++++++++++++++-----------------------\n 1 file changed, 49 insertions(+), 44 deletions(-)\n\ndiff --git a/builtin/rebase.c b/builtin/rebase.c\nindex 21ccb6495e..26d25a5242 100644\n--- a/builtin/rebase.c\n+++ b/builtin/rebase.c\n@@ -119,6 +119,30 @@ static struct replay_opts get_replay_opts(const struct rebase_options *opts)\n \treturn replay;\n }\n \n+enum action {\n+\tACTION_NONE = 0,\n+\tACTION_CONTINUE,\n+\tACTION_SKIP,\n+\tACTION_ABORT,\n+\tACTION_QUIT,\n+\tACTION_EDIT_TODO,\n+\tACTION_SHOW_CURRENT_PATCH,\n+\tACTION_SHORTEN_OIDS,\n+\tACTION_EXPAND_OIDS,\n+\tACTION_CHECK_TODO_LIST,\n+\tACTION_REARRANGE_SQUASH,\n+\tACTION_ADD_EXEC\n+};\n+\n+static const char *action_names[] = { N_(\"undefined\"),\n+\t\t\t\t      N_(\"continue\"),\n+\t\t\t\t      N_(\"skip\"),\n+\t\t\t\t      N_(\"abort\"),\n+\t\t\t\t      N_(\"quit\"),\n+\t\t\t\t      N_(\"edit_todo\"),\n+\t\t\t\t      N_(\"show_current_patch\"),\n+\t\t\t\t      NULL };\n+\n static int add_exec_commands(struct string_list *commands)\n {\n \tconst char *todo_file = rebase_path_todo();\n@@ -347,10 +371,7 @@ int cmd_rebase__interactive(int argc, const char **argv, const char *prefix)\n \tunsigned flags = 0;\n \tint abbreviate_commands = 0, ret = 0;\n \tstruct object_id squash_onto = null_oid;\n-\tenum {\n-\t\tNONE = 0, CONTINUE, SKIP, EDIT_TODO, SHOW_CURRENT_PATCH,\n-\t\tSHORTEN_OIDS, EXPAND_OIDS, CHECK_TODO_LIST, REARRANGE_SQUASH, ADD_EXEC\n-\t} command = 0;\n+\tenum action command = ACTION_NONE;\n \tstruct option options[] = {\n \t\tOPT_NEGBIT(0, \"ff\", &opts.flags, N_(\"allow fast-forward\"),\n \t\t\t   REBASE_FORCE),\n@@ -367,22 +388,22 @@ int cmd_rebase__interactive(int argc, const char **argv, const char *prefix)\n \t\t\tN_(\"display a diffstat of what changed upstream\"),\n \t\t\tREBASE_NO_QUIET | REBASE_VERBOSE | REBASE_DIFFSTAT),\n \t\tOPT_CMDMODE(0, \"continue\", &command, N_(\"continue rebase\"),\n-\t\t\t    CONTINUE),\n-\t\tOPT_CMDMODE(0, \"skip\", &command, N_(\"skip commit\"), SKIP),\n+\t\t\t    ACTION_CONTINUE),\n+\t\tOPT_CMDMODE(0, \"skip\", &command, N_(\"skip commit\"), ACTION_SKIP),\n \t\tOPT_CMDMODE(0, \"edit-todo\", &command, N_(\"edit the todo list\"),\n-\t\t\t    EDIT_TODO),\n+\t\t\t    ACTION_EDIT_TODO),\n \t\tOPT_CMDMODE(0, \"show-current-patch\", &command, N_(\"show the current patch\"),\n-\t\t\t    SHOW_CURRENT_PATCH),\n+\t\t\t    ACTION_SHOW_CURRENT_PATCH),\n \t\tOPT_CMDMODE(0, \"shorten-ids\", &command,\n-\t\t\tN_(\"shorten commit ids in the todo list\"), SHORTEN_OIDS),\n+\t\t\tN_(\"shorten commit ids in the todo list\"), ACTION_SHORTEN_OIDS),\n \t\tOPT_CMDMODE(0, \"expand-ids\", &command,\n-\t\t\tN_(\"expand commit ids in the todo list\"), EXPAND_OIDS),\n+\t\t\tN_(\"expand commit ids in the todo list\"), ACTION_EXPAND_OIDS),\n \t\tOPT_CMDMODE(0, \"check-todo-list\", &command,\n-\t\t\tN_(\"check the todo list\"), CHECK_TODO_LIST),\n+\t\t\tN_(\"check the todo list\"), ACTION_CHECK_TODO_LIST),\n \t\tOPT_CMDMODE(0, \"rearrange-squash\", &command,\n-\t\t\tN_(\"rearrange fixup/squash lines\"), REARRANGE_SQUASH),\n+\t\t\tN_(\"rearrange fixup/squash lines\"), ACTION_REARRANGE_SQUASH),\n \t\tOPT_CMDMODE(0, \"add-exec-commands\", &command,\n-\t\t\tN_(\"insert exec commands in todo list\"), ADD_EXEC),\n+\t\t\tN_(\"insert exec commands in todo list\"), ACTION_ADD_EXEC),\n \t\t{ OPTION_CALLBACK, 0, \"onto\", &opts.onto, N_(\"onto\"), N_(\"onto\"),\n \t\t  PARSE_OPT_NONEG, parse_opt_commit, 0 },\n \t\t{ OPTION_CALLBACK, 0, \"restrict-revision\", &opts.restrict_revision,\n@@ -428,36 +449,36 @@ int cmd_rebase__interactive(int argc, const char **argv, const char *prefix)\n \tflags |= abbreviate_commands ? TODO_LIST_ABBREVIATE_CMDS : 0;\n \tflags |= opts.rebase_merges ? TODO_LIST_REBASE_MERGES : 0;\n \tflags |= opts.rebase_cousins > 0 ? TODO_LIST_REBASE_COUSINS : 0;\n-\tflags |= command == SHORTEN_OIDS ? TODO_LIST_SHORTEN_IDS : 0;\n+\tflags |= command == ACTION_SHORTEN_OIDS ? TODO_LIST_SHORTEN_IDS : 0;\n \n \tif (opts.rebase_cousins >= 0 && !opts.rebase_merges)\n \t\twarning(_(\"--[no-]rebase-cousins has no effect without \"\n \t\t\t  \"--rebase-merges\"));\n \n \tswitch (command) {\n-\tcase NONE: {\n+\tcase ACTION_NONE: {\n \t\tif (!opts.onto && !opts.upstream)\n \t\t\tdie(_(\"a base commit must be provided with --upstream or --onto\"));\n \n \t\tret = do_interactive_rebase(&opts, flags);\n \t\tbreak;\n \t}\n-\tcase SKIP: {\n+\tcase ACTION_SKIP: {\n \t\tstruct string_list merge_rr = STRING_LIST_INIT_DUP;\n \n \t\trerere_clear(the_repository, &merge_rr);\n \t}\n \t\t/* fallthrough */\n-\tcase CONTINUE: {\n+\tcase ACTION_CONTINUE: {\n \t\tstruct replay_opts replay_opts = get_replay_opts(&opts);\n \n \t\tret = sequencer_continue(the_repository, &replay_opts);\n \t\tbreak;\n \t}\n-\tcase EDIT_TODO:\n+\tcase ACTION_EDIT_TODO:\n \t\tret = edit_todo_file(flags);\n \t\tbreak;\n-\tcase SHOW_CURRENT_PATCH: {\n+\tcase ACTION_SHOW_CURRENT_PATCH: {\n \t\tstruct child_process cmd = CHILD_PROCESS_INIT;\n \n \t\tcmd.git_cmd = 1;\n@@ -466,17 +487,17 @@ int cmd_rebase__interactive(int argc, const char **argv, const char *prefix)\n \n \t\tbreak;\n \t}\n-\tcase SHORTEN_OIDS:\n-\tcase EXPAND_OIDS:\n+\tcase ACTION_SHORTEN_OIDS:\n+\tcase ACTION_EXPAND_OIDS:\n \t\tret = transform_todo_file(flags);\n \t\tbreak;\n-\tcase CHECK_TODO_LIST:\n+\tcase ACTION_CHECK_TODO_LIST:\n \t\tret = check_todo_list_from_file(the_repository);\n \t\tbreak;\n-\tcase REARRANGE_SQUASH:\n+\tcase ACTION_REARRANGE_SQUASH:\n \t\tret = rearrange_squash_in_todo_file();\n \t\tbreak;\n-\tcase ADD_EXEC: {\n+\tcase ACTION_ADD_EXEC: {\n \t\tstruct string_list commands = STRING_LIST_INIT_DUP;\n \n \t\tsplit_exec_commands(opts.cmd, &commands);\n@@ -1417,23 +1438,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \tstruct strbuf revisions = STRBUF_INIT;\n \tstruct strbuf buf = STRBUF_INIT;\n \tstruct object_id merge_base;\n-\tenum {\n-\t\tNO_ACTION,\n-\t\tACTION_CONTINUE,\n-\t\tACTION_SKIP,\n-\t\tACTION_ABORT,\n-\t\tACTION_QUIT,\n-\t\tACTION_EDIT_TODO,\n-\t\tACTION_SHOW_CURRENT_PATCH,\n-\t} action = NO_ACTION;\n-\tstatic const char *action_names[] = { N_(\"undefined\"),\n-\t\t\t\t\t      N_(\"continue\"),\n-\t\t\t\t\t      N_(\"skip\"),\n-\t\t\t\t\t      N_(\"abort\"),\n-\t\t\t\t\t      N_(\"quit\"),\n-\t\t\t\t\t      N_(\"edit_todo\"),\n-\t\t\t\t\t      N_(\"show_current_patch\"),\n-\t\t\t\t\t      NULL };\n+\tenum action action = ACTION_NONE;\n \tconst char *gpg_sign = NULL;\n \tstruct string_list exec = STRING_LIST_INIT_NODUP;\n \tconst char *rebase_merges = NULL;\n@@ -1600,7 +1605,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \t\t\t     builtin_rebase_options,\n \t\t\t     builtin_rebase_usage, 0);\n \n-\tif (action != NO_ACTION && total_argc != 2) {\n+\tif (action != ACTION_NONE && total_argc != 2) {\n \t\tusage_with_options(builtin_rebase_usage,\n \t\t\t\t   builtin_rebase_options);\n \t}\n@@ -1609,7 +1614,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \t\tusage_with_options(builtin_rebase_usage,\n \t\t\t\t   builtin_rebase_options);\n \n-\tif (action != NO_ACTION && !in_progress)\n+\tif (action != ACTION_NONE && !in_progress)\n \t\tdie(_(\"No rebase in progress?\"));\n \tsetenv(GIT_REFLOG_ACTION_ENVIRONMENT, \"rebase\", 0);\n \n@@ -1709,7 +1714,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \t\toptions.action = \"show-current-patch\";\n \t\toptions.dont_finish_rebase = 1;\n \t\tgoto run_rebase;\n-\tcase NO_ACTION:\n+\tcase ACTION_NONE:\n \t\tbreak;\n \tdefault:\n \t\tBUG(\"action: %d\", action);\n-- \n2.21.0\n\n"},{"id":"371927","messageId":"20190319190317.6632-10-phillip.wood123@gmail.com","threadId":"50780","inReplyTo":"20190319190317.6632-1-phillip.wood123@gmail.com","subject":"[RFC PATCH 09/11] rebase -i: use struct rebase_options in do_interactive_rebase()","fromName":"Phillip Wood","fromEmail":"phillip.wood123@gmail.com","sentAt":"2019-03-19T19:03:15Z","receivedAt":"2019-03-19T19:04:13Z","isPatch":true,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"From: Phillip Wood <phillip.wood@dunelm.org.uk>\n\nAll the parameters that are passed to do_interactive_rebase() apart from\n`flags` are already in `struct rebase_options` so there is no need to\npass them separately.\n\nSigned-off-by: Phillip Wood <phillip.wood@dunelm.org.uk>\n---\n builtin/rebase.c | 69 +++++++++++++++++++++++++-----------------------\n 1 file changed, 36 insertions(+), 33 deletions(-)\n\ndiff --git a/builtin/rebase.c b/builtin/rebase.c\nindex 33a2495032..21ccb6495e 100644\n--- a/builtin/rebase.c\n+++ b/builtin/rebase.c\n@@ -113,6 +113,8 @@ static struct replay_opts get_replay_opts(const struct rebase_options *opts)\n \treplay.reschedule_failed_exec = opts->reschedule_failed_exec;\n \treplay.gpg_sign = xstrdup_or_null(opts->gpg_sign_opt);\n \treplay.strategy = opts->strategy;\n+\tif (opts->strategy_opts)\n+\t\tparse_strategy_opts(&replay, opts->strategy_opts);\n \n \treturn replay;\n }\n@@ -262,44 +264,50 @@ static int init_basic_state(struct replay_opts *opts, const char *head_name,\n \treturn write_basic_state(opts, head_name, onto, orig_head);\n }\n \n-static int do_interactive_rebase(struct replay_opts *opts, unsigned flags,\n-\t\t\t\t const char *switch_to, struct commit *upstream,\n-\t\t\t\t struct commit *onto, const char *onto_name,\n-\t\t\t\t struct object_id *squash_onto, const char *head_name,\n-\t\t\t\t struct commit *restrict_revision, char *raw_strategies,\n-\t\t\t\t struct string_list *commands, unsigned autosquash)\n+static void split_exec_commands(const char *cmd, struct string_list *commands)\n+{\n+\tif (cmd && *cmd) {\n+\t\tstring_list_split(commands, cmd, '\\n', -1);\n+\n+\t\t/* rebase.c adds a new line to cmd after every command,\n+\t\t * so here the last command is always empty */\n+\t\tstring_list_remove_empty_items(commands, 0);\n+\t}\n+}\n+\n+static int do_interactive_rebase(struct rebase_options *opts, unsigned flags)\n {\n \tint ret;\n \tconst char *head_hash = NULL;\n \tchar *revisions = NULL, *shortrevisions = NULL;\n \tstruct argv_array make_script_args = ARGV_ARRAY_INIT;\n \tstruct todo_list todo_list = TODO_LIST_INIT;\n+\tstruct replay_opts replay = get_replay_opts(opts);\n+\tstruct string_list commands = STRING_LIST_INIT_DUP;\n \n-\tif (prepare_branch_to_be_rebased(the_repository, opts, switch_to))\n+\tif (prepare_branch_to_be_rebased(the_repository, &replay,\n+\t\t\t\t\t opts->switch_to))\n \t\treturn -1;\n \n-\tif (get_revision_ranges(upstream, onto, &head_hash,\n+\tif (get_revision_ranges(opts->upstream, opts->onto, &head_hash,\n \t\t\t\t&revisions, &shortrevisions))\n \t\treturn -1;\n \n-\tif (raw_strategies)\n-\t\tparse_strategy_opts(opts, raw_strategies);\n-\n-\tif (init_basic_state(opts, head_name, onto, head_hash)) {\n+\tif (init_basic_state(&replay, opts->head_name, opts->onto, head_hash)) {\n \t\tfree(revisions);\n \t\tfree(shortrevisions);\n \n \t\treturn -1;\n \t}\n \n-\tif (!upstream && squash_onto)\n+\tif (!opts->upstream && opts->squash_onto)\n \t\twrite_file(path_squash_onto(), \"%s\\n\",\n-\t\t\t   oid_to_hex(squash_onto));\n+\t\t\t   oid_to_hex(opts->squash_onto));\n \n \targv_array_pushl(&make_script_args, \"\", revisions, NULL);\n-\tif (restrict_revision)\n+\tif (opts->restrict_revision)\n \t\targv_array_push(&make_script_args,\n-\t\t\t\toid_to_hex(&restrict_revision->object.oid));\n+\t\t\t\toid_to_hex(&opts->restrict_revision->object.oid));\n \n \tret = sequencer_make_script(the_repository, &todo_list.buf,\n \t\t\t\t    make_script_args.argc, make_script_args.argv,\n@@ -313,10 +321,13 @@ static int do_interactive_rebase(struct replay_opts *opts, unsigned flags,\n \t\t\t\t\t\t&todo_list))\n \t\t\tBUG(\"unusable todo list\");\n \n-\t\tret = complete_action(the_repository, opts, flags, shortrevisions, onto_name,\n-\t\t\t\t      onto, head_hash, commands, autosquash, &todo_list);\n+\t\tsplit_exec_commands(opts->cmd, &commands);\n+\t\tret = complete_action(the_repository, &replay, flags,\n+\t\t\tshortrevisions, opts->onto_name, opts->onto, head_hash,\n+\t\t\t&commands, opts->autosquash, &todo_list);\n \t}\n \n+\tstring_list_clear(&commands, 0);\n \tfree(revisions);\n \tfree(shortrevisions);\n \ttodo_list_release(&todo_list);\n@@ -336,7 +347,6 @@ int cmd_rebase__interactive(int argc, const char **argv, const char *prefix)\n \tunsigned flags = 0;\n \tint abbreviate_commands = 0, ret = 0;\n \tstruct object_id squash_onto = null_oid;\n-\tstruct string_list commands = STRING_LIST_INIT_DUP;\n \tenum {\n \t\tNONE = 0, CONTINUE, SKIP, EDIT_TODO, SHOW_CURRENT_PATCH,\n \t\tSHORTEN_OIDS, EXPAND_OIDS, CHECK_TODO_LIST, REARRANGE_SQUASH, ADD_EXEC\n@@ -424,23 +434,12 @@ int cmd_rebase__interactive(int argc, const char **argv, const char *prefix)\n \t\twarning(_(\"--[no-]rebase-cousins has no effect without \"\n \t\t\t  \"--rebase-merges\"));\n \n-\tif (opts.cmd && *opts.cmd) {\n-\t\tstring_list_split(&commands, opts.cmd, '\\n', -1);\n-\n-\t\t/* rebase.c adds a new line to cmd after every command,\n-\t\t * so here the last command is always empty */\n-\t\tstring_list_remove_empty_items(&commands, 0);\n-\t}\n-\n \tswitch (command) {\n \tcase NONE: {\n-\t\tstruct replay_opts replay_opts = get_replay_opts(&opts);\n \t\tif (!opts.onto && !opts.upstream)\n \t\t\tdie(_(\"a base commit must be provided with --upstream or --onto\"));\n \n-\t\tret = do_interactive_rebase(&replay_opts, flags, opts.switch_to, opts.upstream, opts.onto,\n-\t\t\t\t\t    opts.onto_name, opts.squash_onto, opts.head_name, opts.restrict_revision,\n-\t\t\t\t\t    opts.strategy_opts, &commands, opts.autosquash);\n+\t\tret = do_interactive_rebase(&opts, flags);\n \t\tbreak;\n \t}\n \tcase SKIP: {\n@@ -477,14 +476,18 @@ int cmd_rebase__interactive(int argc, const char **argv, const char *prefix)\n \tcase REARRANGE_SQUASH:\n \t\tret = rearrange_squash_in_todo_file();\n \t\tbreak;\n-\tcase ADD_EXEC:\n+\tcase ADD_EXEC: {\n+\t\tstruct string_list commands = STRING_LIST_INIT_DUP;\n+\n+\t\tsplit_exec_commands(opts.cmd, &commands);\n \t\tret = add_exec_commands(&commands);\n+\t\tstring_list_clear(&commands, 0);\n \t\tbreak;\n+\t}\n \tdefault:\n \t\tBUG(\"invalid command '%d'\", command);\n \t}\n \n-\tstring_list_clear(&commands, 0);\n \treturn !!ret;\n }\n \n-- \n2.21.0\n\n"},{"id":"371928","messageId":"20190319190317.6632-12-phillip.wood123@gmail.com","threadId":"50780","inReplyTo":"20190319190317.6632-1-phillip.wood123@gmail.com","subject":"[RFC PATCH 11/11] rebase -i: run without forking rebase--interactive","fromName":"Phillip Wood","fromEmail":"phillip.wood123@gmail.com","sentAt":"2019-03-19T19:03:17Z","receivedAt":"2019-03-19T19:04:15Z","isPatch":true,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"From: Phillip Wood <phillip.wood@dunelm.org.uk>\n\nWhen the builtin rebase starts an interactive rebase it parses the\noptions and then repackages them and forks\n`rebase--interactive`. Separate the option parsing in\ncmd_rebase__interactive() from the business logic to allow interactive\nrebases can be run without forking `rebase__interactive` by calling\nrun_rebase_interactive() directly. This makes it easy to debug the\nsequencer without worrying about attaching to child processes. It also\nmakes it easy to remove cmd_rebase__interactive() in the future when\ngit-legacy-rebase.sh and git-rebase--preserve-merges.sh are retired.\n\nSigned-off-by: Phillip Wood <phillip.wood@dunelm.org.uk>\n---\n builtin/rebase.c | 221 ++++++++++++++++++-----------------------------\n 1 file changed, 86 insertions(+), 135 deletions(-)\n\ndiff --git a/builtin/rebase.c b/builtin/rebase.c\nindex 26d25a5242..2e26d350f0 100644\n--- a/builtin/rebase.c\n+++ b/builtin/rebase.c\n@@ -317,7 +317,9 @@ static int do_interactive_rebase(struct rebase_options *opts, unsigned flags)\n \t\t\t\t&revisions, &shortrevisions))\n \t\treturn -1;\n \n-\tif (init_basic_state(&replay, opts->head_name, opts->onto, head_hash)) {\n+\tif (init_basic_state(&replay,\n+\t\t\t     opts->head_name ? opts->head_name : \"detached HEAD\",\n+\t\t\t     opts->onto, head_hash)) {\n \t\tfree(revisions);\n \t\tfree(shortrevisions);\n \n@@ -360,6 +362,77 @@ static int do_interactive_rebase(struct rebase_options *opts, unsigned flags)\n \treturn ret;\n }\n \n+static int run_rebase_interactive(struct rebase_options *opts,\n+\t\t\t\t  enum action command)\n+{\n+\tunsigned flags = 0;\n+\tint abbreviate_commands = 0, ret = 0;\n+\n+\tgit_config_get_bool(\"rebase.abbreviatecommands\", &abbreviate_commands);\n+\n+\tflags |= opts->keep_empty ? TODO_LIST_KEEP_EMPTY : 0;\n+\tflags |= abbreviate_commands ? TODO_LIST_ABBREVIATE_CMDS : 0;\n+\tflags |= opts->rebase_merges ? TODO_LIST_REBASE_MERGES : 0;\n+\tflags |= opts->rebase_cousins > 0 ? TODO_LIST_REBASE_COUSINS : 0;\n+\tflags |= command == ACTION_SHORTEN_OIDS ? TODO_LIST_SHORTEN_IDS : 0;\n+\n+\tswitch (command) {\n+\tcase ACTION_NONE: {\n+\t\tif (!opts->onto && !opts->upstream)\n+\t\t\tdie(_(\"a base commit must be provided with --upstream or --onto\"));\n+\n+\t\tret = do_interactive_rebase(opts, flags);\n+\t\tbreak;\n+\t}\n+\tcase ACTION_SKIP: {\n+\t\tstruct string_list merge_rr = STRING_LIST_INIT_DUP;\n+\n+\t\trerere_clear(the_repository, &merge_rr);\n+\t}\n+\t\t/* fallthrough */\n+\tcase ACTION_CONTINUE: {\n+\t\tstruct replay_opts replay_opts = get_replay_opts(opts);\n+\n+\t\tret = sequencer_continue(the_repository, &replay_opts);\n+\t\tbreak;\n+\t}\n+\tcase ACTION_EDIT_TODO:\n+\t\tret = edit_todo_file(flags);\n+\t\tbreak;\n+\tcase ACTION_SHOW_CURRENT_PATCH: {\n+\t\tstruct child_process cmd = CHILD_PROCESS_INIT;\n+\n+\t\tcmd.git_cmd = 1;\n+\t\targv_array_pushl(&cmd.args, \"show\", \"REBASE_HEAD\", \"--\", NULL);\n+\t\tret = run_command(&cmd);\n+\n+\t\tbreak;\n+\t}\n+\tcase ACTION_SHORTEN_OIDS:\n+\tcase ACTION_EXPAND_OIDS:\n+\t\tret = transform_todo_file(flags);\n+\t\tbreak;\n+\tcase ACTION_CHECK_TODO_LIST:\n+\t\tret = check_todo_list_from_file(the_repository);\n+\t\tbreak;\n+\tcase ACTION_REARRANGE_SQUASH:\n+\t\tret = rearrange_squash_in_todo_file();\n+\t\tbreak;\n+\tcase ACTION_ADD_EXEC: {\n+\t\tstruct string_list commands = STRING_LIST_INIT_DUP;\n+\n+\t\tsplit_exec_commands(opts->cmd, &commands);\n+\t\tret = add_exec_commands(&commands);\n+\t\tstring_list_clear(&commands, 0);\n+\t\tbreak;\n+\t}\n+\tdefault:\n+\t\tBUG(\"invalid command '%d'\", command);\n+\t}\n+\n+\treturn ret;\n+}\n+\n static const char * const builtin_rebase_interactive_usage[] = {\n \tN_(\"git rebase--interactive [<options>]\"),\n \tNULL\n@@ -368,8 +441,6 @@ static const char * const builtin_rebase_interactive_usage[] = {\n int cmd_rebase__interactive(int argc, const char **argv, const char *prefix)\n {\n \tstruct rebase_options opts = REBASE_OPTIONS_INIT;\n-\tunsigned flags = 0;\n-\tint abbreviate_commands = 0, ret = 0;\n \tstruct object_id squash_onto = null_oid;\n \tenum action command = ACTION_NONE;\n \tstruct option options[] = {\n@@ -434,8 +505,6 @@ int cmd_rebase__interactive(int argc, const char **argv, const char *prefix)\n \n \topts.rebase_cousins = -1;\n \n-\tgit_config_get_bool(\"rebase.abbreviatecommands\", &abbreviate_commands);\n-\n \tif (argc == 1)\n \t\tusage_with_options(builtin_rebase_interactive_usage, options);\n \n@@ -445,71 +514,11 @@ int cmd_rebase__interactive(int argc, const char **argv, const char *prefix)\n \tif (!is_null_oid(&squash_onto))\n \t\topts.squash_onto = &squash_onto;\n \n-\tflags |= opts.keep_empty ? TODO_LIST_KEEP_EMPTY : 0;\n-\tflags |= abbreviate_commands ? TODO_LIST_ABBREVIATE_CMDS : 0;\n-\tflags |= opts.rebase_merges ? TODO_LIST_REBASE_MERGES : 0;\n-\tflags |= opts.rebase_cousins > 0 ? TODO_LIST_REBASE_COUSINS : 0;\n-\tflags |= command == ACTION_SHORTEN_OIDS ? TODO_LIST_SHORTEN_IDS : 0;\n-\n \tif (opts.rebase_cousins >= 0 && !opts.rebase_merges)\n \t\twarning(_(\"--[no-]rebase-cousins has no effect without \"\n \t\t\t  \"--rebase-merges\"));\n \n-\tswitch (command) {\n-\tcase ACTION_NONE: {\n-\t\tif (!opts.onto && !opts.upstream)\n-\t\t\tdie(_(\"a base commit must be provided with --upstream or --onto\"));\n-\n-\t\tret = do_interactive_rebase(&opts, flags);\n-\t\tbreak;\n-\t}\n-\tcase ACTION_SKIP: {\n-\t\tstruct string_list merge_rr = STRING_LIST_INIT_DUP;\n-\n-\t\trerere_clear(the_repository, &merge_rr);\n-\t}\n-\t\t/* fallthrough */\n-\tcase ACTION_CONTINUE: {\n-\t\tstruct replay_opts replay_opts = get_replay_opts(&opts);\n-\n-\t\tret = sequencer_continue(the_repository, &replay_opts);\n-\t\tbreak;\n-\t}\n-\tcase ACTION_EDIT_TODO:\n-\t\tret = edit_todo_file(flags);\n-\t\tbreak;\n-\tcase ACTION_SHOW_CURRENT_PATCH: {\n-\t\tstruct child_process cmd = CHILD_PROCESS_INIT;\n-\n-\t\tcmd.git_cmd = 1;\n-\t\targv_array_pushl(&cmd.args, \"show\", \"REBASE_HEAD\", \"--\", NULL);\n-\t\tret = run_command(&cmd);\n-\n-\t\tbreak;\n-\t}\n-\tcase ACTION_SHORTEN_OIDS:\n-\tcase ACTION_EXPAND_OIDS:\n-\t\tret = transform_todo_file(flags);\n-\t\tbreak;\n-\tcase ACTION_CHECK_TODO_LIST:\n-\t\tret = check_todo_list_from_file(the_repository);\n-\t\tbreak;\n-\tcase ACTION_REARRANGE_SQUASH:\n-\t\tret = rearrange_squash_in_todo_file();\n-\t\tbreak;\n-\tcase ACTION_ADD_EXEC: {\n-\t\tstruct string_list commands = STRING_LIST_INIT_DUP;\n-\n-\t\tsplit_exec_commands(opts.cmd, &commands);\n-\t\tret = add_exec_commands(&commands);\n-\t\tstring_list_clear(&commands, 0);\n-\t\tbreak;\n-\t}\n-\tdefault:\n-\t\tBUG(\"invalid command '%d'\", command);\n-\t}\n-\n-\treturn !!ret;\n+\treturn !!run_rebase_interactive(&opts, command);\n }\n \n static int use_builtin_rebase(void)\n@@ -1072,7 +1081,7 @@ static int run_am(struct rebase_options *opts)\n \treturn status;\n }\n \n-static int run_specific_rebase(struct rebase_options *opts)\n+static int run_specific_rebase(struct rebase_options *opts, enum action action)\n {\n \tconst char *argv[] = { NULL, NULL };\n \tstruct strbuf script_snippet = STRBUF_INIT, buf = STRBUF_INIT;\n@@ -1081,77 +1090,19 @@ static int run_specific_rebase(struct rebase_options *opts)\n \n \tif (opts->type == REBASE_INTERACTIVE) {\n \t\t/* Run builtin interactive rebase */\n-\t\tstruct child_process child = CHILD_PROCESS_INIT;\n-\n-\t\targv_array_pushf(&child.env_array, \"GIT_CHERRY_PICK_HELP=%s\",\n-\t\t\t\t resolvemsg);\n+\t\tsetenv(\"GIT_CHERRY_PICK_HELP\", resolvemsg, 1);\n \t\tif (!(opts->flags & REBASE_INTERACTIVE_EXPLICIT)) {\n-\t\t\targv_array_push(&child.env_array,\n-\t\t\t\t\t\"GIT_SEQUENCE_EDITOR=:\");\n+\t\t\tsetenv(\"GIT_SEQUENCE_EDITOR\", \":\", 1);\n \t\t\topts->autosquash = 0;\n \t\t}\n+\t\tif (opts->gpg_sign_opt) {\n+\t\t\t/* remove the leading \"-S\" */\n+\t\t\tchar *tmp = xstrdup(opts->gpg_sign_opt + 2);\n+\t\t\tfree(opts->gpg_sign_opt);\n+\t\t\topts->gpg_sign_opt = tmp;\n+\t\t}\n \n-\t\tchild.git_cmd = 1;\n-\t\targv_array_push(&child.args, \"rebase--interactive\");\n-\n-\t\tif (opts->action)\n-\t\t\targv_array_pushf(&child.args, \"--%s\", opts->action);\n-\t\tif (opts->keep_empty)\n-\t\t\targv_array_push(&child.args, \"--keep-empty\");\n-\t\tif (opts->rebase_merges)\n-\t\t\targv_array_push(&child.args, \"--rebase-merges\");\n-\t\tif (opts->rebase_cousins)\n-\t\t\targv_array_push(&child.args, \"--rebase-cousins\");\n-\t\tif (opts->autosquash)\n-\t\t\targv_array_push(&child.args, \"--autosquash\");\n-\t\tif (opts->flags & REBASE_VERBOSE)\n-\t\t\targv_array_push(&child.args, \"--verbose\");\n-\t\tif (opts->flags & REBASE_FORCE)\n-\t\t\targv_array_push(&child.args, \"--no-ff\");\n-\t\tif (opts->restrict_revision)\n-\t\t\targv_array_pushf(&child.args,\n-\t\t\t\t\t \"--restrict-revision=^%s\",\n-\t\t\t\t\t oid_to_hex(&opts->restrict_revision->object.oid));\n-\t\tif (opts->upstream)\n-\t\t\targv_array_pushf(&child.args, \"--upstream=%s\",\n-\t\t\t\t\t oid_to_hex(&opts->upstream->object.oid));\n-\t\tif (opts->onto)\n-\t\t\targv_array_pushf(&child.args, \"--onto=%s\",\n-\t\t\t\t\t oid_to_hex(&opts->onto->object.oid));\n-\t\tif (opts->squash_onto)\n-\t\t\targv_array_pushf(&child.args, \"--squash-onto=%s\",\n-\t\t\t\t\t oid_to_hex(opts->squash_onto));\n-\t\tif (opts->onto_name)\n-\t\t\targv_array_pushf(&child.args, \"--onto-name=%s\",\n-\t\t\t\t\t opts->onto_name);\n-\t\targv_array_pushf(&child.args, \"--head-name=%s\",\n-\t\t\t\t opts->head_name ?\n-\t\t\t\t opts->head_name : \"detached HEAD\");\n-\t\tif (opts->strategy)\n-\t\t\targv_array_pushf(&child.args, \"--strategy=%s\",\n-\t\t\t\t\t opts->strategy);\n-\t\tif (opts->strategy_opts)\n-\t\t\targv_array_pushf(&child.args, \"--strategy-opts=%s\",\n-\t\t\t\t\t opts->strategy_opts);\n-\t\tif (opts->switch_to)\n-\t\t\targv_array_pushf(&child.args, \"--switch-to=%s\",\n-\t\t\t\t\t opts->switch_to);\n-\t\tif (opts->cmd)\n-\t\t\targv_array_pushf(&child.args, \"--cmd=%s\", opts->cmd);\n-\t\tif (opts->allow_empty_message)\n-\t\t\targv_array_push(&child.args, \"--allow-empty-message\");\n-\t\tif (opts->allow_rerere_autoupdate == RERERE_AUTOUPDATE)\n-\t\t\targv_array_push(&child.args, \"--rerere-autoupdate\");\n-\t\telse if (opts->allow_rerere_autoupdate == RERERE_NOAUTOUPDATE)\n-\t\t\targv_array_push(&child.args, \"--no-rerere-autoupdate\");\n-\t\tif (opts->gpg_sign_opt)\n-\t\t\targv_array_push(&child.args, opts->gpg_sign_opt);\n-\t\tif (opts->signoff)\n-\t\t\targv_array_push(&child.args, \"--signoff\");\n-\t\tif (opts->reschedule_failed_exec)\n-\t\t\targv_array_push(&child.args, \"--reschedule-failed-exec\");\n-\n-\t\tstatus = run_command(&child);\n+\t\tstatus = run_rebase_interactive(opts, action);\n \t\tgoto finished_rebase;\n \t}\n \n@@ -2212,7 +2163,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \toptions.revisions = revisions.buf;\n \n run_rebase:\n-\tret = !!run_specific_rebase(&options);\n+\tret = !!run_specific_rebase(&options, action);\n \n cleanup:\n \tstrbuf_release(&revisions);\n-- \n2.21.0\n\n"},{"id":"371931","messageId":"875zseehoj.fsf@evledraar.gmail.com","threadId":"50780","inReplyTo":"20190319190317.6632-11-phillip.wood123@gmail.com","subject":"Re: [RFC PATCH 10/11] rebase: use a common action enum","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2019-03-19T20:24:28Z","receivedAt":"2019-03-19T20:24:34Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"\nOn Tue, Mar 19 2019, Phillip Wood wrote:\n\n> From: Phillip Wood <phillip.wood@dunelm.org.uk>\n>\n> cmd_rebase() and cmd_rebase__interactive() used different enums to hold\n> the current action. Change to using a common enum so the values are the\n> same when we change `rebase -i` to avoid forking `rebase--interactive`.\n>\n> Signed-off-by: Phillip Wood <phillip.wood@dunelm.org.uk>\n> ---\n>\n> Notes:\n>     I'm not sure what to do with action_names, I moved it to keep it near\n>     the definition of the enum. The extra commands in the enum are not\n>     traced so they don't need to be in action_names but it looks odd to\n>     leave them out. Also I don't understand why action_names in NULL\n>     terminated or the names are marked for translation as it is used in\n>     \ttrace2_cmd_mode(action_names[action]);\n>     so we don't use the NULL termination or translate the names (I'd be\n>     surprised if we did for tracing)\n\nMaking them for translation is a bug in the recent b3a5d5a80c\n(\"trace2:data: add subverb for rebase\", 2019-02-22) and just looks like\ncopy/paste cargo-culting from somewhere else, and likewise with the\ntrailing NULL which doesn't make sense in this case.\n\n\n>  builtin/rebase.c | 93 +++++++++++++++++++++++++-----------------------\n>  1 file changed, 49 insertions(+), 44 deletions(-)\n>\n> diff --git a/builtin/rebase.c b/builtin/rebase.c\n> index 21ccb6495e..26d25a5242 100644\n> --- a/builtin/rebase.c\n> +++ b/builtin/rebase.c\n> @@ -119,6 +119,30 @@ static struct replay_opts get_replay_opts(const struct rebase_options *opts)\n>  \treturn replay;\n>  }\n>\n> +enum action {\n> +\tACTION_NONE = 0,\n> +\tACTION_CONTINUE,\n> +\tACTION_SKIP,\n> +\tACTION_ABORT,\n> +\tACTION_QUIT,\n> +\tACTION_EDIT_TODO,\n> +\tACTION_SHOW_CURRENT_PATCH,\n> +\tACTION_SHORTEN_OIDS,\n> +\tACTION_EXPAND_OIDS,\n> +\tACTION_CHECK_TODO_LIST,\n> +\tACTION_REARRANGE_SQUASH,\n> +\tACTION_ADD_EXEC\n> +};\n> +\n> +static const char *action_names[] = { N_(\"undefined\"),\n> +\t\t\t\t      N_(\"continue\"),\n> +\t\t\t\t      N_(\"skip\"),\n> +\t\t\t\t      N_(\"abort\"),\n> +\t\t\t\t      N_(\"quit\"),\n> +\t\t\t\t      N_(\"edit_todo\"),\n> +\t\t\t\t      N_(\"show_current_patch\"),\n> +\t\t\t\t      NULL };\n> +\n>  static int add_exec_commands(struct string_list *commands)\n>  {\n>  \tconst char *todo_file = rebase_path_todo();\n> @@ -347,10 +371,7 @@ int cmd_rebase__interactive(int argc, const char **argv, const char *prefix)\n>  \tunsigned flags = 0;\n>  \tint abbreviate_commands = 0, ret = 0;\n>  \tstruct object_id squash_onto = null_oid;\n> -\tenum {\n> -\t\tNONE = 0, CONTINUE, SKIP, EDIT_TODO, SHOW_CURRENT_PATCH,\n> -\t\tSHORTEN_OIDS, EXPAND_OIDS, CHECK_TODO_LIST, REARRANGE_SQUASH, ADD_EXEC\n> -\t} command = 0;\n> +\tenum action command = ACTION_NONE;\n>  \tstruct option options[] = {\n>  \t\tOPT_NEGBIT(0, \"ff\", &opts.flags, N_(\"allow fast-forward\"),\n>  \t\t\t   REBASE_FORCE),\n> @@ -367,22 +388,22 @@ int cmd_rebase__interactive(int argc, const char **argv, const char *prefix)\n>  \t\t\tN_(\"display a diffstat of what changed upstream\"),\n>  \t\t\tREBASE_NO_QUIET | REBASE_VERBOSE | REBASE_DIFFSTAT),\n>  \t\tOPT_CMDMODE(0, \"continue\", &command, N_(\"continue rebase\"),\n> -\t\t\t    CONTINUE),\n> -\t\tOPT_CMDMODE(0, \"skip\", &command, N_(\"skip commit\"), SKIP),\n> +\t\t\t    ACTION_CONTINUE),\n> +\t\tOPT_CMDMODE(0, \"skip\", &command, N_(\"skip commit\"), ACTION_SKIP),\n>  \t\tOPT_CMDMODE(0, \"edit-todo\", &command, N_(\"edit the todo list\"),\n> -\t\t\t    EDIT_TODO),\n> +\t\t\t    ACTION_EDIT_TODO),\n>  \t\tOPT_CMDMODE(0, \"show-current-patch\", &command, N_(\"show the current patch\"),\n> -\t\t\t    SHOW_CURRENT_PATCH),\n> +\t\t\t    ACTION_SHOW_CURRENT_PATCH),\n>  \t\tOPT_CMDMODE(0, \"shorten-ids\", &command,\n> -\t\t\tN_(\"shorten commit ids in the todo list\"), SHORTEN_OIDS),\n> +\t\t\tN_(\"shorten commit ids in the todo list\"), ACTION_SHORTEN_OIDS),\n>  \t\tOPT_CMDMODE(0, \"expand-ids\", &command,\n> -\t\t\tN_(\"expand commit ids in the todo list\"), EXPAND_OIDS),\n> +\t\t\tN_(\"expand commit ids in the todo list\"), ACTION_EXPAND_OIDS),\n>  \t\tOPT_CMDMODE(0, \"check-todo-list\", &command,\n> -\t\t\tN_(\"check the todo list\"), CHECK_TODO_LIST),\n> +\t\t\tN_(\"check the todo list\"), ACTION_CHECK_TODO_LIST),\n>  \t\tOPT_CMDMODE(0, \"rearrange-squash\", &command,\n> -\t\t\tN_(\"rearrange fixup/squash lines\"), REARRANGE_SQUASH),\n> +\t\t\tN_(\"rearrange fixup/squash lines\"), ACTION_REARRANGE_SQUASH),\n>  \t\tOPT_CMDMODE(0, \"add-exec-commands\", &command,\n> -\t\t\tN_(\"insert exec commands in todo list\"), ADD_EXEC),\n> +\t\t\tN_(\"insert exec commands in todo list\"), ACTION_ADD_EXEC),\n>  \t\t{ OPTION_CALLBACK, 0, \"onto\", &opts.onto, N_(\"onto\"), N_(\"onto\"),\n>  \t\t  PARSE_OPT_NONEG, parse_opt_commit, 0 },\n>  \t\t{ OPTION_CALLBACK, 0, \"restrict-revision\", &opts.restrict_revision,\n> @@ -428,36 +449,36 @@ int cmd_rebase__interactive(int argc, const char **argv, const char *prefix)\n>  \tflags |= abbreviate_commands ? TODO_LIST_ABBREVIATE_CMDS : 0;\n>  \tflags |= opts.rebase_merges ? TODO_LIST_REBASE_MERGES : 0;\n>  \tflags |= opts.rebase_cousins > 0 ? TODO_LIST_REBASE_COUSINS : 0;\n> -\tflags |= command == SHORTEN_OIDS ? TODO_LIST_SHORTEN_IDS : 0;\n> +\tflags |= command == ACTION_SHORTEN_OIDS ? TODO_LIST_SHORTEN_IDS : 0;\n>\n>  \tif (opts.rebase_cousins >= 0 && !opts.rebase_merges)\n>  \t\twarning(_(\"--[no-]rebase-cousins has no effect without \"\n>  \t\t\t  \"--rebase-merges\"));\n>\n>  \tswitch (command) {\n> -\tcase NONE: {\n> +\tcase ACTION_NONE: {\n>  \t\tif (!opts.onto && !opts.upstream)\n>  \t\t\tdie(_(\"a base commit must be provided with --upstream or --onto\"));\n>\n>  \t\tret = do_interactive_rebase(&opts, flags);\n>  \t\tbreak;\n>  \t}\n> -\tcase SKIP: {\n> +\tcase ACTION_SKIP: {\n>  \t\tstruct string_list merge_rr = STRING_LIST_INIT_DUP;\n>\n>  \t\trerere_clear(the_repository, &merge_rr);\n>  \t}\n>  \t\t/* fallthrough */\n> -\tcase CONTINUE: {\n> +\tcase ACTION_CONTINUE: {\n>  \t\tstruct replay_opts replay_opts = get_replay_opts(&opts);\n>\n>  \t\tret = sequencer_continue(the_repository, &replay_opts);\n>  \t\tbreak;\n>  \t}\n> -\tcase EDIT_TODO:\n> +\tcase ACTION_EDIT_TODO:\n>  \t\tret = edit_todo_file(flags);\n>  \t\tbreak;\n> -\tcase SHOW_CURRENT_PATCH: {\n> +\tcase ACTION_SHOW_CURRENT_PATCH: {\n>  \t\tstruct child_process cmd = CHILD_PROCESS_INIT;\n>\n>  \t\tcmd.git_cmd = 1;\n> @@ -466,17 +487,17 @@ int cmd_rebase__interactive(int argc, const char **argv, const char *prefix)\n>\n>  \t\tbreak;\n>  \t}\n> -\tcase SHORTEN_OIDS:\n> -\tcase EXPAND_OIDS:\n> +\tcase ACTION_SHORTEN_OIDS:\n> +\tcase ACTION_EXPAND_OIDS:\n>  \t\tret = transform_todo_file(flags);\n>  \t\tbreak;\n> -\tcase CHECK_TODO_LIST:\n> +\tcase ACTION_CHECK_TODO_LIST:\n>  \t\tret = check_todo_list_from_file(the_repository);\n>  \t\tbreak;\n> -\tcase REARRANGE_SQUASH:\n> +\tcase ACTION_REARRANGE_SQUASH:\n>  \t\tret = rearrange_squash_in_todo_file();\n>  \t\tbreak;\n> -\tcase ADD_EXEC: {\n> +\tcase ACTION_ADD_EXEC: {\n>  \t\tstruct string_list commands = STRING_LIST_INIT_DUP;\n>\n>  \t\tsplit_exec_commands(opts.cmd, &commands);\n> @@ -1417,23 +1438,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n>  \tstruct strbuf revisions = STRBUF_INIT;\n>  \tstruct strbuf buf = STRBUF_INIT;\n>  \tstruct object_id merge_base;\n> -\tenum {\n> -\t\tNO_ACTION,\n> -\t\tACTION_CONTINUE,\n> -\t\tACTION_SKIP,\n> -\t\tACTION_ABORT,\n> -\t\tACTION_QUIT,\n> -\t\tACTION_EDIT_TODO,\n> -\t\tACTION_SHOW_CURRENT_PATCH,\n> -\t} action = NO_ACTION;\n> -\tstatic const char *action_names[] = { N_(\"undefined\"),\n> -\t\t\t\t\t      N_(\"continue\"),\n> -\t\t\t\t\t      N_(\"skip\"),\n> -\t\t\t\t\t      N_(\"abort\"),\n> -\t\t\t\t\t      N_(\"quit\"),\n> -\t\t\t\t\t      N_(\"edit_todo\"),\n> -\t\t\t\t\t      N_(\"show_current_patch\"),\n> -\t\t\t\t\t      NULL };\n> +\tenum action action = ACTION_NONE;\n>  \tconst char *gpg_sign = NULL;\n>  \tstruct string_list exec = STRING_LIST_INIT_NODUP;\n>  \tconst char *rebase_merges = NULL;\n> @@ -1600,7 +1605,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n>  \t\t\t     builtin_rebase_options,\n>  \t\t\t     builtin_rebase_usage, 0);\n>\n> -\tif (action != NO_ACTION && total_argc != 2) {\n> +\tif (action != ACTION_NONE && total_argc != 2) {\n>  \t\tusage_with_options(builtin_rebase_usage,\n>  \t\t\t\t   builtin_rebase_options);\n>  \t}\n> @@ -1609,7 +1614,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n>  \t\tusage_with_options(builtin_rebase_usage,\n>  \t\t\t\t   builtin_rebase_options);\n>\n> -\tif (action != NO_ACTION && !in_progress)\n> +\tif (action != ACTION_NONE && !in_progress)\n>  \t\tdie(_(\"No rebase in progress?\"));\n>  \tsetenv(GIT_REFLOG_ACTION_ENVIRONMENT, \"rebase\", 0);\n>\n> @@ -1709,7 +1714,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n>  \t\toptions.action = \"show-current-patch\";\n>  \t\toptions.dont_finish_rebase = 1;\n>  \t\tgoto run_rebase;\n> -\tcase NO_ACTION:\n> +\tcase ACTION_NONE:\n>  \t\tbreak;\n>  \tdefault:\n>  \t\tBUG(\"action: %d\", action);\n"},{"id":"371947","messageId":"CACsJy8CRN1NUD1DdKXkOoaYqCU_RJU56ph=eBAGSS-EXMAcmww@mail.gmail.com","threadId":"50780","inReplyTo":"20190319190317.6632-2-phillip.wood123@gmail.com","subject":"Re: [RFC PATCH 01/11] sequencer: always discard index after checkout","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2019-03-20T01:50:12Z","receivedAt":"2019-03-20T01:50:40Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Wed, Mar 20, 2019 at 2:04 AM Phillip Wood <phillip.wood123@gmail.com> wrote:\n>     It would perhaps be better to pass around the_index rather than\n>     the_repository\n\nNot by a large margin. For sequencer.c most operations require more\nthan just the index and passing 'struct repository *' around has been\nthe norm. And as soon as you need to load the index back (not sure if\nyou should do it here btw, after discard_index, since we have the\nindex loaded before) you need 'struct repository' not 'struct\nindex_state'.\n\n>  builtin/rebase--interactive.c |  2 +-\n>  sequencer.c                   | 27 +++++++++++++++++----------\n>  sequencer.h                   |  3 ++-\n>  3 files changed, 20 insertions(+), 12 deletions(-)\n-- \nDuy\n"},{"id":"372024","messageId":"20190320205042.GH47591@google.com","threadId":"50780","inReplyTo":"20190319190317.6632-1-phillip.wood123@gmail.com","subject":"Re: [RFC PATCH 00/11] rebase -i run without forking rebase--interactive","fromName":"Josh Steadmon","fromEmail":"steadmon@google.com","sentAt":"2019-03-20T20:50:42Z","receivedAt":"2019-03-20T20:50:53Z","isPatch":true,"sender":{"key":"steadmon@google.com","avatar":"https://avatars.githubusercontent.com/u/2654920?v=4"},"body":"On 2019.03.19 19:03, Phillip Wood wrote:\n> From: Phillip Wood <phillip.wood@dunelm.org.uk>\n> \n> When the builtin rebase starts an interactive rebase it parses the\n> options and then repackages them and forks `rebase--interactive`. This\n> series refactors rebase--interactive so that interactive rebases can\n> be started by the builtin rebase without forking. My motivation was to\n> make it easier to debug the sequencer but this should help future\n> maintainability.\n> \n> This series involves some code movement so viewing the diffs with\n> --color-moved is recommended.\n> \n> These patches are based on a merge of master [e902e9bcae (\"The second\n> batch\", 2019-03-11)] and ag/sequencer-reduce-rewriting-todo ed35d18841\n> (\"rebase--interactive: move transform_todo_file()\", 2019-03-05). They\n> can be fetched from the tag rebase-i-no-fork/rfc at\n> https://github.com/phillipwood/git.git\n> \n> Phillip Wood (11):\n>   sequencer: always discard index after checkout\n>   rebase: rename write_basic_state()\n>   rebase: use OPT_RERERE_AUTOUPDATE()\n>   rebase -i: combine rebase--interactive.c with rebase.c\n>   rebase -i: remove duplication\n>   rebase -i: use struct commit when parsing options\n>   rebase -i: use struct object_id for squash_onto\n>   rebase -i: use struct rebase_options to parse args\n>   rebase -i: use struct rebase_options in do_interactive_rebase()\n>   rebase: use a common action enum\n>   rebase -i: run without forking rebase--interactive\n\nAlthough I'm not very familiar with the rebase code, this series looks\ngood to me.\n\nReviewed-by: Josh Steadmon <steadmon@google.com>\n"},{"id":"372035","messageId":"87y359cfjj.fsf@evledraar.gmail.com","threadId":"50780","inReplyTo":"20190319190317.6632-1-phillip.wood123@gmail.com","subject":"Re: [RFC PATCH 00/11] rebase -i run without forking rebase--interactive","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2019-03-20T23:05:52Z","receivedAt":"2019-03-20T23:05:56Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"\nOn Tue, Mar 19 2019, Phillip Wood wrote:\n\n> From: Phillip Wood <phillip.wood@dunelm.org.uk>\n>\n> When the builtin rebase starts an interactive rebase it parses the\n> options and then repackages them and forks `rebase--interactive`. This\n> series refactors rebase--interactive so that interactive rebases can\n> be started by the builtin rebase without forking. My motivation was to\n> make it easier to debug the sequencer but this should help future\n> maintainability.\n>\n> This series involves some code movement so viewing the diffs with\n> --color-moved is recommended.\n>\n> These patches are based on a merge of master [e902e9bcae (\"The second\n> batch\", 2019-03-11)] and ag/sequencer-reduce-rewriting-todo ed35d18841\n> (\"rebase--interactive: move transform_todo_file()\", 2019-03-05). They\n> can be fetched from the tag rebase-i-no-fork/rfc at\n> https://github.com/phillipwood/git.git\n\nJust a that the t/perf/*rebase* numbers look much better with this. I\ndon't have these in front of me anymore, but over 10 runs with -O3 one\nof those long-runnings test was 30% faster.\n\nAnother one (rebase -i) went from 0.02 to 0.01 sec, with that short\namount of time I wonder (but didn't dig) if the test itself is broken...\n"},{"id":"372046","messageId":"xmqqr2b1t30g.fsf@gitster-ct.c.googlers.com","threadId":"50780","inReplyTo":"20190319190317.6632-1-phillip.wood123@gmail.com","subject":"Re: [RFC PATCH 00/11] rebase -i run without forking rebase--interactive","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2019-03-21T01:44:31Z","receivedAt":"2019-03-21T01:44:35Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Phillip Wood <phillip.wood123@gmail.com> writes:\n\n> From: Phillip Wood <phillip.wood@dunelm.org.uk>\n>\n> When the builtin rebase starts an interactive rebase it parses the\n> options and then repackages them and forks `rebase--interactive`. This\n> series refactors rebase--interactive so that interactive rebases can\n> be started by the builtin rebase without forking. My motivation was to\n> make it easier to debug the sequencer but this should help future\n> maintainability.\n>\n> This series involves some code movement so viewing the diffs with\n> --color-moved is recommended.\n>\n> These patches are based on a merge of master [e902e9bcae (\"The second\n> batch\", 2019-03-11)] and ag/sequencer-reduce-rewriting-todo ed35d18841\n> (\"rebase--interactive: move transform_todo_file()\", 2019-03-05). They\n> can be fetched from the tag rebase-i-no-fork/rfc at\n> https://github.com/phillipwood/git.git\n\nExciting.\n\n>\n> Phillip Wood (11):\n>   sequencer: always discard index after checkout\n>   rebase: rename write_basic_state()\n>   rebase: use OPT_RERERE_AUTOUPDATE()\n>   rebase -i: combine rebase--interactive.c with rebase.c\n>   rebase -i: remove duplication\n>   rebase -i: use struct commit when parsing options\n>   rebase -i: use struct object_id for squash_onto\n>   rebase -i: use struct rebase_options to parse args\n>   rebase -i: use struct rebase_options in do_interactive_rebase()\n>   rebase: use a common action enum\n>   rebase -i: run without forking rebase--interactive\n>\n>  Makefile                      |   1 -\n>  builtin/rebase--interactive.c | 377 --------------------\n>  builtin/rebase.c              | 625 ++++++++++++++++++++++++++--------\n>  parse-options-cb.c            |  34 ++\n>  parse-options.h               |   4 +\n>  sequencer.c                   |  42 ++-\n>  sequencer.h                   |   7 +-\n>  7 files changed, 556 insertions(+), 534 deletions(-)\n>  delete mode 100644 builtin/rebase--interactive.c\n"},{"id":"372052","messageId":"xmqqwokssvq6.fsf@gitster-ct.c.googlers.com","threadId":"50780","inReplyTo":"20190319190317.6632-9-phillip.wood123@gmail.com","subject":"Re: [RFC PATCH 08/11] rebase -i: use struct rebase_options to parse args","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2019-03-21T04:21:53Z","receivedAt":"2019-03-21T04:21:59Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Phillip Wood <phillip.wood123@gmail.com> writes:\n\n> +static struct replay_opts get_replay_opts(const struct rebase_options *opts)\n> +{\n> +\tstruct replay_opts replay = REPLAY_OPTS_INIT;\n> +\n> +\tsequencer_init_config(&replay);\n> +\n> +\treplay.action = REPLAY_INTERACTIVE_REBASE;\n> +\treplay.signoff = opts->signoff;\n> +\treplay.allow_ff = !(opts->flags & REBASE_FORCE);\n> +\tif (opts->allow_rerere_autoupdate)\n> +\t\treplay.allow_rerere_auto = opts->allow_rerere_autoupdate;\n> +\treplay.allow_empty = 1;\n> +\treplay.allow_empty_message = opts->allow_empty_message;\n> +\treplay.verbose = opts->flags & REBASE_VERBOSE;\n> +\treplay.reschedule_failed_exec = opts->reschedule_failed_exec;\n> +\treplay.gpg_sign = xstrdup_or_null(opts->gpg_sign_opt);\n> +\treplay.strategy = opts->strategy;\n> +\n> +\treturn replay;\n> +}\n\nThis calls init_config() and then sets .action; does it revert to\nwhat dl/merge-cleanup-scissors-fix wants to do, which flipped the\norder to fix some bug?  It is a bit hard to tell.\n\nUnfortunately because of the earlier huge code movement the changes\nto _this_ file does not conflict and cleanly merges, but because the\nother file is removed by this series while a topic in flight updates\nit, the semantic conflict like this luckily gets discovered.\n\nEspecially since this is still an RFC, I'd preferred to see it\nwithout moving around the code too much (instead, exporting some\nsymbols that need to be visible with each other after renaming them\nto more appropriate names that are fit in the global namespace).\n"},{"id":"372133","messageId":"8c663552-b792-b885-ea59-abe3137efe26@gmail.com","threadId":"50780","inReplyTo":"CACsJy8CRN1NUD1DdKXkOoaYqCU_RJU56ph=eBAGSS-EXMAcmww@mail.gmail.com","subject":"Re: [RFC PATCH 01/11] sequencer: always discard index after checkout","fromName":"Phillip Wood","fromEmail":"phillip.wood123@gmail.com","sentAt":"2019-03-21T14:35:12Z","receivedAt":"2019-03-21T14:35:17Z","isPatch":true,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"On 20/03/2019 01:50, Duy Nguyen wrote:\n> On Wed, Mar 20, 2019 at 2:04 AM Phillip Wood <phillip.wood123@gmail.com> wrote:\n>>      It would perhaps be better to pass around the_index rather than\n>>      the_repository\n> \n> Not by a large margin. For sequencer.c most operations require more\n> than just the index and passing 'struct repository *' around has been\n> the norm. And as soon as you need to load the index back (not sure if\n> you should do it here btw, after discard_index, since we have the\n> index loaded before) you need 'struct repository' not 'struct\n> index_state'.\n\nThanks, I think I'll leave it as it is then. After we checkout the new \nbase we reload the index in the loop that picks the commits. For 'rebase \n<upstream> <branch>' after we checkout <branch> we create the todo-list \nwhich involves a revision walk and then checkout the new base. I'm not \nentirely sure if it needs reloading before we create the todo list but I \nthink it probably not as I don't think rebase--interactive.c loads the \nindex (which would explain why this only becomes an issue when we stop \nforking rebase--interactive from rebase because then rebase.c has loaded \nthe index to check there are no uncommitted changes)\n\nBest Wishes\n\nPhillip\n\n\n\n> \n>>   builtin/rebase--interactive.c |  2 +-\n>>   sequencer.c                   | 27 +++++++++++++++++----------\n>>   sequencer.h                   |  3 ++-\n>>   3 files changed, 20 insertions(+), 12 deletions(-)\n"},{"id":"372135","messageId":"0f1ee77b-90e6-ef61-0aee-ff182c20a98c@gmail.com","threadId":"50780","inReplyTo":"87y359cfjj.fsf@evledraar.gmail.com","subject":"Re: [RFC PATCH 00/11] rebase -i run without forking rebase--interactive","fromName":"Phillip Wood","fromEmail":"phillip.wood123@gmail.com","sentAt":"2019-03-21T14:40:08Z","receivedAt":"2019-03-21T14:40:13Z","isPatch":true,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"\n\nOn 20/03/2019 23:05, Ævar Arnfjörð Bjarmason wrote:\n> \n> On Tue, Mar 19 2019, Phillip Wood wrote:\n> \n>> From: Phillip Wood <phillip.wood@dunelm.org.uk>\n>>\n>> When the builtin rebase starts an interactive rebase it parses the\n>> options and then repackages them and forks `rebase--interactive`. This\n>> series refactors rebase--interactive so that interactive rebases can\n>> be started by the builtin rebase without forking. My motivation was to\n>> make it easier to debug the sequencer but this should help future\n>> maintainability.\n>>\n>> This series involves some code movement so viewing the diffs with\n>> --color-moved is recommended.\n>>\n>> These patches are based on a merge of master [e902e9bcae (\"The second\n>> batch\", 2019-03-11)] and ag/sequencer-reduce-rewriting-todo ed35d18841\n>> (\"rebase--interactive: move transform_todo_file()\", 2019-03-05). They\n>> can be fetched from the tag rebase-i-no-fork/rfc at\n>> https://github.com/phillipwood/git.git\n> \n> Just a that the t/perf/*rebase* numbers look much better with this. I\n> don't have these in front of me anymore, but over 10 runs with -O3 one\n> of those long-runnings test was 30% faster.\n\nThat's surprising I wouldn't expect that much change as the time taken \nto fork shouldn't be that significant compared to the overall running \ntime. I'll make a note to have a look at those tests.\n\n> Another one (rebase -i) went from 0.02 to 0.01 sec, with that short\n> amount of time I wonder (but didn't dig) if the test itself is broken...\n\nYeah, that sounds suspicious\n\nThanks for sharing those results\n\nPhillip\n"},{"id":"372136","messageId":"dbc948f4-164d-6d1d-d7c8-b9d1136cd4c2@gmail.com","threadId":"50780","inReplyTo":"875zseehoj.fsf@evledraar.gmail.com","subject":"Re: [RFC PATCH 10/11] rebase: use a common action enum","fromName":"Phillip Wood","fromEmail":"phillip.wood123@gmail.com","sentAt":"2019-03-21T14:43:31Z","receivedAt":"2019-03-21T14:43:37Z","isPatch":true,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"\n\nOn 19/03/2019 20:24, Ævar Arnfjörð Bjarmason wrote:\n> \n> On Tue, Mar 19 2019, Phillip Wood wrote:\n> \n>> From: Phillip Wood <phillip.wood@dunelm.org.uk>\n>>\n>> cmd_rebase() and cmd_rebase__interactive() used different enums to hold\n>> the current action. Change to using a common enum so the values are the\n>> same when we change `rebase -i` to avoid forking `rebase--interactive`.\n>>\n>> Signed-off-by: Phillip Wood <phillip.wood@dunelm.org.uk>\n>> ---\n>>\n>> Notes:\n>>      I'm not sure what to do with action_names, I moved it to keep it near\n>>      the definition of the enum. The extra commands in the enum are not\n>>      traced so they don't need to be in action_names but it looks odd to\n>>      leave them out. Also I don't understand why action_names in NULL\n>>      terminated or the names are marked for translation as it is used in\n>>      \ttrace2_cmd_mode(action_names[action]);\n>>      so we don't use the NULL termination or translate the names (I'd be\n>>      surprised if we did for tracing)\n> \n> Making them for translation is a bug in the recent b3a5d5a80c\n> (\"trace2:data: add subverb for rebase\", 2019-02-22) and just looks like\n> copy/paste cargo-culting from somewhere else, and likewise with the\n> trailing NULL which doesn't make sense in this case.\n\nThanks for clarifying that, I'll add a preparatory patch at the \nbeginning of the series to fix those issues\n\nBest Wishes\n\nPhillip\n\n>>   builtin/rebase.c | 93 +++++++++++++++++++++++++-----------------------\n>>   1 file changed, 49 insertions(+), 44 deletions(-)\n>>\n>> diff --git a/builtin/rebase.c b/builtin/rebase.c\n>> index 21ccb6495e..26d25a5242 100644\n>> --- a/builtin/rebase.c\n>> +++ b/builtin/rebase.c\n>> @@ -119,6 +119,30 @@ static struct replay_opts get_replay_opts(const struct rebase_options *opts)\n>>   \treturn replay;\n>>   }\n>>\n>> +enum action {\n>> +\tACTION_NONE = 0,\n>> +\tACTION_CONTINUE,\n>> +\tACTION_SKIP,\n>> +\tACTION_ABORT,\n>> +\tACTION_QUIT,\n>> +\tACTION_EDIT_TODO,\n>> +\tACTION_SHOW_CURRENT_PATCH,\n>> +\tACTION_SHORTEN_OIDS,\n>> +\tACTION_EXPAND_OIDS,\n>> +\tACTION_CHECK_TODO_LIST,\n>> +\tACTION_REARRANGE_SQUASH,\n>> +\tACTION_ADD_EXEC\n>> +};\n>> +\n>> +static const char *action_names[] = { N_(\"undefined\"),\n>> +\t\t\t\t      N_(\"continue\"),\n>> +\t\t\t\t      N_(\"skip\"),\n>> +\t\t\t\t      N_(\"abort\"),\n>> +\t\t\t\t      N_(\"quit\"),\n>> +\t\t\t\t      N_(\"edit_todo\"),\n>> +\t\t\t\t      N_(\"show_current_patch\"),\n>> +\t\t\t\t      NULL };\n>> +\n>>   static int add_exec_commands(struct string_list *commands)\n>>   {\n>>   \tconst char *todo_file = rebase_path_todo();\n>> @@ -347,10 +371,7 @@ int cmd_rebase__interactive(int argc, const char **argv, const char *prefix)\n>>   \tunsigned flags = 0;\n>>   \tint abbreviate_commands = 0, ret = 0;\n>>   \tstruct object_id squash_onto = null_oid;\n>> -\tenum {\n>> -\t\tNONE = 0, CONTINUE, SKIP, EDIT_TODO, SHOW_CURRENT_PATCH,\n>> -\t\tSHORTEN_OIDS, EXPAND_OIDS, CHECK_TODO_LIST, REARRANGE_SQUASH, ADD_EXEC\n>> -\t} command = 0;\n>> +\tenum action command = ACTION_NONE;\n>>   \tstruct option options[] = {\n>>   \t\tOPT_NEGBIT(0, \"ff\", &opts.flags, N_(\"allow fast-forward\"),\n>>   \t\t\t   REBASE_FORCE),\n>> @@ -367,22 +388,22 @@ int cmd_rebase__interactive(int argc, const char **argv, const char *prefix)\n>>   \t\t\tN_(\"display a diffstat of what changed upstream\"),\n>>   \t\t\tREBASE_NO_QUIET | REBASE_VERBOSE | REBASE_DIFFSTAT),\n>>   \t\tOPT_CMDMODE(0, \"continue\", &command, N_(\"continue rebase\"),\n>> -\t\t\t    CONTINUE),\n>> -\t\tOPT_CMDMODE(0, \"skip\", &command, N_(\"skip commit\"), SKIP),\n>> +\t\t\t    ACTION_CONTINUE),\n>> +\t\tOPT_CMDMODE(0, \"skip\", &command, N_(\"skip commit\"), ACTION_SKIP),\n>>   \t\tOPT_CMDMODE(0, \"edit-todo\", &command, N_(\"edit the todo list\"),\n>> -\t\t\t    EDIT_TODO),\n>> +\t\t\t    ACTION_EDIT_TODO),\n>>   \t\tOPT_CMDMODE(0, \"show-current-patch\", &command, N_(\"show the current patch\"),\n>> -\t\t\t    SHOW_CURRENT_PATCH),\n>> +\t\t\t    ACTION_SHOW_CURRENT_PATCH),\n>>   \t\tOPT_CMDMODE(0, \"shorten-ids\", &command,\n>> -\t\t\tN_(\"shorten commit ids in the todo list\"), SHORTEN_OIDS),\n>> +\t\t\tN_(\"shorten commit ids in the todo list\"), ACTION_SHORTEN_OIDS),\n>>   \t\tOPT_CMDMODE(0, \"expand-ids\", &command,\n>> -\t\t\tN_(\"expand commit ids in the todo list\"), EXPAND_OIDS),\n>> +\t\t\tN_(\"expand commit ids in the todo list\"), ACTION_EXPAND_OIDS),\n>>   \t\tOPT_CMDMODE(0, \"check-todo-list\", &command,\n>> -\t\t\tN_(\"check the todo list\"), CHECK_TODO_LIST),\n>> +\t\t\tN_(\"check the todo list\"), ACTION_CHECK_TODO_LIST),\n>>   \t\tOPT_CMDMODE(0, \"rearrange-squash\", &command,\n>> -\t\t\tN_(\"rearrange fixup/squash lines\"), REARRANGE_SQUASH),\n>> +\t\t\tN_(\"rearrange fixup/squash lines\"), ACTION_REARRANGE_SQUASH),\n>>   \t\tOPT_CMDMODE(0, \"add-exec-commands\", &command,\n>> -\t\t\tN_(\"insert exec commands in todo list\"), ADD_EXEC),\n>> +\t\t\tN_(\"insert exec commands in todo list\"), ACTION_ADD_EXEC),\n>>   \t\t{ OPTION_CALLBACK, 0, \"onto\", &opts.onto, N_(\"onto\"), N_(\"onto\"),\n>>   \t\t  PARSE_OPT_NONEG, parse_opt_commit, 0 },\n>>   \t\t{ OPTION_CALLBACK, 0, \"restrict-revision\", &opts.restrict_revision,\n>> @@ -428,36 +449,36 @@ int cmd_rebase__interactive(int argc, const char **argv, const char *prefix)\n>>   \tflags |= abbreviate_commands ? TODO_LIST_ABBREVIATE_CMDS : 0;\n>>   \tflags |= opts.rebase_merges ? TODO_LIST_REBASE_MERGES : 0;\n>>   \tflags |= opts.rebase_cousins > 0 ? TODO_LIST_REBASE_COUSINS : 0;\n>> -\tflags |= command == SHORTEN_OIDS ? TODO_LIST_SHORTEN_IDS : 0;\n>> +\tflags |= command == ACTION_SHORTEN_OIDS ? TODO_LIST_SHORTEN_IDS : 0;\n>>\n>>   \tif (opts.rebase_cousins >= 0 && !opts.rebase_merges)\n>>   \t\twarning(_(\"--[no-]rebase-cousins has no effect without \"\n>>   \t\t\t  \"--rebase-merges\"));\n>>\n>>   \tswitch (command) {\n>> -\tcase NONE: {\n>> +\tcase ACTION_NONE: {\n>>   \t\tif (!opts.onto && !opts.upstream)\n>>   \t\t\tdie(_(\"a base commit must be provided with --upstream or --onto\"));\n>>\n>>   \t\tret = do_interactive_rebase(&opts, flags);\n>>   \t\tbreak;\n>>   \t}\n>> -\tcase SKIP: {\n>> +\tcase ACTION_SKIP: {\n>>   \t\tstruct string_list merge_rr = STRING_LIST_INIT_DUP;\n>>\n>>   \t\trerere_clear(the_repository, &merge_rr);\n>>   \t}\n>>   \t\t/* fallthrough */\n>> -\tcase CONTINUE: {\n>> +\tcase ACTION_CONTINUE: {\n>>   \t\tstruct replay_opts replay_opts = get_replay_opts(&opts);\n>>\n>>   \t\tret = sequencer_continue(the_repository, &replay_opts);\n>>   \t\tbreak;\n>>   \t}\n>> -\tcase EDIT_TODO:\n>> +\tcase ACTION_EDIT_TODO:\n>>   \t\tret = edit_todo_file(flags);\n>>   \t\tbreak;\n>> -\tcase SHOW_CURRENT_PATCH: {\n>> +\tcase ACTION_SHOW_CURRENT_PATCH: {\n>>   \t\tstruct child_process cmd = CHILD_PROCESS_INIT;\n>>\n>>   \t\tcmd.git_cmd = 1;\n>> @@ -466,17 +487,17 @@ int cmd_rebase__interactive(int argc, const char **argv, const char *prefix)\n>>\n>>   \t\tbreak;\n>>   \t}\n>> -\tcase SHORTEN_OIDS:\n>> -\tcase EXPAND_OIDS:\n>> +\tcase ACTION_SHORTEN_OIDS:\n>> +\tcase ACTION_EXPAND_OIDS:\n>>   \t\tret = transform_todo_file(flags);\n>>   \t\tbreak;\n>> -\tcase CHECK_TODO_LIST:\n>> +\tcase ACTION_CHECK_TODO_LIST:\n>>   \t\tret = check_todo_list_from_file(the_repository);\n>>   \t\tbreak;\n>> -\tcase REARRANGE_SQUASH:\n>> +\tcase ACTION_REARRANGE_SQUASH:\n>>   \t\tret = rearrange_squash_in_todo_file();\n>>   \t\tbreak;\n>> -\tcase ADD_EXEC: {\n>> +\tcase ACTION_ADD_EXEC: {\n>>   \t\tstruct string_list commands = STRING_LIST_INIT_DUP;\n>>\n>>   \t\tsplit_exec_commands(opts.cmd, &commands);\n>> @@ -1417,23 +1438,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n>>   \tstruct strbuf revisions = STRBUF_INIT;\n>>   \tstruct strbuf buf = STRBUF_INIT;\n>>   \tstruct object_id merge_base;\n>> -\tenum {\n>> -\t\tNO_ACTION,\n>> -\t\tACTION_CONTINUE,\n>> -\t\tACTION_SKIP,\n>> -\t\tACTION_ABORT,\n>> -\t\tACTION_QUIT,\n>> -\t\tACTION_EDIT_TODO,\n>> -\t\tACTION_SHOW_CURRENT_PATCH,\n>> -\t} action = NO_ACTION;\n>> -\tstatic const char *action_names[] = { N_(\"undefined\"),\n>> -\t\t\t\t\t      N_(\"continue\"),\n>> -\t\t\t\t\t      N_(\"skip\"),\n>> -\t\t\t\t\t      N_(\"abort\"),\n>> -\t\t\t\t\t      N_(\"quit\"),\n>> -\t\t\t\t\t      N_(\"edit_todo\"),\n>> -\t\t\t\t\t      N_(\"show_current_patch\"),\n>> -\t\t\t\t\t      NULL };\n>> +\tenum action action = ACTION_NONE;\n>>   \tconst char *gpg_sign = NULL;\n>>   \tstruct string_list exec = STRING_LIST_INIT_NODUP;\n>>   \tconst char *rebase_merges = NULL;\n>> @@ -1600,7 +1605,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n>>   \t\t\t     builtin_rebase_options,\n>>   \t\t\t     builtin_rebase_usage, 0);\n>>\n>> -\tif (action != NO_ACTION && total_argc != 2) {\n>> +\tif (action != ACTION_NONE && total_argc != 2) {\n>>   \t\tusage_with_options(builtin_rebase_usage,\n>>   \t\t\t\t   builtin_rebase_options);\n>>   \t}\n>> @@ -1609,7 +1614,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n>>   \t\tusage_with_options(builtin_rebase_usage,\n>>   \t\t\t\t   builtin_rebase_options);\n>>\n>> -\tif (action != NO_ACTION && !in_progress)\n>> +\tif (action != ACTION_NONE && !in_progress)\n>>   \t\tdie(_(\"No rebase in progress?\"));\n>>   \tsetenv(GIT_REFLOG_ACTION_ENVIRONMENT, \"rebase\", 0);\n>>\n>> @@ -1709,7 +1714,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n>>   \t\toptions.action = \"show-current-patch\";\n>>   \t\toptions.dont_finish_rebase = 1;\n>>   \t\tgoto run_rebase;\n>> -\tcase NO_ACTION:\n>> +\tcase ACTION_NONE:\n>>   \t\tbreak;\n>>   \tdefault:\n>>   \t\tBUG(\"action: %d\", action);\n"},{"id":"372139","messageId":"94fe6518-ca13-8eb8-d455-e2a6fcaeb1d6@gmail.com","threadId":"50780","inReplyTo":"xmqqwokssvq6.fsf@gitster-ct.c.googlers.com","subject":"Re: [RFC PATCH 08/11] rebase -i: use struct rebase_options to parse args","fromName":"Phillip Wood","fromEmail":"phillip.wood123@gmail.com","sentAt":"2019-03-21T14:59:49Z","receivedAt":"2019-03-21T14:59:54Z","isPatch":true,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"Hi Junio\n\nOn 21/03/2019 04:21, Junio C Hamano wrote:\n> Phillip Wood <phillip.wood123@gmail.com> writes:\n> \n>> +static struct replay_opts get_replay_opts(const struct rebase_options *opts)\n>> +{\n>> +\tstruct replay_opts replay = REPLAY_OPTS_INIT;\n>> +\n>> +\tsequencer_init_config(&replay);\n>> +\n>> +\treplay.action = REPLAY_INTERACTIVE_REBASE;\n>> +\treplay.signoff = opts->signoff;\n>> +\treplay.allow_ff = !(opts->flags & REBASE_FORCE);\n>> +\tif (opts->allow_rerere_autoupdate)\n>> +\t\treplay.allow_rerere_auto = opts->allow_rerere_autoupdate;\n>> +\treplay.allow_empty = 1;\n>> +\treplay.allow_empty_message = opts->allow_empty_message;\n>> +\treplay.verbose = opts->flags & REBASE_VERBOSE;\n>> +\treplay.reschedule_failed_exec = opts->reschedule_failed_exec;\n>> +\treplay.gpg_sign = xstrdup_or_null(opts->gpg_sign_opt);\n>> +\treplay.strategy = opts->strategy;\n>> +\n>> +\treturn replay;\n>> +}\n> \n> This calls init_config() and then sets .action; does it revert to\n> what dl/merge-cleanup-scissors-fix wants to do, which flipped the\n> order to fix some bug?  It is a bit hard to tell.\n\ndl/merge-cleanup-scissors-fix changes sequencer_init_config() to depend \non the value of action so action should to be set first. What is in pu \nat the moment in not quite right (though I'm not sure what the practical \nimplications are as it looks like the rebase tests are passing[1]).\n\n[1] https://travis-ci.org/git/git/jobs/509332448\n> Unfortunately because of the earlier huge code movement the changes\n> to _this_ file does not conflict and cleanly merges, but because the\n> other file is removed by this series while a topic in flight updates\n> it, the semantic conflict like this luckily gets discovered.\n> \n> Especially since this is still an RFC, I'd preferred to see it\n> without moving around the code too much (instead, exporting some\n> symbols that need to be visible with each other after renaming them\n> to more appropriate names that are fit in the global namespace).\n\nI'm happy to try doing that, though the textual conflict would be in a \ndifferent place in the file to the semantic conflict but at least they'd \nboth be in the same file. I think it would only need to share the \ndefinitions of struct rebase_options, enum rebase_action and the \ndeclaration of run_rebase_interactive(). Would you be happy with the \naddition of builtin/rebase.h (there don't seem to be another headers in \nthat directory). We could leave rebase--interactive.c around until \nrebase--preserve-merges.sh is finally removed.\n\nBest Wishes\n\nPhillip\n"},{"id":"372176","messageId":"7ba0dc1a-b6dd-4ef6-81ee-495e32fc67cf@gmail.com","threadId":"50780","inReplyTo":"20190319190317.6632-9-phillip.wood123@gmail.com","subject":"Re: [RFC PATCH 08/11] rebase -i: use struct rebase_options to parse args","fromName":"Alban Gruin","fromEmail":"alban.gruin@gmail.com","sentAt":"2019-03-21T21:13:11Z","receivedAt":"2019-03-21T21:13:22Z","isPatch":true,"sender":{"key":"alban.gruin@gmail.com","avatar":"https://avatars.githubusercontent.com/u/6310153?v=4"},"body":"Hi Phillip,\n\nIt’s nice to see your work on this on the list.\n\nLe 19/03/2019 à 20:03, Phillip Wood a écrit :\n> From: Phillip Wood <phillip.wood@dunelm.org.uk>\n> \n> In order to run `rebase -i` without forking `rebase--interactive` it\n> will be convenient to use the same structure when parsing the options in\n> cmd_rebase() and cmd_rebase__interactive().\n> \n> Signed-off-by: Phillip Wood <phillip.wood@dunelm.org.uk>\n> ---\n>  builtin/rebase.c | 203 ++++++++++++++++++++++++++---------------------\n>  1 file changed, 112 insertions(+), 91 deletions(-)\n> \n> diff --git a/builtin/rebase.c b/builtin/rebase.c\n> index c93f2aa629..33a2495032 100644\n> --- a/builtin/rebase.c\n> +++ b/builtin/rebase.c\n> @@ -50,6 +50,73 @@ enum rebase_type {\n>  \tREBASE_PRESERVE_MERGES\n>  };\n>  \n> +struct rebase_options {\n> +\tenum rebase_type type;\n> +\tconst char *state_dir;\n> +\tstruct commit *upstream;\n> +\tconst char *upstream_name;\n> +\tconst char *upstream_arg;\n> +\tchar *head_name;\n> +\tstruct object_id orig_head;\n> +\tstruct commit *onto;\n> +\tconst char *onto_name;\n> +\tconst char *revisions;\n> +\tconst char *switch_to;\n> +\tint root;\n> +\tstruct object_id *squash_onto;\n> +\tstruct commit *restrict_revision;\n> +\tint dont_finish_rebase;\n> +\tenum {\n> +\t\tREBASE_NO_QUIET = 1<<0,\n> +\t\tREBASE_VERBOSE = 1<<1,\n> +\t\tREBASE_DIFFSTAT = 1<<2,\n> +\t\tREBASE_FORCE = 1<<3,\n> +\t\tREBASE_INTERACTIVE_EXPLICIT = 1<<4,\n> +\t} flags;\n> +\tstruct argv_array git_am_opts;\n> +\tconst char *action;\n> +\tint signoff;\n> +\tint allow_rerere_autoupdate;\n> +\tint keep_empty;\n> +\tint autosquash;\n> +\tchar *gpg_sign_opt;\n> +\tint autostash;\n> +\tchar *cmd;\n> +\tint allow_empty_message;\n> +\tint rebase_merges, rebase_cousins;\n> +\tchar *strategy, *strategy_opts;\n> +\tstruct strbuf git_format_patch_opt;\n> +\tint reschedule_failed_exec;\n> +};\n> +\n> +#define REBASE_OPTIONS_INIT {\t\t\t  \t\\\n> +\t\t.type = REBASE_UNSPECIFIED,\t  \t\\\n> +\t\t.flags = REBASE_NO_QUIET, \t\t\\\n> +\t\t.git_am_opts = ARGV_ARRAY_INIT,\t\t\\\n> +\t\t.git_format_patch_opt = STRBUF_INIT\t\\\n> +\t}\n> +\n> +static struct replay_opts get_replay_opts(const struct rebase_options *opts)\n> +{\n> +\tstruct replay_opts replay = REPLAY_OPTS_INIT;\n> +\n> +\tsequencer_init_config(&replay);\n> +\n> +\treplay.action = REPLAY_INTERACTIVE_REBASE;\n> +\treplay.signoff = opts->signoff;\n> +\treplay.allow_ff = !(opts->flags & REBASE_FORCE);\n> +\tif (opts->allow_rerere_autoupdate)\n> +\t\treplay.allow_rerere_auto = opts->allow_rerere_autoupdate;\n> +\treplay.allow_empty = 1;\n> +\treplay.allow_empty_message = opts->allow_empty_message;\n> +\treplay.verbose = opts->flags & REBASE_VERBOSE;\n> +\treplay.reschedule_failed_exec = opts->reschedule_failed_exec;\n> +\treplay.gpg_sign = xstrdup_or_null(opts->gpg_sign_opt);\n> +\treplay.strategy = opts->strategy;\n> +\n> +\treturn replay;\n> +}\n> +\n\nI wonder if `struct rebase_options` and `struct replay_options` could be\nmerged, or at least have `replay_options` used in `rebase_options`,\ninstead of converting one to the other.  I think it would make things\nsimpler and cleaner, but I don’t know how hard it would be, or if my\nassumption is correct.\n\nCheers,\nAlban\n\n"},{"id":"372197","messageId":"xmqqlg17r38v.fsf@gitster-ct.c.googlers.com","threadId":"50780","inReplyTo":"94fe6518-ca13-8eb8-d455-e2a6fcaeb1d6@gmail.com","subject":"Re: [RFC PATCH 08/11] rebase -i: use struct rebase_options to parse args","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2019-03-22T03:34:40Z","receivedAt":"2019-03-22T03:34:44Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Phillip Wood <phillip.wood123@gmail.com> writes:\n\n> Hi Junio\n>\n> On 21/03/2019 04:21, Junio C Hamano wrote:\n>> Phillip Wood <phillip.wood123@gmail.com> writes:\n>>\n>>> +static struct replay_opts get_replay_opts(const struct rebase_options *opts)\n>>> +{\n>>> +\tstruct replay_opts replay = REPLAY_OPTS_INIT;\n>>> +\n>>> +\tsequencer_init_config(&replay);\n>>> +\n>>> +\treplay.action = REPLAY_INTERACTIVE_REBASE;\n>>> +\treplay.signoff = opts->signoff;\n>>> +\treplay.allow_ff = !(opts->flags & REBASE_FORCE);\n>>> +\tif (opts->allow_rerere_autoupdate)\n>>> +\t\treplay.allow_rerere_auto = opts->allow_rerere_autoupdate;\n>>> +\treplay.allow_empty = 1;\n>>> +\treplay.allow_empty_message = opts->allow_empty_message;\n>>> +\treplay.verbose = opts->flags & REBASE_VERBOSE;\n>>> +\treplay.reschedule_failed_exec = opts->reschedule_failed_exec;\n>>> +\treplay.gpg_sign = xstrdup_or_null(opts->gpg_sign_opt);\n>>> +\treplay.strategy = opts->strategy;\n>>> +\n>>> +\treturn replay;\n>>> +}\n>>\n>> This calls init_config() and then sets .action; does it revert to\n>> what dl/merge-cleanup-scissors-fix wants to do, which flipped the\n>> order to fix some bug?  It is a bit hard to tell.\n>\n> dl/merge-cleanup-scissors-fix changes sequencer_init_config() to\n> depend on the value of action so action should to be set first. What\n> is in pu at the moment in not quite right (though I'm not sure what\n> the practical implications are as it looks like the rebase tests are\n> passing[1]).\n>\n> [1] https://travis-ci.org/git/git/jobs/509332448\n\nYes, it actually is the reason why I left the seemingly-wrong merge\nin 'pu' on purpose to see if we have enough test coverage.\n\n> they'd both be in the same file. I think it would only need to share\n> the definitions of struct rebase_options, enum rebase_action and the\n> declaration of run_rebase_interactive(). Would you be happy with the\n> addition of builtin/rebase.h (there don't seem to be another headers\n> in that directory). We could leave rebase--interactive.c around until\n> rebase--preserve-merges.sh is finally removed.\n\nI think dl/merge-cleanup-scissors-fix is getting solid enough, so a\nbetter alternative may be to base this on top of\n\n\treset e902e9bcae ;# The second batch\n\tmerge ag/sequencer-reduce-rewriting-todo\n\tmerge dl/merge-cleanup-scissors-fix\n\ninstead of basing it only on ag/sequencer-reduce-rewriting-todo.\n\nThanks.\n"},{"id":"373609","messageId":"1413d9ef-7164-c3e6-629d-8388d3177e1b@gmail.com","threadId":"50780","inReplyTo":"7ba0dc1a-b6dd-4ef6-81ee-495e32fc67cf@gmail.com","subject":"Re: [RFC PATCH 08/11] rebase -i: use struct rebase_options to parse args","fromName":"Phillip Wood","fromEmail":"phillip.wood123@gmail.com","sentAt":"2019-04-10T19:16:36Z","receivedAt":"2019-04-10T19:16:42Z","isPatch":true,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"Hi Alban\n\nsorry for the slow reply, I think you're probably off-list for a while \nby now\n\nOn 21/03/2019 21:13, Alban Gruin wrote:\n> Hi Phillip,\n> \n> It’s nice to see your work on this on the list.\n> \n> Le 19/03/2019 à 20:03, Phillip Wood a écrit :\n>> From: Phillip Wood <phillip.wood@dunelm.org.uk>\n>>\n>> In order to run `rebase -i` without forking `rebase--interactive` it\n>> will be convenient to use the same structure when parsing the options in\n>> cmd_rebase() and cmd_rebase__interactive().\n>>\n>> Signed-off-by: Phillip Wood <phillip.wood@dunelm.org.uk>\n>> ---\n>>   builtin/rebase.c | 203 ++++++++++++++++++++++++++---------------------\n>>   1 file changed, 112 insertions(+), 91 deletions(-)\n>>\n>> diff --git a/builtin/rebase.c b/builtin/rebase.c\n>> index c93f2aa629..33a2495032 100644\n>> --- a/builtin/rebase.c\n>> +++ b/builtin/rebase.c\n>> @@ -50,6 +50,73 @@ enum rebase_type {\n>>   \tREBASE_PRESERVE_MERGES\n>>   };\n>>   \n>> +struct rebase_options {\n>> +\tenum rebase_type type;\n>> +\tconst char *state_dir;\n>> +\tstruct commit *upstream;\n>> +\tconst char *upstream_name;\n>> +\tconst char *upstream_arg;\n>> +\tchar *head_name;\n>> +\tstruct object_id orig_head;\n>> +\tstruct commit *onto;\n>> +\tconst char *onto_name;\n>> +\tconst char *revisions;\n>> +\tconst char *switch_to;\n>> +\tint root;\n>> +\tstruct object_id *squash_onto;\n>> +\tstruct commit *restrict_revision;\n>> +\tint dont_finish_rebase;\n>> +\tenum {\n>> +\t\tREBASE_NO_QUIET = 1<<0,\n>> +\t\tREBASE_VERBOSE = 1<<1,\n>> +\t\tREBASE_DIFFSTAT = 1<<2,\n>> +\t\tREBASE_FORCE = 1<<3,\n>> +\t\tREBASE_INTERACTIVE_EXPLICIT = 1<<4,\n>> +\t} flags;\n>> +\tstruct argv_array git_am_opts;\n>> +\tconst char *action;\n>> +\tint signoff;\n>> +\tint allow_rerere_autoupdate;\n>> +\tint keep_empty;\n>> +\tint autosquash;\n>> +\tchar *gpg_sign_opt;\n>> +\tint autostash;\n>> +\tchar *cmd;\n>> +\tint allow_empty_message;\n>> +\tint rebase_merges, rebase_cousins;\n>> +\tchar *strategy, *strategy_opts;\n>> +\tstruct strbuf git_format_patch_opt;\n>> +\tint reschedule_failed_exec;\n>> +};\n>> +\n>> +#define REBASE_OPTIONS_INIT {\t\t\t  \t\\\n>> +\t\t.type = REBASE_UNSPECIFIED,\t  \t\\\n>> +\t\t.flags = REBASE_NO_QUIET, \t\t\\\n>> +\t\t.git_am_opts = ARGV_ARRAY_INIT,\t\t\\\n>> +\t\t.git_format_patch_opt = STRBUF_INIT\t\\\n>> +\t}\n>> +\n>> +static struct replay_opts get_replay_opts(const struct rebase_options *opts)\n>> +{\n>> +\tstruct replay_opts replay = REPLAY_OPTS_INIT;\n>> +\n>> +\tsequencer_init_config(&replay);\n>> +\n>> +\treplay.action = REPLAY_INTERACTIVE_REBASE;\n>> +\treplay.signoff = opts->signoff;\n>> +\treplay.allow_ff = !(opts->flags & REBASE_FORCE);\n>> +\tif (opts->allow_rerere_autoupdate)\n>> +\t\treplay.allow_rerere_auto = opts->allow_rerere_autoupdate;\n>> +\treplay.allow_empty = 1;\n>> +\treplay.allow_empty_message = opts->allow_empty_message;\n>> +\treplay.verbose = opts->flags & REBASE_VERBOSE;\n>> +\treplay.reschedule_failed_exec = opts->reschedule_failed_exec;\n>> +\treplay.gpg_sign = xstrdup_or_null(opts->gpg_sign_opt);\n>> +\treplay.strategy = opts->strategy;\n>> +\n>> +\treturn replay;\n>> +}\n>> +\n> \n> I wonder if `struct rebase_options` and `struct replay_options` could be\n> merged, or at least have `replay_options` used in `rebase_options`,\n> instead of converting one to the other.  I think it would make things\n> simpler and cleaner, but I don’t know how hard it would be, or if my\n> assumption is correct.\n\nI did consider doing that, but there are a few subtle differences in the \nway the options are stored in each struct (eg the gpg option has a \nleading -S in struct rebase_options but not struct replay_options) and I \nthink it would be a bit of a faff to align them as it would mean messing \nwith the code uses them and the code that reads/writes the various state \nfiles (we cannot change the on-disk format without breaking things - \nsometimes users start a rebase with one version of git bundled with \nsomething like tig and then continue on the command-line with a \ndifferent version). I'd prefer to leave it as a future cleanup once this \nseries has been merged.\n\nBest Wishes\n\nPhillip\n> \n> Cheers,\n> Alban\n> \n"},{"id":"374037","messageId":"20190417143044.17655-1-phillip.wood123@gmail.com","threadId":"50780","inReplyTo":"20190319190317.6632-1-phillip.wood123@gmail.com","subject":"[PATCH v1 00/12] Run rebase -i without forking rebase--interactive","fromName":"Phillip Wood","fromEmail":"phillip.wood123@gmail.com","sentAt":"2019-04-17T14:30:32Z","receivedAt":"2019-04-17T14:33:01Z","isPatch":true,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"From: Phillip Wood <phillip.wood@dunelm.org.uk>\n\nThanks for the feedback on the last version. I've updated the final\ncommit message to mention the speed up reported by Ævar. I've also\nremoved the translation of the trace strings. Apart from that this\nseries is unchanged. There shouldn't be any merge conflicts with the\nupdated dl/merge-cleanup-scissors-fix I posted earlier. (There are\nconflicts with other series but they are already resolved in pu)\n\nThis series still based on a merge of master [e902e9bcae (\"The second\nbatch\", 2019-03-11)] and ag/sequencer-reduce-rewriting-todo ed35d18841\n(\"rebase--interactive: move transform_todo_file()\", 2019-03-05). It\ncan be fetched from the tag rebase-i-no-fork/v1 at\nhttps://github.com/phillipwood/git.git\n\nPhillip Wood (12):\n  sequencer: always discard index after checkout\n  rebase: don't translate trace strings\n  rebase: rename write_basic_state()\n  rebase: use OPT_RERERE_AUTOUPDATE()\n  rebase -i: combine rebase--interactive.c with rebase.c\n  rebase -i: remove duplication\n  rebase -i: use struct commit when parsing options\n  rebase -i: use struct object_id for squash_onto\n  rebase -i: use struct rebase_options to parse args\n  rebase -i: use struct rebase_options in do_interactive_rebase()\n  rebase: use a common action enum\n  rebase -i: run without forking rebase--interactive\n\n Makefile                      |   1 -\n builtin/rebase--interactive.c | 377 --------------------\n builtin/rebase.c              | 624 ++++++++++++++++++++++++++--------\n parse-options-cb.c            |  34 ++\n parse-options.h               |   4 +\n sequencer.c                   |  42 ++-\n sequencer.h                   |   7 +-\n 7 files changed, 555 insertions(+), 534 deletions(-)\n delete mode 100644 builtin/rebase--interactive.c\n\nRange-diff to rfc\n 1:  549d45dc63 =  1:  fe51202dfb sequencer: always discard index after checkout\n -:  ---------- >  2:  2598165c0f rebase: don't translate trace strings\n 2:  d896a3c76f =  3:  48801ccdd5 rebase: rename write_basic_state()\n 3:  253de33871 =  4:  66972f0f7d rebase: use OPT_RERERE_AUTOUPDATE()\n 4:  0aaeaf7c09 =  5:  c18aa58305 rebase -i: combine rebase--interactive.c with rebase.c\n 5:  ff539c37d1 =  6:  27982630d1 rebase -i: remove duplication\n 6:  71559a38db =  7:  f28e8df52a rebase -i: use struct commit when parsing options\n 7:  34c9e4ae96 =  8:  1ae13b5a7d rebase -i: use struct object_id for squash_onto\n 8:  4fe81c9e81 !  9:  efcc32d8e3 rebase -i: use struct rebase_options to parse args\n    @@ -65,9 +65,9 @@\n     +{\n     +\tstruct replay_opts replay = REPLAY_OPTS_INIT;\n     +\n    -+\tsequencer_init_config(&replay);\n    -+\n     +\treplay.action = REPLAY_INTERACTIVE_REBASE;\n    ++\tsequencer_init_config(&replay);\n    ++\n     +\treplay.signoff = opts->signoff;\n     +\treplay.allow_ff = !(opts->flags & REBASE_FORCE);\n     +\tif (opts->allow_rerere_autoupdate)\n 9:  09343e540f = 10:  c89d815ad4 rebase -i: use struct rebase_options in do_interactive_rebase()\n10:  9ad1482d7f ! 11:  fda591f006 rebase: use a common action enum\n    @@ -38,14 +30,13 @@\n     +\tACTION_ADD_EXEC\n     +};\n     +\n    -+static const char *action_names[] = { N_(\"undefined\"),\n    -+\t\t\t\t      N_(\"continue\"),\n    -+\t\t\t\t      N_(\"skip\"),\n    -+\t\t\t\t      N_(\"abort\"),\n    -+\t\t\t\t      N_(\"quit\"),\n    -+\t\t\t\t      N_(\"edit_todo\"),\n    -+\t\t\t\t      N_(\"show_current_patch\"),\n    -+\t\t\t\t      NULL };\n    ++static const char *action_names[] = { \"undefined\",\n    ++\t\t\t\t      \"continue\",\n    ++\t\t\t\t      \"skip\",\n    ++\t\t\t\t      \"abort\",\n    ++\t\t\t\t      \"quit\",\n    ++\t\t\t\t      \"edit_todo\",\n    ++\t\t\t\t      \"show_current_patch\" };\n     +\n      static int add_exec_commands(struct string_list *commands)\n      {\n    @@ -173,14 +164,13 @@\n     -\t\tACTION_EDIT_TODO,\n     -\t\tACTION_SHOW_CURRENT_PATCH,\n     -\t} action = NO_ACTION;\n    --\tstatic const char *action_names[] = { N_(\"undefined\"),\n    --\t\t\t\t\t      N_(\"continue\"),\n    --\t\t\t\t\t      N_(\"skip\"),\n    --\t\t\t\t\t      N_(\"abort\"),\n    --\t\t\t\t\t      N_(\"quit\"),\n    --\t\t\t\t\t      N_(\"edit_todo\"),\n    --\t\t\t\t\t      N_(\"show_current_patch\"),\n    --\t\t\t\t\t      NULL };\n    +-\tstatic const char *action_names[] = { \"undefined\",\n    +-\t\t\t\t\t      \"continue\",\n    +-\t\t\t\t\t      \"skip\",\n    +-\t\t\t\t\t      \"abort\",\n    +-\t\t\t\t\t      \"quit\",\n    +-\t\t\t\t\t      \"edit_todo\",\n    +-\t\t\t\t\t      \"show_current_patch\" };\n     +\tenum action action = ACTION_NONE;\n      \tconst char *gpg_sign = NULL;\n      \tstruct string_list exec = STRING_LIST_INIT_NODUP;\n11:  ebfd7f80d9 ! 12:  d921226d32 rebase -i: run without forking rebase--interactive\n    @@ -7,10 +7,18 @@\n         `rebase--interactive`. Separate the option parsing in\n         cmd_rebase__interactive() from the business logic to allow interactive\n         rebases can be run without forking `rebase__interactive` by calling\n    -    run_rebase_interactive() directly. This makes it easy to debug the\n    -    sequencer without worrying about attaching to child processes. It also\n    -    makes it easy to remove cmd_rebase__interactive() in the future when\n    -    git-legacy-rebase.sh and git-rebase--preserve-merges.sh are retired.\n    +    run_rebase_interactive() directly.\n    +\n    +    Starting interactive rebases without forking makes it easy to debug\n    +    the sequencer without worrying about attaching to child\n    +    processes. Ævar has also reported that some of the rebase perf tests\n    +    are 30% faster [1].\n    +\n    +    This patch also makes it easy to remove cmd_rebase__interactive() in\n    +    the future when git-legacy-rebase.sh and\n    +    git-rebase--preserve-merges.sh are retired.\n    +\n    +    [1] https://public-inbox.org/git/87y359cfjj.fsf@evledraar.gmail.com/\n\n         Signed-off-by: Phillip Wood <phillip.wood@dunelm.org.uk>\n\n--\n2.21.0\n\n"},{"id":"374038","messageId":"20190417143044.17655-2-phillip.wood123@gmail.com","threadId":"50780","inReplyTo":"20190417143044.17655-1-phillip.wood123@gmail.com","subject":"[PATCH v1 01/12] sequencer: always discard index after checkout","fromName":"Phillip Wood","fromEmail":"phillip.wood123@gmail.com","sentAt":"2019-04-17T14:30:33Z","receivedAt":"2019-04-17T14:33:01Z","isPatch":true,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"From: Phillip Wood <phillip.wood@dunelm.org.uk>\n\nAs the checkout runs in a separate process our index will be out of date\nso it should be discarded. The existing callers are not doing this\nconsistently so do it here to avoid the callers having to worry about\nit.\n\nThis fixes some test failures that happen if do_interactive_rebase() is\ncalled without forking rebase--interactive which we will implement\nshortly. Running\n\n  git rebase -i master topic\n\nstarting on master created empty todo lists because all the commits in\ntopic were marked as cherry-picks. After topic was checked out in\nprepare_branch_to_be_rebased() the working tree contained the contents\nfrom topic but the index contained master and the cache entries were\nstill valid. This meant that diff_populate_filespec() which loads the\nblobs when calculating patch-id's ended up reading the contents for\nmaster from the working tree which actually contained topic.\n\nSigned-off-by: Phillip Wood <phillip.wood@dunelm.org.uk>\n---\n builtin/rebase--interactive.c |  2 +-\n sequencer.c                   | 27 +++++++++++++++++----------\n sequencer.h                   |  3 ++-\n 3 files changed, 20 insertions(+), 12 deletions(-)\n\ndiff --git a/builtin/rebase--interactive.c b/builtin/rebase--interactive.c\nindex 4535523bf5..d1a4ac1b84 100644\n--- a/builtin/rebase--interactive.c\n+++ b/builtin/rebase--interactive.c\n@@ -171,7 +171,7 @@ static int do_interactive_rebase(struct replay_opts *opts, unsigned flags,\n \tstruct argv_array make_script_args = ARGV_ARRAY_INIT;\n \tstruct todo_list todo_list = TODO_LIST_INIT;\n \n-\tif (prepare_branch_to_be_rebased(opts, switch_to))\n+\tif (prepare_branch_to_be_rebased(the_repository, opts, switch_to))\n \t\treturn -1;\n \n \tif (get_revision_ranges(upstream, onto, &head_hash,\ndiff --git a/sequencer.c b/sequencer.c\nindex 281a8ade19..ccc0160800 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -3418,10 +3418,11 @@ static const char *reflog_message(struct replay_opts *opts,\n \treturn buf.buf;\n }\n \n-static int run_git_checkout(struct replay_opts *opts, const char *commit,\n-\t\t\t    const char *action)\n+static int run_git_checkout(struct repository *r, struct replay_opts *opts,\n+\t\t\t    const char *commit, const char *action)\n {\n \tstruct child_process cmd = CHILD_PROCESS_INIT;\n+\tint ret;\n \n \tcmd.git_cmd = 1;\n \n@@ -3430,25 +3431,31 @@ static int run_git_checkout(struct replay_opts *opts, const char *commit,\n \targv_array_pushf(&cmd.env_array, GIT_REFLOG_ACTION \"=%s\", action);\n \n \tif (opts->verbose)\n-\t\treturn run_command(&cmd);\n+\t\tret = run_command(&cmd);\n \telse\n-\t\treturn run_command_silent_on_success(&cmd);\n+\t\tret = run_command_silent_on_success(&cmd);\n+\n+\tif (!ret)\n+\t\tdiscard_index(r->index);\n+\n+\treturn ret;\n }\n \n-int prepare_branch_to_be_rebased(struct replay_opts *opts, const char *commit)\n+int prepare_branch_to_be_rebased(struct repository *r, struct replay_opts *opts,\n+\t\t\t\t const char *commit)\n {\n \tconst char *action;\n \n \tif (commit && *commit) {\n \t\taction = reflog_message(opts, \"start\", \"checkout %s\", commit);\n-\t\tif (run_git_checkout(opts, commit, action))\n+\t\tif (run_git_checkout(r, opts, commit, action))\n \t\t\treturn error(_(\"could not checkout %s\"), commit);\n \t}\n \n \treturn 0;\n }\n \n-static int checkout_onto(struct replay_opts *opts,\n+static int checkout_onto(struct repository *r, struct replay_opts *opts,\n \t\t\t const char *onto_name, const char *onto,\n \t\t\t const char *orig_head)\n {\n@@ -3458,7 +3465,7 @@ static int checkout_onto(struct replay_opts *opts,\n \tif (get_oid(orig_head, &oid))\n \t\treturn error(_(\"%s: not a valid OID\"), orig_head);\n \n-\tif (run_git_checkout(opts, onto, action)) {\n+\tif (run_git_checkout(r, opts, onto, action)) {\n \t\tapply_autostash(opts);\n \t\tsequencer_remove_state(opts);\n \t\treturn error(_(\"could not detach HEAD\"));\n@@ -4786,7 +4793,7 @@ int complete_action(struct repository *r, struct replay_opts *opts, unsigned fla\n \tif (todo_list_parse_insn_buffer(r, new_todo.buf.buf, &new_todo) ||\n \t    todo_list_check(todo_list, &new_todo)) {\n \t\tfprintf(stderr, _(edit_todo_list_advice));\n-\t\tcheckout_onto(opts, onto_name, onto, orig_head);\n+\t\tcheckout_onto(r, opts, onto_name, onto, orig_head);\n \t\ttodo_list_release(&new_todo);\n \n \t\treturn -1;\n@@ -4805,7 +4812,7 @@ int complete_action(struct repository *r, struct replay_opts *opts, unsigned fla\n \n \ttodo_list_release(&new_todo);\n \n-\tif (checkout_onto(opts, onto_name, oid_to_hex(&oid), orig_head))\n+\tif (checkout_onto(r, opts, onto_name, oid_to_hex(&oid), orig_head))\n \t\treturn -1;\n \n \tif (require_clean_work_tree(r, \"rebase\", \"\", 1, 1))\ndiff --git a/sequencer.h b/sequencer.h\nindex a515ee4457..6c55aa4200 100644\n--- a/sequencer.h\n+++ b/sequencer.h\n@@ -175,7 +175,8 @@ void commit_post_rewrite(struct repository *r,\n \t\t\t const struct commit *current_head,\n \t\t\t const struct object_id *new_head);\n \n-int prepare_branch_to_be_rebased(struct replay_opts *opts, const char *commit);\n+int prepare_branch_to_be_rebased(struct repository *r, struct replay_opts *opts,\n+\t\t\t\t const char *commit);\n \n #define SUMMARY_INITIAL_COMMIT   (1 << 0)\n #define SUMMARY_SHOW_AUTHOR_DATE (1 << 1)\n-- \n2.21.0\n\n"},{"id":"374039","messageId":"20190417143044.17655-4-phillip.wood123@gmail.com","threadId":"50780","inReplyTo":"20190417143044.17655-1-phillip.wood123@gmail.com","subject":"[PATCH v1 03/12] rebase: rename write_basic_state()","fromName":"Phillip Wood","fromEmail":"phillip.wood123@gmail.com","sentAt":"2019-04-17T14:30:35Z","receivedAt":"2019-04-17T14:33:04Z","isPatch":true,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"From: Phillip Wood <phillip.wood@dunelm.org.uk>\n\nThis clashes with a function in sequencer.c\n\nSigned-off-by: Phillip Wood <phillip.wood@dunelm.org.uk>\n---\n builtin/rebase.c | 4 ++--\n 1 file changed, 2 insertions(+), 2 deletions(-)\n\ndiff --git a/builtin/rebase.c b/builtin/rebase.c\nindex 239a54ecfe..0b1a193a8e 100644\n--- a/builtin/rebase.c\n+++ b/builtin/rebase.c\n@@ -245,7 +245,7 @@ static int read_basic_state(struct rebase_options *opts)\n \treturn 0;\n }\n \n-static int write_basic_state(struct rebase_options *opts)\n+static int rebase_write_basic_state(struct rebase_options *opts)\n {\n \twrite_file(state_dir_path(\"head-name\", opts), \"%s\",\n \t\t   opts->head_name ? opts->head_name : \"detached HEAD\");\n@@ -640,7 +640,7 @@ static int run_am(struct rebase_options *opts)\n \t}\n \n \tif (is_directory(opts->state_dir))\n-\t\twrite_basic_state(opts);\n+\t\trebase_write_basic_state(opts);\n \n \treturn status;\n }\n-- \n2.21.0\n\n"},{"id":"374040","messageId":"20190417143044.17655-5-phillip.wood123@gmail.com","threadId":"50780","inReplyTo":"20190417143044.17655-1-phillip.wood123@gmail.com","subject":"[PATCH v1 04/12] rebase: use OPT_RERERE_AUTOUPDATE()","fromName":"Phillip Wood","fromEmail":"phillip.wood123@gmail.com","sentAt":"2019-04-17T14:30:36Z","receivedAt":"2019-04-17T14:33:04Z","isPatch":true,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"From: Phillip Wood <phillip.wood@dunelm.org.uk>\n\nAs we have a macro for this it makes sense to use it. Having\ncmd_rebase() and cmd_rebase__interactive() use the same values for\nthis option will be helpful when we start running interactive rebases\nwithout forking rebase--interactive.\n\nSigned-off-by: Phillip Wood <phillip.wood@dunelm.org.uk>\n---\n builtin/rebase.c | 30 +++++++++++++-----------------\n 1 file changed, 13 insertions(+), 17 deletions(-)\n\ndiff --git a/builtin/rebase.c b/builtin/rebase.c\nindex 0b1a193a8e..e7b8122003 100644\n--- a/builtin/rebase.c\n+++ b/builtin/rebase.c\n@@ -206,14 +206,13 @@ static int read_basic_state(struct rebase_options *opts)\n \t\t\t    &buf))\n \t\t\treturn -1;\n \t\tif (!strcmp(buf.buf, \"--rerere-autoupdate\"))\n-\t\t\topts->allow_rerere_autoupdate = 1;\n+\t\t\topts->allow_rerere_autoupdate = RERERE_AUTOUPDATE;\n \t\telse if (!strcmp(buf.buf, \"--no-rerere-autoupdate\"))\n-\t\t\topts->allow_rerere_autoupdate = 0;\n+\t\t\topts->allow_rerere_autoupdate = RERERE_NOAUTOUPDATE;\n \t\telse\n \t\t\twarning(_(\"ignoring invalid allow_rerere_autoupdate: \"\n \t\t\t\t  \"'%s'\"), buf.buf);\n-\t} else\n-\t\topts->allow_rerere_autoupdate = -1;\n+\t}\n \n \tif (file_exists(state_dir_path(\"gpg_sign_opt\", opts))) {\n \t\tstrbuf_reset(&buf);\n@@ -263,10 +262,11 @@ static int rebase_write_basic_state(struct rebase_options *opts)\n \tif (opts->strategy_opts)\n \t\twrite_file(state_dir_path(\"strategy_opts\", opts), \"%s\",\n \t\t\t   opts->strategy_opts);\n-\tif (opts->allow_rerere_autoupdate >= 0)\n+\tif (opts->allow_rerere_autoupdate > 0)\n \t\twrite_file(state_dir_path(\"allow_rerere_autoupdate\", opts),\n \t\t\t   \"-%s-rerere-autoupdate\",\n-\t\t\t   opts->allow_rerere_autoupdate ? \"\" : \"-no\");\n+\t\t\t   opts->allow_rerere_autoupdate == RERERE_AUTOUPDATE ?\n+\t\t\t\t\"\" : \"-no\");\n \tif (opts->gpg_sign_opt)\n \t\twrite_file(state_dir_path(\"gpg_sign_opt\", opts), \"%s\",\n \t\t\t   opts->gpg_sign_opt);\n@@ -625,9 +625,9 @@ static int run_am(struct rebase_options *opts)\n \targv_array_push(&am.args, \"--rebasing\");\n \targv_array_pushf(&am.args, \"--resolvemsg=%s\", resolvemsg);\n \targv_array_push(&am.args, \"--patch-format=mboxrd\");\n-\tif (opts->allow_rerere_autoupdate > 0)\n+\tif (opts->allow_rerere_autoupdate == RERERE_AUTOUPDATE)\n \t\targv_array_push(&am.args, \"--rerere-autoupdate\");\n-\telse if (opts->allow_rerere_autoupdate == 0)\n+\telse if (opts->allow_rerere_autoupdate == RERERE_NOAUTOUPDATE)\n \t\targv_array_push(&am.args, \"--no-rerere-autoupdate\");\n \tif (opts->gpg_sign_opt)\n \t\targv_array_push(&am.args, opts->gpg_sign_opt);\n@@ -713,9 +713,9 @@ static int run_specific_rebase(struct rebase_options *opts)\n \t\t\targv_array_pushf(&child.args, \"--cmd=%s\", opts->cmd);\n \t\tif (opts->allow_empty_message)\n \t\t\targv_array_push(&child.args, \"--allow-empty-message\");\n-\t\tif (opts->allow_rerere_autoupdate > 0)\n+\t\tif (opts->allow_rerere_autoupdate == RERERE_AUTOUPDATE)\n \t\t\targv_array_push(&child.args, \"--rerere-autoupdate\");\n-\t\telse if (opts->allow_rerere_autoupdate == 0)\n+\t\telse if (opts->allow_rerere_autoupdate == RERERE_NOAUTOUPDATE)\n \t\t\targv_array_push(&child.args, \"--no-rerere-autoupdate\");\n \t\tif (opts->gpg_sign_opt)\n \t\t\targv_array_push(&child.args, opts->gpg_sign_opt);\n@@ -764,9 +764,9 @@ static int run_specific_rebase(struct rebase_options *opts)\n \tadd_var(&script_snippet, \"action\", opts->action ? opts->action : \"\");\n \tadd_var(&script_snippet, \"signoff\", opts->signoff ? \"--signoff\" : \"\");\n \tadd_var(&script_snippet, \"allow_rerere_autoupdate\",\n-\t\topts->allow_rerere_autoupdate < 0 ? \"\" :\n \t\topts->allow_rerere_autoupdate ?\n-\t\t\"--rerere-autoupdate\" : \"--no-rerere-autoupdate\");\n+\t\t\topts->allow_rerere_autoupdate == RERERE_AUTOUPDATE ?\n+\t\t\t\"--rerere-autoupdate\" : \"--no-rerere-autoupdate\" : \"\");\n \tadd_var(&script_snippet, \"keep_empty\", opts->keep_empty ? \"yes\" : \"\");\n \tadd_var(&script_snippet, \"autosquash\", opts->autosquash ? \"t\" : \"\");\n \tadd_var(&script_snippet, \"gpg_sign_opt\", opts->gpg_sign_opt);\n@@ -1007,7 +1007,6 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \t\t.type = REBASE_UNSPECIFIED,\n \t\t.flags = REBASE_NO_QUIET,\n \t\t.git_am_opts = ARGV_ARRAY_INIT,\n-\t\t.allow_rerere_autoupdate  = -1,\n \t\t.allow_empty_message = 1,\n \t\t.git_format_patch_opt = STRBUF_INIT,\n \t};\n@@ -1101,10 +1100,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \t\tOPT_SET_INT('p', \"preserve-merges\", &options.type,\n \t\t\t    N_(\"try to recreate merges instead of ignoring \"\n \t\t\t       \"them\"), REBASE_PRESERVE_MERGES),\n-\t\tOPT_BOOL(0, \"rerere-autoupdate\",\n-\t\t\t &options.allow_rerere_autoupdate,\n-\t\t\t N_(\"allow rerere to update index with resolved \"\n-\t\t\t    \"conflict\")),\n+\t\tOPT_RERERE_AUTOUPDATE(&options.allow_rerere_autoupdate),\n \t\tOPT_BOOL('k', \"keep-empty\", &options.keep_empty,\n \t\t\t N_(\"preserve empty commits during rebase\")),\n \t\tOPT_BOOL(0, \"autosquash\", &options.autosquash,\n-- \n2.21.0\n\n"},{"id":"374041","messageId":"20190417143044.17655-3-phillip.wood123@gmail.com","threadId":"50780","inReplyTo":"20190417143044.17655-1-phillip.wood123@gmail.com","subject":"[PATCH v1 02/12] rebase: don't translate trace strings","fromName":"Phillip Wood","fromEmail":"phillip.wood123@gmail.com","sentAt":"2019-04-17T14:30:34Z","receivedAt":"2019-04-17T14:33:06Z","isPatch":true,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"From: Phillip Wood <phillip.wood@dunelm.org.uk>\n\ncommit b3a5d5a80c (\"trace2:data: add subverb for rebase\", 2019-02-22)\nmistakenly marked the subverb names for translation and unnecessarily\nNULL terminated the array.\n\nSigned-off-by: Phillip Wood <phillip.wood@dunelm.org.uk>\n---\n builtin/rebase.c | 15 +++++++--------\n 1 file changed, 7 insertions(+), 8 deletions(-)\n\ndiff --git a/builtin/rebase.c b/builtin/rebase.c\nindex 52114cbf0d..239a54ecfe 100644\n--- a/builtin/rebase.c\n+++ b/builtin/rebase.c\n@@ -1027,14 +1027,13 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \t\tACTION_EDIT_TODO,\n \t\tACTION_SHOW_CURRENT_PATCH,\n \t} action = NO_ACTION;\n-\tstatic const char *action_names[] = { N_(\"undefined\"),\n-\t\t\t\t\t      N_(\"continue\"),\n-\t\t\t\t\t      N_(\"skip\"),\n-\t\t\t\t\t      N_(\"abort\"),\n-\t\t\t\t\t      N_(\"quit\"),\n-\t\t\t\t\t      N_(\"edit_todo\"),\n-\t\t\t\t\t      N_(\"show_current_patch\"),\n-\t\t\t\t\t      NULL };\n+\tstatic const char *action_names[] = { \"undefined\",\n+\t\t\t\t\t      \"continue\",\n+\t\t\t\t\t      \"skip\",\n+\t\t\t\t\t      \"abort\",\n+\t\t\t\t\t      \"quit\",\n+\t\t\t\t\t      \"edit_todo\",\n+\t\t\t\t\t      \"show_current_patch\" };\n \tconst char *gpg_sign = NULL;\n \tstruct string_list exec = STRING_LIST_INIT_NODUP;\n \tconst char *rebase_merges = NULL;\n-- \n2.21.0\n\n"},{"id":"374042","messageId":"20190417143044.17655-6-phillip.wood123@gmail.com","threadId":"50780","inReplyTo":"20190417143044.17655-1-phillip.wood123@gmail.com","subject":"[PATCH v1 05/12] rebase -i: combine rebase--interactive.c with rebase.c","fromName":"Phillip Wood","fromEmail":"phillip.wood123@gmail.com","sentAt":"2019-04-17T14:30:37Z","receivedAt":"2019-04-17T14:33:08Z","isPatch":true,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"From: Phillip Wood <phillip.wood@dunelm.org.uk>\n\nIn order to run `rebase -i` without forking `rebase--interactive` it\nwill be convenient to have all the code from rebase--interactive.c in\nrebase.c. This is a straight forward copy of the code from\nrebase--interactive.c, it will be simplified slightly in the next\ncommit.\n\nSigned-off-by: Phillip Wood <phillip.wood@dunelm.org.uk>\n---\n Makefile                      |   1 -\n builtin/rebase--interactive.c | 377 ----------------------------------\n builtin/rebase.c              | 367 +++++++++++++++++++++++++++++++++\n 3 files changed, 367 insertions(+), 378 deletions(-)\n delete mode 100644 builtin/rebase--interactive.c\n\ndiff --git a/Makefile b/Makefile\nindex 537493822b..c644089244 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -1130,7 +1130,6 @@ BUILTIN_OBJS += builtin/push.o\n BUILTIN_OBJS += builtin/range-diff.o\n BUILTIN_OBJS += builtin/read-tree.o\n BUILTIN_OBJS += builtin/rebase.o\n-BUILTIN_OBJS += builtin/rebase--interactive.o\n BUILTIN_OBJS += builtin/receive-pack.o\n BUILTIN_OBJS += builtin/reflog.o\n BUILTIN_OBJS += builtin/remote.o\ndiff --git a/builtin/rebase--interactive.c b/builtin/rebase--interactive.c\ndeleted file mode 100644\nindex d1a4ac1b84..0000000000\n--- a/builtin/rebase--interactive.c\n+++ /dev/null\n@@ -1,377 +0,0 @@\n-#define USE_THE_INDEX_COMPATIBILITY_MACROS\n-#include \"builtin.h\"\n-#include \"cache.h\"\n-#include \"config.h\"\n-#include \"parse-options.h\"\n-#include \"sequencer.h\"\n-#include \"rebase-interactive.h\"\n-#include \"argv-array.h\"\n-#include \"refs.h\"\n-#include \"rerere.h\"\n-#include \"run-command.h\"\n-\n-static GIT_PATH_FUNC(path_state_dir, \"rebase-merge/\")\n-static GIT_PATH_FUNC(path_squash_onto, \"rebase-merge/squash-onto\")\n-static GIT_PATH_FUNC(path_interactive, \"rebase-merge/interactive\")\n-\n-static int add_exec_commands(struct string_list *commands)\n-{\n-\tconst char *todo_file = rebase_path_todo();\n-\tstruct todo_list todo_list = TODO_LIST_INIT;\n-\tint res;\n-\n-\tif (strbuf_read_file(&todo_list.buf, todo_file, 0) < 0)\n-\t\treturn error_errno(_(\"could not read '%s'.\"), todo_file);\n-\n-\tif (todo_list_parse_insn_buffer(the_repository, todo_list.buf.buf,\n-\t\t\t\t\t&todo_list)) {\n-\t\ttodo_list_release(&todo_list);\n-\t\treturn error(_(\"unusable todo list: '%s'\"), todo_file);\n-\t}\n-\n-\ttodo_list_add_exec_commands(&todo_list, commands);\n-\tres = todo_list_write_to_file(the_repository, &todo_list,\n-\t\t\t\t      todo_file, NULL, NULL, -1, 0);\n-\ttodo_list_release(&todo_list);\n-\n-\tif (res)\n-\t\treturn error_errno(_(\"could not write '%s'.\"), todo_file);\n-\treturn 0;\n-}\n-\n-static int rearrange_squash_in_todo_file(void)\n-{\n-\tconst char *todo_file = rebase_path_todo();\n-\tstruct todo_list todo_list = TODO_LIST_INIT;\n-\tint res = 0;\n-\n-\tif (strbuf_read_file(&todo_list.buf, todo_file, 0) < 0)\n-\t\treturn error_errno(_(\"could not read '%s'.\"), todo_file);\n-\tif (todo_list_parse_insn_buffer(the_repository, todo_list.buf.buf,\n-\t\t\t\t\t&todo_list)) {\n-\t\ttodo_list_release(&todo_list);\n-\t\treturn error(_(\"unusable todo list: '%s'\"), todo_file);\n-\t}\n-\n-\tres = todo_list_rearrange_squash(&todo_list);\n-\tif (!res)\n-\t\tres = todo_list_write_to_file(the_repository, &todo_list,\n-\t\t\t\t\t      todo_file, NULL, NULL, -1, 0);\n-\n-\ttodo_list_release(&todo_list);\n-\n-\tif (res)\n-\t\treturn error_errno(_(\"could not write '%s'.\"), todo_file);\n-\treturn 0;\n-}\n-\n-static int transform_todo_file(unsigned flags)\n-{\n-\tconst char *todo_file = rebase_path_todo();\n-\tstruct todo_list todo_list = TODO_LIST_INIT;\n-\tint res;\n-\n-\tif (strbuf_read_file(&todo_list.buf, todo_file, 0) < 0)\n-\t\treturn error_errno(_(\"could not read '%s'.\"), todo_file);\n-\n-\tif (todo_list_parse_insn_buffer(the_repository, todo_list.buf.buf,\n-\t\t\t\t\t&todo_list)) {\n-\t\ttodo_list_release(&todo_list);\n-\t\treturn error(_(\"unusable todo list: '%s'\"), todo_file);\n-\t}\n-\n-\tres = todo_list_write_to_file(the_repository, &todo_list, todo_file,\n-\t\t\t\t      NULL, NULL, -1, flags);\n-\ttodo_list_release(&todo_list);\n-\n-\tif (res)\n-\t\treturn error_errno(_(\"could not write '%s'.\"), todo_file);\n-\treturn 0;\n-}\n-\n-static int edit_todo_file(unsigned flags)\n-{\n-\tconst char *todo_file = rebase_path_todo();\n-\tstruct todo_list todo_list = TODO_LIST_INIT,\n-\t\tnew_todo = TODO_LIST_INIT;\n-\tint res = 0;\n-\n-\tif (strbuf_read_file(&todo_list.buf, todo_file, 0) < 0)\n-\t\treturn error_errno(_(\"could not read '%s'.\"), todo_file);\n-\n-\tstrbuf_stripspace(&todo_list.buf, 1);\n-\tres = edit_todo_list(the_repository, &todo_list, &new_todo, NULL, NULL, flags);\n-\tif (!res && todo_list_write_to_file(the_repository, &new_todo, todo_file,\n-\t\t\t\t\t    NULL, NULL, -1, flags & ~(TODO_LIST_SHORTEN_IDS)))\n-\t\tres = error_errno(_(\"could not write '%s'\"), todo_file);\n-\n-\ttodo_list_release(&todo_list);\n-\ttodo_list_release(&new_todo);\n-\n-\treturn res;\n-}\n-\n-static int get_revision_ranges(const char *upstream, const char *onto,\n-\t\t\t       const char **head_hash,\n-\t\t\t       char **revisions, char **shortrevisions)\n-{\n-\tconst char *base_rev = upstream ? upstream : onto, *shorthead;\n-\tstruct object_id orig_head;\n-\n-\tif (get_oid(\"HEAD\", &orig_head))\n-\t\treturn error(_(\"no HEAD?\"));\n-\n-\t*head_hash = find_unique_abbrev(&orig_head, GIT_MAX_HEXSZ);\n-\t*revisions = xstrfmt(\"%s...%s\", base_rev, *head_hash);\n-\n-\tshorthead = find_unique_abbrev(&orig_head, DEFAULT_ABBREV);\n-\n-\tif (upstream) {\n-\t\tconst char *shortrev;\n-\t\tstruct object_id rev_oid;\n-\n-\t\tget_oid(base_rev, &rev_oid);\n-\t\tshortrev = find_unique_abbrev(&rev_oid, DEFAULT_ABBREV);\n-\n-\t\t*shortrevisions = xstrfmt(\"%s..%s\", shortrev, shorthead);\n-\t} else\n-\t\t*shortrevisions = xstrdup(shorthead);\n-\n-\treturn 0;\n-}\n-\n-static int init_basic_state(struct replay_opts *opts, const char *head_name,\n-\t\t\t    const char *onto, const char *orig_head)\n-{\n-\tFILE *interactive;\n-\n-\tif (!is_directory(path_state_dir()) && mkdir_in_gitdir(path_state_dir()))\n-\t\treturn error_errno(_(\"could not create temporary %s\"), path_state_dir());\n-\n-\tdelete_reflog(\"REBASE_HEAD\");\n-\n-\tinteractive = fopen(path_interactive(), \"w\");\n-\tif (!interactive)\n-\t\treturn error_errno(_(\"could not mark as interactive\"));\n-\tfclose(interactive);\n-\n-\treturn write_basic_state(opts, head_name, onto, orig_head);\n-}\n-\n-static int do_interactive_rebase(struct replay_opts *opts, unsigned flags,\n-\t\t\t\t const char *switch_to, const char *upstream,\n-\t\t\t\t const char *onto, const char *onto_name,\n-\t\t\t\t const char *squash_onto, const char *head_name,\n-\t\t\t\t const char *restrict_revision, char *raw_strategies,\n-\t\t\t\t struct string_list *commands, unsigned autosquash)\n-{\n-\tint ret;\n-\tconst char *head_hash = NULL;\n-\tchar *revisions = NULL, *shortrevisions = NULL;\n-\tstruct argv_array make_script_args = ARGV_ARRAY_INIT;\n-\tstruct todo_list todo_list = TODO_LIST_INIT;\n-\n-\tif (prepare_branch_to_be_rebased(the_repository, opts, switch_to))\n-\t\treturn -1;\n-\n-\tif (get_revision_ranges(upstream, onto, &head_hash,\n-\t\t\t\t&revisions, &shortrevisions))\n-\t\treturn -1;\n-\n-\tif (raw_strategies)\n-\t\tparse_strategy_opts(opts, raw_strategies);\n-\n-\tif (init_basic_state(opts, head_name, onto, head_hash)) {\n-\t\tfree(revisions);\n-\t\tfree(shortrevisions);\n-\n-\t\treturn -1;\n-\t}\n-\n-\tif (!upstream && squash_onto)\n-\t\twrite_file(path_squash_onto(), \"%s\\n\", squash_onto);\n-\n-\targv_array_pushl(&make_script_args, \"\", revisions, NULL);\n-\tif (restrict_revision)\n-\t\targv_array_push(&make_script_args, restrict_revision);\n-\n-\tret = sequencer_make_script(the_repository, &todo_list.buf,\n-\t\t\t\t    make_script_args.argc, make_script_args.argv,\n-\t\t\t\t    flags);\n-\n-\tif (ret)\n-\t\terror(_(\"could not generate todo list\"));\n-\telse {\n-\t\tdiscard_cache();\n-\t\tif (todo_list_parse_insn_buffer(the_repository, todo_list.buf.buf,\n-\t\t\t\t\t\t&todo_list))\n-\t\t\tBUG(\"unusable todo list\");\n-\n-\t\tret = complete_action(the_repository, opts, flags, shortrevisions, onto_name,\n-\t\t\t\t      onto, head_hash, commands, autosquash, &todo_list);\n-\t}\n-\n-\tfree(revisions);\n-\tfree(shortrevisions);\n-\ttodo_list_release(&todo_list);\n-\targv_array_clear(&make_script_args);\n-\n-\treturn ret;\n-}\n-\n-static const char * const builtin_rebase_interactive_usage[] = {\n-\tN_(\"git rebase--interactive [<options>]\"),\n-\tNULL\n-};\n-\n-int cmd_rebase__interactive(int argc, const char **argv, const char *prefix)\n-{\n-\tstruct replay_opts opts = REPLAY_OPTS_INIT;\n-\tunsigned flags = 0, keep_empty = 0, rebase_merges = 0, autosquash = 0;\n-\tint abbreviate_commands = 0, rebase_cousins = -1, ret = 0;\n-\tconst char *onto = NULL, *onto_name = NULL, *restrict_revision = NULL,\n-\t\t*squash_onto = NULL, *upstream = NULL, *head_name = NULL,\n-\t\t*switch_to = NULL, *cmd = NULL;\n-\tstruct string_list commands = STRING_LIST_INIT_DUP;\n-\tchar *raw_strategies = NULL;\n-\tenum {\n-\t\tNONE = 0, CONTINUE, SKIP, EDIT_TODO, SHOW_CURRENT_PATCH,\n-\t\tSHORTEN_OIDS, EXPAND_OIDS, CHECK_TODO_LIST, REARRANGE_SQUASH, ADD_EXEC\n-\t} command = 0;\n-\tstruct option options[] = {\n-\t\tOPT_BOOL(0, \"ff\", &opts.allow_ff, N_(\"allow fast-forward\")),\n-\t\tOPT_BOOL(0, \"keep-empty\", &keep_empty, N_(\"keep empty commits\")),\n-\t\tOPT_BOOL(0, \"allow-empty-message\", &opts.allow_empty_message,\n-\t\t\t N_(\"allow commits with empty messages\")),\n-\t\tOPT_BOOL(0, \"rebase-merges\", &rebase_merges, N_(\"rebase merge commits\")),\n-\t\tOPT_BOOL(0, \"rebase-cousins\", &rebase_cousins,\n-\t\t\t N_(\"keep original branch points of cousins\")),\n-\t\tOPT_BOOL(0, \"autosquash\", &autosquash,\n-\t\t\t N_(\"move commits that begin with squash!/fixup!\")),\n-\t\tOPT_BOOL(0, \"signoff\", &opts.signoff, N_(\"sign commits\")),\n-\t\tOPT__VERBOSE(&opts.verbose, N_(\"be verbose\")),\n-\t\tOPT_CMDMODE(0, \"continue\", &command, N_(\"continue rebase\"),\n-\t\t\t    CONTINUE),\n-\t\tOPT_CMDMODE(0, \"skip\", &command, N_(\"skip commit\"), SKIP),\n-\t\tOPT_CMDMODE(0, \"edit-todo\", &command, N_(\"edit the todo list\"),\n-\t\t\t    EDIT_TODO),\n-\t\tOPT_CMDMODE(0, \"show-current-patch\", &command, N_(\"show the current patch\"),\n-\t\t\t    SHOW_CURRENT_PATCH),\n-\t\tOPT_CMDMODE(0, \"shorten-ids\", &command,\n-\t\t\tN_(\"shorten commit ids in the todo list\"), SHORTEN_OIDS),\n-\t\tOPT_CMDMODE(0, \"expand-ids\", &command,\n-\t\t\tN_(\"expand commit ids in the todo list\"), EXPAND_OIDS),\n-\t\tOPT_CMDMODE(0, \"check-todo-list\", &command,\n-\t\t\tN_(\"check the todo list\"), CHECK_TODO_LIST),\n-\t\tOPT_CMDMODE(0, \"rearrange-squash\", &command,\n-\t\t\tN_(\"rearrange fixup/squash lines\"), REARRANGE_SQUASH),\n-\t\tOPT_CMDMODE(0, \"add-exec-commands\", &command,\n-\t\t\tN_(\"insert exec commands in todo list\"), ADD_EXEC),\n-\t\tOPT_STRING(0, \"onto\", &onto, N_(\"onto\"), N_(\"onto\")),\n-\t\tOPT_STRING(0, \"restrict-revision\", &restrict_revision,\n-\t\t\t   N_(\"restrict-revision\"), N_(\"restrict revision\")),\n-\t\tOPT_STRING(0, \"squash-onto\", &squash_onto, N_(\"squash-onto\"),\n-\t\t\t   N_(\"squash onto\")),\n-\t\tOPT_STRING(0, \"upstream\", &upstream, N_(\"upstream\"),\n-\t\t\t   N_(\"the upstream commit\")),\n-\t\tOPT_STRING(0, \"head-name\", &head_name, N_(\"head-name\"), N_(\"head name\")),\n-\t\t{ OPTION_STRING, 'S', \"gpg-sign\", &opts.gpg_sign, N_(\"key-id\"),\n-\t\t\tN_(\"GPG-sign commits\"),\n-\t\t\tPARSE_OPT_OPTARG, NULL, (intptr_t) \"\" },\n-\t\tOPT_STRING(0, \"strategy\", &opts.strategy, N_(\"strategy\"),\n-\t\t\t   N_(\"rebase strategy\")),\n-\t\tOPT_STRING(0, \"strategy-opts\", &raw_strategies, N_(\"strategy-opts\"),\n-\t\t\t   N_(\"strategy options\")),\n-\t\tOPT_STRING(0, \"switch-to\", &switch_to, N_(\"switch-to\"),\n-\t\t\t   N_(\"the branch or commit to checkout\")),\n-\t\tOPT_STRING(0, \"onto-name\", &onto_name, N_(\"onto-name\"), N_(\"onto name\")),\n-\t\tOPT_STRING(0, \"cmd\", &cmd, N_(\"cmd\"), N_(\"the command to run\")),\n-\t\tOPT_RERERE_AUTOUPDATE(&opts.allow_rerere_auto),\n-\t\tOPT_BOOL(0, \"reschedule-failed-exec\", &opts.reschedule_failed_exec,\n-\t\t\t N_(\"automatically re-schedule any `exec` that fails\")),\n-\t\tOPT_END()\n-\t};\n-\n-\tsequencer_init_config(&opts);\n-\tgit_config_get_bool(\"rebase.abbreviatecommands\", &abbreviate_commands);\n-\n-\topts.action = REPLAY_INTERACTIVE_REBASE;\n-\topts.allow_ff = 1;\n-\topts.allow_empty = 1;\n-\n-\tif (argc == 1)\n-\t\tusage_with_options(builtin_rebase_interactive_usage, options);\n-\n-\targc = parse_options(argc, argv, NULL, options,\n-\t\t\tbuiltin_rebase_interactive_usage, PARSE_OPT_KEEP_ARGV0);\n-\n-\topts.gpg_sign = xstrdup_or_null(opts.gpg_sign);\n-\n-\tflags |= keep_empty ? TODO_LIST_KEEP_EMPTY : 0;\n-\tflags |= abbreviate_commands ? TODO_LIST_ABBREVIATE_CMDS : 0;\n-\tflags |= rebase_merges ? TODO_LIST_REBASE_MERGES : 0;\n-\tflags |= rebase_cousins > 0 ? TODO_LIST_REBASE_COUSINS : 0;\n-\tflags |= command == SHORTEN_OIDS ? TODO_LIST_SHORTEN_IDS : 0;\n-\n-\tif (rebase_cousins >= 0 && !rebase_merges)\n-\t\twarning(_(\"--[no-]rebase-cousins has no effect without \"\n-\t\t\t  \"--rebase-merges\"));\n-\n-\tif (cmd && *cmd) {\n-\t\tstring_list_split(&commands, cmd, '\\n', -1);\n-\n-\t\t/* rebase.c adds a new line to cmd after every command,\n-\t\t * so here the last command is always empty */\n-\t\tstring_list_remove_empty_items(&commands, 0);\n-\t}\n-\n-\tswitch (command) {\n-\tcase NONE:\n-\t\tif (!onto && !upstream)\n-\t\t\tdie(_(\"a base commit must be provided with --upstream or --onto\"));\n-\n-\t\tret = do_interactive_rebase(&opts, flags, switch_to, upstream, onto,\n-\t\t\t\t\t    onto_name, squash_onto, head_name, restrict_revision,\n-\t\t\t\t\t    raw_strategies, &commands, autosquash);\n-\t\tbreak;\n-\tcase SKIP: {\n-\t\tstruct string_list merge_rr = STRING_LIST_INIT_DUP;\n-\n-\t\trerere_clear(the_repository, &merge_rr);\n-\t\t/* fallthrough */\n-\tcase CONTINUE:\n-\t\tret = sequencer_continue(the_repository, &opts);\n-\t\tbreak;\n-\t}\n-\tcase EDIT_TODO:\n-\t\tret = edit_todo_file(flags);\n-\t\tbreak;\n-\tcase SHOW_CURRENT_PATCH: {\n-\t\tstruct child_process cmd = CHILD_PROCESS_INIT;\n-\n-\t\tcmd.git_cmd = 1;\n-\t\targv_array_pushl(&cmd.args, \"show\", \"REBASE_HEAD\", \"--\", NULL);\n-\t\tret = run_command(&cmd);\n-\n-\t\tbreak;\n-\t}\n-\tcase SHORTEN_OIDS:\n-\tcase EXPAND_OIDS:\n-\t\tret = transform_todo_file(flags);\n-\t\tbreak;\n-\tcase CHECK_TODO_LIST:\n-\t\tret = check_todo_list_from_file(the_repository);\n-\t\tbreak;\n-\tcase REARRANGE_SQUASH:\n-\t\tret = rearrange_squash_in_todo_file();\n-\t\tbreak;\n-\tcase ADD_EXEC:\n-\t\tret = add_exec_commands(&commands);\n-\t\tbreak;\n-\tdefault:\n-\t\tBUG(\"invalid command '%d'\", command);\n-\t}\n-\n-\tstring_list_clear(&commands, 0);\n-\treturn !!ret;\n-}\ndiff --git a/builtin/rebase.c b/builtin/rebase.c\nindex e7b8122003..57a3c9caf1 100644\n--- a/builtin/rebase.c\n+++ b/builtin/rebase.c\n@@ -25,6 +25,8 @@\n #include \"commit-reach.h\"\n #include \"rerere.h\"\n #include \"branch.h\"\n+#include \"sequencer.h\"\n+#include \"rebase-interactive.h\"\n \n static char const * const builtin_rebase_usage[] = {\n \tN_(\"git rebase [-i] [options] [--exec <cmd>] [--onto <newbase>] \"\n@@ -35,6 +37,9 @@ static char const * const builtin_rebase_usage[] = {\n \tNULL\n };\n \n+static GIT_PATH_FUNC(path_state_dir, \"rebase-merge/\")\n+static GIT_PATH_FUNC(path_squash_onto, \"rebase-merge/squash-onto\")\n+static GIT_PATH_FUNC(path_interactive, \"rebase-merge/interactive\")\n static GIT_PATH_FUNC(apply_dir, \"rebase-apply\")\n static GIT_PATH_FUNC(merge_dir, \"rebase-merge\")\n \n@@ -46,6 +51,368 @@ enum rebase_type {\n \tREBASE_PRESERVE_MERGES\n };\n \n+static int add_exec_commands(struct string_list *commands)\n+{\n+\tconst char *todo_file = rebase_path_todo();\n+\tstruct todo_list todo_list = TODO_LIST_INIT;\n+\tint res;\n+\n+\tif (strbuf_read_file(&todo_list.buf, todo_file, 0) < 0)\n+\t\treturn error_errno(_(\"could not read '%s'.\"), todo_file);\n+\n+\tif (todo_list_parse_insn_buffer(the_repository, todo_list.buf.buf,\n+\t\t\t\t\t&todo_list)) {\n+\t\ttodo_list_release(&todo_list);\n+\t\treturn error(_(\"unusable todo list: '%s'\"), todo_file);\n+\t}\n+\n+\ttodo_list_add_exec_commands(&todo_list, commands);\n+\tres = todo_list_write_to_file(the_repository, &todo_list,\n+\t\t\t\t      todo_file, NULL, NULL, -1, 0);\n+\ttodo_list_release(&todo_list);\n+\n+\tif (res)\n+\t\treturn error_errno(_(\"could not write '%s'.\"), todo_file);\n+\treturn 0;\n+}\n+\n+static int rearrange_squash_in_todo_file(void)\n+{\n+\tconst char *todo_file = rebase_path_todo();\n+\tstruct todo_list todo_list = TODO_LIST_INIT;\n+\tint res = 0;\n+\n+\tif (strbuf_read_file(&todo_list.buf, todo_file, 0) < 0)\n+\t\treturn error_errno(_(\"could not read '%s'.\"), todo_file);\n+\tif (todo_list_parse_insn_buffer(the_repository, todo_list.buf.buf,\n+\t\t\t\t\t&todo_list)) {\n+\t\ttodo_list_release(&todo_list);\n+\t\treturn error(_(\"unusable todo list: '%s'\"), todo_file);\n+\t}\n+\n+\tres = todo_list_rearrange_squash(&todo_list);\n+\tif (!res)\n+\t\tres = todo_list_write_to_file(the_repository, &todo_list,\n+\t\t\t\t\t      todo_file, NULL, NULL, -1, 0);\n+\n+\ttodo_list_release(&todo_list);\n+\n+\tif (res)\n+\t\treturn error_errno(_(\"could not write '%s'.\"), todo_file);\n+\treturn 0;\n+}\n+\n+static int transform_todo_file(unsigned flags)\n+{\n+\tconst char *todo_file = rebase_path_todo();\n+\tstruct todo_list todo_list = TODO_LIST_INIT;\n+\tint res;\n+\n+\tif (strbuf_read_file(&todo_list.buf, todo_file, 0) < 0)\n+\t\treturn error_errno(_(\"could not read '%s'.\"), todo_file);\n+\n+\tif (todo_list_parse_insn_buffer(the_repository, todo_list.buf.buf,\n+\t\t\t\t\t&todo_list)) {\n+\t\ttodo_list_release(&todo_list);\n+\t\treturn error(_(\"unusable todo list: '%s'\"), todo_file);\n+\t}\n+\n+\tres = todo_list_write_to_file(the_repository, &todo_list, todo_file,\n+\t\t\t\t      NULL, NULL, -1, flags);\n+\ttodo_list_release(&todo_list);\n+\n+\tif (res)\n+\t\treturn error_errno(_(\"could not write '%s'.\"), todo_file);\n+\treturn 0;\n+}\n+\n+static int edit_todo_file(unsigned flags)\n+{\n+\tconst char *todo_file = rebase_path_todo();\n+\tstruct todo_list todo_list = TODO_LIST_INIT,\n+\t\tnew_todo = TODO_LIST_INIT;\n+\tint res = 0;\n+\n+\tif (strbuf_read_file(&todo_list.buf, todo_file, 0) < 0)\n+\t\treturn error_errno(_(\"could not read '%s'.\"), todo_file);\n+\n+\tstrbuf_stripspace(&todo_list.buf, 1);\n+\tres = edit_todo_list(the_repository, &todo_list, &new_todo, NULL, NULL, flags);\n+\tif (!res && todo_list_write_to_file(the_repository, &new_todo, todo_file,\n+\t\t\t\t\t    NULL, NULL, -1, flags & ~(TODO_LIST_SHORTEN_IDS)))\n+\t\tres = error_errno(_(\"could not write '%s'\"), todo_file);\n+\n+\ttodo_list_release(&todo_list);\n+\ttodo_list_release(&new_todo);\n+\n+\treturn res;\n+}\n+\n+static int get_revision_ranges(const char *upstream, const char *onto,\n+\t\t\t       const char **head_hash,\n+\t\t\t       char **revisions, char **shortrevisions)\n+{\n+\tconst char *base_rev = upstream ? upstream : onto, *shorthead;\n+\tstruct object_id orig_head;\n+\n+\tif (get_oid(\"HEAD\", &orig_head))\n+\t\treturn error(_(\"no HEAD?\"));\n+\n+\t*head_hash = find_unique_abbrev(&orig_head, GIT_MAX_HEXSZ);\n+\t*revisions = xstrfmt(\"%s...%s\", base_rev, *head_hash);\n+\n+\tshorthead = find_unique_abbrev(&orig_head, DEFAULT_ABBREV);\n+\n+\tif (upstream) {\n+\t\tconst char *shortrev;\n+\t\tstruct object_id rev_oid;\n+\n+\t\tget_oid(base_rev, &rev_oid);\n+\t\tshortrev = find_unique_abbrev(&rev_oid, DEFAULT_ABBREV);\n+\n+\t\t*shortrevisions = xstrfmt(\"%s..%s\", shortrev, shorthead);\n+\t} else\n+\t\t*shortrevisions = xstrdup(shorthead);\n+\n+\treturn 0;\n+}\n+\n+static int init_basic_state(struct replay_opts *opts, const char *head_name,\n+\t\t\t    const char *onto, const char *orig_head)\n+{\n+\tFILE *interactive;\n+\n+\tif (!is_directory(path_state_dir()) && mkdir_in_gitdir(path_state_dir()))\n+\t\treturn error_errno(_(\"could not create temporary %s\"), path_state_dir());\n+\n+\tdelete_reflog(\"REBASE_HEAD\");\n+\n+\tinteractive = fopen(path_interactive(), \"w\");\n+\tif (!interactive)\n+\t\treturn error_errno(_(\"could not mark as interactive\"));\n+\tfclose(interactive);\n+\n+\treturn write_basic_state(opts, head_name, onto, orig_head);\n+}\n+\n+static int do_interactive_rebase(struct replay_opts *opts, unsigned flags,\n+\t\t\t\t const char *switch_to, const char *upstream,\n+\t\t\t\t const char *onto, const char *onto_name,\n+\t\t\t\t const char *squash_onto, const char *head_name,\n+\t\t\t\t const char *restrict_revision, char *raw_strategies,\n+\t\t\t\t struct string_list *commands, unsigned autosquash)\n+{\n+\tint ret;\n+\tconst char *head_hash = NULL;\n+\tchar *revisions = NULL, *shortrevisions = NULL;\n+\tstruct argv_array make_script_args = ARGV_ARRAY_INIT;\n+\tstruct todo_list todo_list = TODO_LIST_INIT;\n+\n+\tif (prepare_branch_to_be_rebased(the_repository, opts, switch_to))\n+\t\treturn -1;\n+\n+\tif (get_revision_ranges(upstream, onto, &head_hash,\n+\t\t\t\t&revisions, &shortrevisions))\n+\t\treturn -1;\n+\n+\tif (raw_strategies)\n+\t\tparse_strategy_opts(opts, raw_strategies);\n+\n+\tif (init_basic_state(opts, head_name, onto, head_hash)) {\n+\t\tfree(revisions);\n+\t\tfree(shortrevisions);\n+\n+\t\treturn -1;\n+\t}\n+\n+\tif (!upstream && squash_onto)\n+\t\twrite_file(path_squash_onto(), \"%s\\n\", squash_onto);\n+\n+\targv_array_pushl(&make_script_args, \"\", revisions, NULL);\n+\tif (restrict_revision)\n+\t\targv_array_push(&make_script_args, restrict_revision);\n+\n+\tret = sequencer_make_script(the_repository, &todo_list.buf,\n+\t\t\t\t    make_script_args.argc, make_script_args.argv,\n+\t\t\t\t    flags);\n+\n+\tif (ret)\n+\t\terror(_(\"could not generate todo list\"));\n+\telse {\n+\t\tdiscard_cache();\n+\t\tif (todo_list_parse_insn_buffer(the_repository, todo_list.buf.buf,\n+\t\t\t\t\t\t&todo_list))\n+\t\t\tBUG(\"unusable todo list\");\n+\n+\t\tret = complete_action(the_repository, opts, flags, shortrevisions, onto_name,\n+\t\t\t\t      onto, head_hash, commands, autosquash, &todo_list);\n+\t}\n+\n+\tfree(revisions);\n+\tfree(shortrevisions);\n+\ttodo_list_release(&todo_list);\n+\targv_array_clear(&make_script_args);\n+\n+\treturn ret;\n+}\n+\n+static const char * const builtin_rebase_interactive_usage[] = {\n+\tN_(\"git rebase--interactive [<options>]\"),\n+\tNULL\n+};\n+\n+int cmd_rebase__interactive(int argc, const char **argv, const char *prefix)\n+{\n+\tstruct replay_opts opts = REPLAY_OPTS_INIT;\n+\tunsigned flags = 0, keep_empty = 0, rebase_merges = 0, autosquash = 0;\n+\tint abbreviate_commands = 0, rebase_cousins = -1, ret = 0;\n+\tconst char *onto = NULL, *onto_name = NULL, *restrict_revision = NULL,\n+\t\t*squash_onto = NULL, *upstream = NULL, *head_name = NULL,\n+\t\t*switch_to = NULL, *cmd = NULL;\n+\tstruct string_list commands = STRING_LIST_INIT_DUP;\n+\tchar *raw_strategies = NULL;\n+\tenum {\n+\t\tNONE = 0, CONTINUE, SKIP, EDIT_TODO, SHOW_CURRENT_PATCH,\n+\t\tSHORTEN_OIDS, EXPAND_OIDS, CHECK_TODO_LIST, REARRANGE_SQUASH, ADD_EXEC\n+\t} command = 0;\n+\tstruct option options[] = {\n+\t\tOPT_BOOL(0, \"ff\", &opts.allow_ff, N_(\"allow fast-forward\")),\n+\t\tOPT_BOOL(0, \"keep-empty\", &keep_empty, N_(\"keep empty commits\")),\n+\t\tOPT_BOOL(0, \"allow-empty-message\", &opts.allow_empty_message,\n+\t\t\t N_(\"allow commits with empty messages\")),\n+\t\tOPT_BOOL(0, \"rebase-merges\", &rebase_merges, N_(\"rebase merge commits\")),\n+\t\tOPT_BOOL(0, \"rebase-cousins\", &rebase_cousins,\n+\t\t\t N_(\"keep original branch points of cousins\")),\n+\t\tOPT_BOOL(0, \"autosquash\", &autosquash,\n+\t\t\t N_(\"move commits that begin with squash!/fixup!\")),\n+\t\tOPT_BOOL(0, \"signoff\", &opts.signoff, N_(\"sign commits\")),\n+\t\tOPT__VERBOSE(&opts.verbose, N_(\"be verbose\")),\n+\t\tOPT_CMDMODE(0, \"continue\", &command, N_(\"continue rebase\"),\n+\t\t\t    CONTINUE),\n+\t\tOPT_CMDMODE(0, \"skip\", &command, N_(\"skip commit\"), SKIP),\n+\t\tOPT_CMDMODE(0, \"edit-todo\", &command, N_(\"edit the todo list\"),\n+\t\t\t    EDIT_TODO),\n+\t\tOPT_CMDMODE(0, \"show-current-patch\", &command, N_(\"show the current patch\"),\n+\t\t\t    SHOW_CURRENT_PATCH),\n+\t\tOPT_CMDMODE(0, \"shorten-ids\", &command,\n+\t\t\tN_(\"shorten commit ids in the todo list\"), SHORTEN_OIDS),\n+\t\tOPT_CMDMODE(0, \"expand-ids\", &command,\n+\t\t\tN_(\"expand commit ids in the todo list\"), EXPAND_OIDS),\n+\t\tOPT_CMDMODE(0, \"check-todo-list\", &command,\n+\t\t\tN_(\"check the todo list\"), CHECK_TODO_LIST),\n+\t\tOPT_CMDMODE(0, \"rearrange-squash\", &command,\n+\t\t\tN_(\"rearrange fixup/squash lines\"), REARRANGE_SQUASH),\n+\t\tOPT_CMDMODE(0, \"add-exec-commands\", &command,\n+\t\t\tN_(\"insert exec commands in todo list\"), ADD_EXEC),\n+\t\tOPT_STRING(0, \"onto\", &onto, N_(\"onto\"), N_(\"onto\")),\n+\t\tOPT_STRING(0, \"restrict-revision\", &restrict_revision,\n+\t\t\t   N_(\"restrict-revision\"), N_(\"restrict revision\")),\n+\t\tOPT_STRING(0, \"squash-onto\", &squash_onto, N_(\"squash-onto\"),\n+\t\t\t   N_(\"squash onto\")),\n+\t\tOPT_STRING(0, \"upstream\", &upstream, N_(\"upstream\"),\n+\t\t\t   N_(\"the upstream commit\")),\n+\t\tOPT_STRING(0, \"head-name\", &head_name, N_(\"head-name\"), N_(\"head name\")),\n+\t\t{ OPTION_STRING, 'S', \"gpg-sign\", &opts.gpg_sign, N_(\"key-id\"),\n+\t\t\tN_(\"GPG-sign commits\"),\n+\t\t\tPARSE_OPT_OPTARG, NULL, (intptr_t) \"\" },\n+\t\tOPT_STRING(0, \"strategy\", &opts.strategy, N_(\"strategy\"),\n+\t\t\t   N_(\"rebase strategy\")),\n+\t\tOPT_STRING(0, \"strategy-opts\", &raw_strategies, N_(\"strategy-opts\"),\n+\t\t\t   N_(\"strategy options\")),\n+\t\tOPT_STRING(0, \"switch-to\", &switch_to, N_(\"switch-to\"),\n+\t\t\t   N_(\"the branch or commit to checkout\")),\n+\t\tOPT_STRING(0, \"onto-name\", &onto_name, N_(\"onto-name\"), N_(\"onto name\")),\n+\t\tOPT_STRING(0, \"cmd\", &cmd, N_(\"cmd\"), N_(\"the command to run\")),\n+\t\tOPT_RERERE_AUTOUPDATE(&opts.allow_rerere_auto),\n+\t\tOPT_BOOL(0, \"reschedule-failed-exec\", &opts.reschedule_failed_exec,\n+\t\t\t N_(\"automatically re-schedule any `exec` that fails\")),\n+\t\tOPT_END()\n+\t};\n+\n+\tsequencer_init_config(&opts);\n+\tgit_config_get_bool(\"rebase.abbreviatecommands\", &abbreviate_commands);\n+\n+\topts.action = REPLAY_INTERACTIVE_REBASE;\n+\topts.allow_ff = 1;\n+\topts.allow_empty = 1;\n+\n+\tif (argc == 1)\n+\t\tusage_with_options(builtin_rebase_interactive_usage, options);\n+\n+\targc = parse_options(argc, argv, NULL, options,\n+\t\t\tbuiltin_rebase_interactive_usage, PARSE_OPT_KEEP_ARGV0);\n+\n+\topts.gpg_sign = xstrdup_or_null(opts.gpg_sign);\n+\n+\tflags |= keep_empty ? TODO_LIST_KEEP_EMPTY : 0;\n+\tflags |= abbreviate_commands ? TODO_LIST_ABBREVIATE_CMDS : 0;\n+\tflags |= rebase_merges ? TODO_LIST_REBASE_MERGES : 0;\n+\tflags |= rebase_cousins > 0 ? TODO_LIST_REBASE_COUSINS : 0;\n+\tflags |= command == SHORTEN_OIDS ? TODO_LIST_SHORTEN_IDS : 0;\n+\n+\tif (rebase_cousins >= 0 && !rebase_merges)\n+\t\twarning(_(\"--[no-]rebase-cousins has no effect without \"\n+\t\t\t  \"--rebase-merges\"));\n+\n+\tif (cmd && *cmd) {\n+\t\tstring_list_split(&commands, cmd, '\\n', -1);\n+\n+\t\t/* rebase.c adds a new line to cmd after every command,\n+\t\t * so here the last command is always empty */\n+\t\tstring_list_remove_empty_items(&commands, 0);\n+\t}\n+\n+\tswitch (command) {\n+\tcase NONE:\n+\t\tif (!onto && !upstream)\n+\t\t\tdie(_(\"a base commit must be provided with --upstream or --onto\"));\n+\n+\t\tret = do_interactive_rebase(&opts, flags, switch_to, upstream, onto,\n+\t\t\t\t\t    onto_name, squash_onto, head_name, restrict_revision,\n+\t\t\t\t\t    raw_strategies, &commands, autosquash);\n+\t\tbreak;\n+\tcase SKIP: {\n+\t\tstruct string_list merge_rr = STRING_LIST_INIT_DUP;\n+\n+\t\trerere_clear(the_repository, &merge_rr);\n+\t\t/* fallthrough */\n+\tcase CONTINUE:\n+\t\tret = sequencer_continue(the_repository, &opts);\n+\t\tbreak;\n+\t}\n+\tcase EDIT_TODO:\n+\t\tret = edit_todo_file(flags);\n+\t\tbreak;\n+\tcase SHOW_CURRENT_PATCH: {\n+\t\tstruct child_process cmd = CHILD_PROCESS_INIT;\n+\n+\t\tcmd.git_cmd = 1;\n+\t\targv_array_pushl(&cmd.args, \"show\", \"REBASE_HEAD\", \"--\", NULL);\n+\t\tret = run_command(&cmd);\n+\n+\t\tbreak;\n+\t}\n+\tcase SHORTEN_OIDS:\n+\tcase EXPAND_OIDS:\n+\t\tret = transform_todo_file(flags);\n+\t\tbreak;\n+\tcase CHECK_TODO_LIST:\n+\t\tret = check_todo_list_from_file(the_repository);\n+\t\tbreak;\n+\tcase REARRANGE_SQUASH:\n+\t\tret = rearrange_squash_in_todo_file();\n+\t\tbreak;\n+\tcase ADD_EXEC:\n+\t\tret = add_exec_commands(&commands);\n+\t\tbreak;\n+\tdefault:\n+\t\tBUG(\"invalid command '%d'\", command);\n+\t}\n+\n+\tstring_list_clear(&commands, 0);\n+\treturn !!ret;\n+}\n+\n static int use_builtin_rebase(void)\n {\n \tstruct child_process cp = CHILD_PROCESS_INIT;\n-- \n2.21.0\n\n"},{"id":"374043","messageId":"20190417143044.17655-7-phillip.wood123@gmail.com","threadId":"50780","inReplyTo":"20190417143044.17655-1-phillip.wood123@gmail.com","subject":"[PATCH v1 06/12] rebase -i: remove duplication","fromName":"Phillip Wood","fromEmail":"phillip.wood123@gmail.com","sentAt":"2019-04-17T14:30:38Z","receivedAt":"2019-04-17T14:33:08Z","isPatch":true,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"From: Phillip Wood <phillip.wood@dunelm.org.uk>\n\npath_state_dir() and merge_dir() refer to the same path so remove one of\nthem.\n\nSigned-off-by: Phillip Wood <phillip.wood@dunelm.org.uk>\n---\n builtin/rebase.c | 5 ++---\n 1 file changed, 2 insertions(+), 3 deletions(-)\n\ndiff --git a/builtin/rebase.c b/builtin/rebase.c\nindex 57a3c9caf1..610b67827b 100644\n--- a/builtin/rebase.c\n+++ b/builtin/rebase.c\n@@ -37,7 +37,6 @@ static char const * const builtin_rebase_usage[] = {\n \tNULL\n };\n \n-static GIT_PATH_FUNC(path_state_dir, \"rebase-merge/\")\n static GIT_PATH_FUNC(path_squash_onto, \"rebase-merge/squash-onto\")\n static GIT_PATH_FUNC(path_interactive, \"rebase-merge/interactive\")\n static GIT_PATH_FUNC(apply_dir, \"rebase-apply\")\n@@ -182,8 +181,8 @@ static int init_basic_state(struct replay_opts *opts, const char *head_name,\n {\n \tFILE *interactive;\n \n-\tif (!is_directory(path_state_dir()) && mkdir_in_gitdir(path_state_dir()))\n-\t\treturn error_errno(_(\"could not create temporary %s\"), path_state_dir());\n+\tif (!is_directory(merge_dir()) && mkdir_in_gitdir(merge_dir()))\n+\t\treturn error_errno(_(\"could not create temporary %s\"), merge_dir());\n \n \tdelete_reflog(\"REBASE_HEAD\");\n \n-- \n2.21.0\n\n"},{"id":"374045","messageId":"20190417143044.17655-9-phillip.wood123@gmail.com","threadId":"50780","inReplyTo":"20190417143044.17655-1-phillip.wood123@gmail.com","subject":"[PATCH v1 08/12] rebase -i: use struct object_id for squash_onto","fromName":"Phillip Wood","fromEmail":"phillip.wood123@gmail.com","sentAt":"2019-04-17T14:30:40Z","receivedAt":"2019-04-17T14:33:11Z","isPatch":true,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"From: Phillip Wood <phillip.wood@dunelm.org.uk>\n\nMore preparation for using `struct rebase_options` in\ncmd_rebase__interactive(). Using a string was a hangover from the\nscripted version of rebase, update the functions that use `squash_onto`\nto take a `sturct object_id`.\n\nSigned-off-by: Phillip Wood <phillip.wood@dunelm.org.uk>\n---\n builtin/rebase.c   | 21 +++++++++++++--------\n parse-options-cb.c | 17 +++++++++++++++++\n parse-options.h    |  3 +++\n 3 files changed, 33 insertions(+), 8 deletions(-)\n\ndiff --git a/builtin/rebase.c b/builtin/rebase.c\nindex 06f6490ca3..3b9da69473 100644\n--- a/builtin/rebase.c\n+++ b/builtin/rebase.c\n@@ -198,7 +198,7 @@ static int init_basic_state(struct replay_opts *opts, const char *head_name,\n static int do_interactive_rebase(struct replay_opts *opts, unsigned flags,\n \t\t\t\t const char *switch_to, struct commit *upstream,\n \t\t\t\t struct commit *onto, const char *onto_name,\n-\t\t\t\t const char *squash_onto, const char *head_name,\n+\t\t\t\t struct object_id *squash_onto, const char *head_name,\n \t\t\t\t struct commit *restrict_revision, char *raw_strategies,\n \t\t\t\t struct string_list *commands, unsigned autosquash)\n {\n@@ -226,7 +226,8 @@ static int do_interactive_rebase(struct replay_opts *opts, unsigned flags,\n \t}\n \n \tif (!upstream && squash_onto)\n-\t\twrite_file(path_squash_onto(), \"%s\\n\", squash_onto);\n+\t\twrite_file(path_squash_onto(), \"%s\\n\",\n+\t\t\t   oid_to_hex(squash_onto));\n \n \targv_array_pushl(&make_script_args, \"\", revisions, NULL);\n \tif (restrict_revision)\n@@ -267,10 +268,11 @@ int cmd_rebase__interactive(int argc, const char **argv, const char *prefix)\n \tstruct replay_opts opts = REPLAY_OPTS_INIT;\n \tunsigned flags = 0, keep_empty = 0, rebase_merges = 0, autosquash = 0;\n \tint abbreviate_commands = 0, rebase_cousins = -1, ret = 0;\n-\tconst char *onto_name = NULL,\n-\t\t*squash_onto = NULL, *head_name = NULL,\n-\t\t*switch_to = NULL, *cmd = NULL;\n+\tconst char *onto_name = NULL, *head_name = NULL, *switch_to = NULL,\n+\t\t*cmd = NULL;\n \tstruct commit *onto = NULL, *upstream = NULL, *restrict_revision = NULL;\n+\tstruct object_id squash_onto = null_oid;\n+\tstruct object_id *squash_onto_opt = NULL;\n \tstruct string_list commands = STRING_LIST_INIT_DUP;\n \tchar *raw_strategies = NULL;\n \tenum {\n@@ -311,8 +313,8 @@ int cmd_rebase__interactive(int argc, const char **argv, const char *prefix)\n \t\t{ OPTION_CALLBACK, 0, \"restrict-revision\", &restrict_revision,\n \t\t  N_(\"restrict-revision\"), N_(\"restrict revision\"),\n \t\t  PARSE_OPT_NONEG, parse_opt_commit, 0 },\n-\t\tOPT_STRING(0, \"squash-onto\", &squash_onto, N_(\"squash-onto\"),\n-\t\t\t   N_(\"squash onto\")),\n+\t\t{ OPTION_CALLBACK, 0, \"squash-onto\", &squash_onto, N_(\"squash-onto\"),\n+\t\t  N_(\"squash onto\"), PARSE_OPT_NONEG, parse_opt_object_id, 0 },\n \t\t{ OPTION_CALLBACK, 0, \"upstream\", &upstream, N_(\"upstream\"),\n \t\t  N_(\"the upstream commit\"), PARSE_OPT_NONEG, parse_opt_commit,\n \t\t  0 },\n@@ -349,6 +351,9 @@ int cmd_rebase__interactive(int argc, const char **argv, const char *prefix)\n \n \topts.gpg_sign = xstrdup_or_null(opts.gpg_sign);\n \n+\tif (!is_null_oid(&squash_onto))\n+\t\tsquash_onto_opt = &squash_onto;\n+\n \tflags |= keep_empty ? TODO_LIST_KEEP_EMPTY : 0;\n \tflags |= abbreviate_commands ? TODO_LIST_ABBREVIATE_CMDS : 0;\n \tflags |= rebase_merges ? TODO_LIST_REBASE_MERGES : 0;\n@@ -373,7 +378,7 @@ int cmd_rebase__interactive(int argc, const char **argv, const char *prefix)\n \t\t\tdie(_(\"a base commit must be provided with --upstream or --onto\"));\n \n \t\tret = do_interactive_rebase(&opts, flags, switch_to, upstream, onto,\n-\t\t\t\t\t    onto_name, squash_onto, head_name, restrict_revision,\n+\t\t\t\t\t    onto_name, squash_onto_opt, head_name, restrict_revision,\n \t\t\t\t\t    raw_strategies, &commands, autosquash);\n \t\tbreak;\n \tcase SKIP: {\ndiff --git a/parse-options-cb.c b/parse-options-cb.c\nindex 2206eb763c..28ad5cd94b 100644\n--- a/parse-options-cb.c\n+++ b/parse-options-cb.c\n@@ -129,6 +129,23 @@ int parse_opt_object_name(const struct option *opt, const char *arg, int unset)\n \treturn 0;\n }\n \n+int parse_opt_object_id(const struct option *opt, const char *arg, int unset)\n+{\n+\tstruct object_id oid;\n+\tstruct object_id *target = opt->value;\n+\n+\tif (unset) {\n+\t\t*target = null_oid;\n+\t\treturn 0;\n+\t}\n+\tif (!arg)\n+\t\treturn -1;\n+\tif (get_oid(arg, &oid))\n+\t\treturn error(_(\"malformed object name '%s'\"), arg);\n+\t*target = oid;\n+\treturn 0;\n+}\n+\n int parse_opt_tertiary(const struct option *opt, const char *arg, int unset)\n {\n \tint *target = opt->value;\ndiff --git a/parse-options.h b/parse-options.h\nindex 5a75646618..0ab1103bc7 100644\n--- a/parse-options.h\n+++ b/parse-options.h\n@@ -264,7 +264,10 @@ int parse_opt_abbrev_cb(const struct option *, const char *, int);\n int parse_opt_expiry_date_cb(const struct option *, const char *, int);\n int parse_opt_color_flag_cb(const struct option *, const char *, int);\n int parse_opt_verbosity_cb(const struct option *, const char *, int);\n+/* value is struct oid_array* */\n int parse_opt_object_name(const struct option *, const char *, int);\n+/* value is struct object_id* */\n+int parse_opt_object_id(const struct option *, const char *, int);\n int parse_opt_commits(const struct option *, const char *, int);\n int parse_opt_commit(const struct option *, const char *, int);\n int parse_opt_tertiary(const struct option *, const char *, int);\n-- \n2.21.0\n\n"},{"id":"374044","messageId":"20190417143044.17655-8-phillip.wood123@gmail.com","threadId":"50780","inReplyTo":"20190417143044.17655-1-phillip.wood123@gmail.com","subject":"[PATCH v1 07/12] rebase -i: use struct commit when parsing options","fromName":"Phillip Wood","fromEmail":"phillip.wood123@gmail.com","sentAt":"2019-04-17T14:30:39Z","receivedAt":"2019-04-17T14:33:12Z","isPatch":true,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"From: Phillip Wood <phillip.wood@dunelm.org.uk>\n\nThis is in preparation for using `struct rebase_options` when parsing\noptions in cmd_rebase__interactive(). Using a string for onto,\nrestrict_revision and upstream, was a hangover from the scripted version\nof rebase. The functions that use these variables are updated to take a\n`struct commit`.\n\nSigned-off-by: Phillip Wood <phillip.wood@dunelm.org.uk>\n---\n builtin/rebase.c   | 42 ++++++++++++++++++++++++------------------\n parse-options-cb.c | 17 +++++++++++++++++\n parse-options.h    |  1 +\n sequencer.c        | 21 +++++++++++----------\n sequencer.h        |  4 ++--\n 5 files changed, 55 insertions(+), 30 deletions(-)\n\ndiff --git a/builtin/rebase.c b/builtin/rebase.c\nindex 610b67827b..06f6490ca3 100644\n--- a/builtin/rebase.c\n+++ b/builtin/rebase.c\n@@ -147,27 +147,28 @@ static int edit_todo_file(unsigned flags)\n \treturn res;\n }\n \n-static int get_revision_ranges(const char *upstream, const char *onto,\n+static int get_revision_ranges(struct commit *upstream, struct commit *onto,\n \t\t\t       const char **head_hash,\n \t\t\t       char **revisions, char **shortrevisions)\n {\n-\tconst char *base_rev = upstream ? upstream : onto, *shorthead;\n+\tstruct commit *base_rev = upstream ? upstream : onto;\n+\tconst char *shorthead;\n \tstruct object_id orig_head;\n \n \tif (get_oid(\"HEAD\", &orig_head))\n \t\treturn error(_(\"no HEAD?\"));\n \n \t*head_hash = find_unique_abbrev(&orig_head, GIT_MAX_HEXSZ);\n-\t*revisions = xstrfmt(\"%s...%s\", base_rev, *head_hash);\n+\t*revisions = xstrfmt(\"%s...%s\", oid_to_hex(&base_rev->object.oid),\n+\t\t\t\t\t\t   *head_hash);\n \n \tshorthead = find_unique_abbrev(&orig_head, DEFAULT_ABBREV);\n \n \tif (upstream) {\n \t\tconst char *shortrev;\n-\t\tstruct object_id rev_oid;\n \n-\t\tget_oid(base_rev, &rev_oid);\n-\t\tshortrev = find_unique_abbrev(&rev_oid, DEFAULT_ABBREV);\n+\t\tshortrev = find_unique_abbrev(&base_rev->object.oid,\n+\t\t\t\t\t      DEFAULT_ABBREV);\n \n \t\t*shortrevisions = xstrfmt(\"%s..%s\", shortrev, shorthead);\n \t} else\n@@ -177,7 +178,7 @@ static int get_revision_ranges(const char *upstream, const char *onto,\n }\n \n static int init_basic_state(struct replay_opts *opts, const char *head_name,\n-\t\t\t    const char *onto, const char *orig_head)\n+\t\t\t    struct commit *onto, const char *orig_head)\n {\n \tFILE *interactive;\n \n@@ -195,10 +196,10 @@ static int init_basic_state(struct replay_opts *opts, const char *head_name,\n }\n \n static int do_interactive_rebase(struct replay_opts *opts, unsigned flags,\n-\t\t\t\t const char *switch_to, const char *upstream,\n-\t\t\t\t const char *onto, const char *onto_name,\n+\t\t\t\t const char *switch_to, struct commit *upstream,\n+\t\t\t\t struct commit *onto, const char *onto_name,\n \t\t\t\t const char *squash_onto, const char *head_name,\n-\t\t\t\t const char *restrict_revision, char *raw_strategies,\n+\t\t\t\t struct commit *restrict_revision, char *raw_strategies,\n \t\t\t\t struct string_list *commands, unsigned autosquash)\n {\n \tint ret;\n@@ -229,7 +230,8 @@ static int do_interactive_rebase(struct replay_opts *opts, unsigned flags,\n \n \targv_array_pushl(&make_script_args, \"\", revisions, NULL);\n \tif (restrict_revision)\n-\t\targv_array_push(&make_script_args, restrict_revision);\n+\t\targv_array_push(&make_script_args,\n+\t\t\t\toid_to_hex(&restrict_revision->object.oid));\n \n \tret = sequencer_make_script(the_repository, &todo_list.buf,\n \t\t\t\t    make_script_args.argc, make_script_args.argv,\n@@ -265,9 +267,10 @@ int cmd_rebase__interactive(int argc, const char **argv, const char *prefix)\n \tstruct replay_opts opts = REPLAY_OPTS_INIT;\n \tunsigned flags = 0, keep_empty = 0, rebase_merges = 0, autosquash = 0;\n \tint abbreviate_commands = 0, rebase_cousins = -1, ret = 0;\n-\tconst char *onto = NULL, *onto_name = NULL, *restrict_revision = NULL,\n-\t\t*squash_onto = NULL, *upstream = NULL, *head_name = NULL,\n+\tconst char *onto_name = NULL,\n+\t\t*squash_onto = NULL, *head_name = NULL,\n \t\t*switch_to = NULL, *cmd = NULL;\n+\tstruct commit *onto = NULL, *upstream = NULL, *restrict_revision = NULL;\n \tstruct string_list commands = STRING_LIST_INIT_DUP;\n \tchar *raw_strategies = NULL;\n \tenum {\n@@ -303,13 +306,16 @@ int cmd_rebase__interactive(int argc, const char **argv, const char *prefix)\n \t\t\tN_(\"rearrange fixup/squash lines\"), REARRANGE_SQUASH),\n \t\tOPT_CMDMODE(0, \"add-exec-commands\", &command,\n \t\t\tN_(\"insert exec commands in todo list\"), ADD_EXEC),\n-\t\tOPT_STRING(0, \"onto\", &onto, N_(\"onto\"), N_(\"onto\")),\n-\t\tOPT_STRING(0, \"restrict-revision\", &restrict_revision,\n-\t\t\t   N_(\"restrict-revision\"), N_(\"restrict revision\")),\n+\t\t{ OPTION_CALLBACK, 0, \"onto\", &onto, N_(\"onto\"), N_(\"onto\"),\n+\t\t  PARSE_OPT_NONEG, parse_opt_commit, 0 },\n+\t\t{ OPTION_CALLBACK, 0, \"restrict-revision\", &restrict_revision,\n+\t\t  N_(\"restrict-revision\"), N_(\"restrict revision\"),\n+\t\t  PARSE_OPT_NONEG, parse_opt_commit, 0 },\n \t\tOPT_STRING(0, \"squash-onto\", &squash_onto, N_(\"squash-onto\"),\n \t\t\t   N_(\"squash onto\")),\n-\t\tOPT_STRING(0, \"upstream\", &upstream, N_(\"upstream\"),\n-\t\t\t   N_(\"the upstream commit\")),\n+\t\t{ OPTION_CALLBACK, 0, \"upstream\", &upstream, N_(\"upstream\"),\n+\t\t  N_(\"the upstream commit\"), PARSE_OPT_NONEG, parse_opt_commit,\n+\t\t  0 },\n \t\tOPT_STRING(0, \"head-name\", &head_name, N_(\"head-name\"), N_(\"head name\")),\n \t\t{ OPTION_STRING, 'S', \"gpg-sign\", &opts.gpg_sign, N_(\"key-id\"),\n \t\t\tN_(\"GPG-sign commits\"),\ndiff --git a/parse-options-cb.c b/parse-options-cb.c\nindex 2733393546..2206eb763c 100644\n--- a/parse-options-cb.c\n+++ b/parse-options-cb.c\n@@ -96,6 +96,23 @@ int parse_opt_commits(const struct option *opt, const char *arg, int unset)\n \treturn 0;\n }\n \n+int parse_opt_commit(const struct option *opt, const char *arg, int unset)\n+{\n+\tstruct object_id oid;\n+\tstruct commit *commit;\n+\tstruct commit **target = opt->value;\n+\n+\tif (!arg)\n+\t\treturn -1;\n+\tif (get_oid(arg, &oid))\n+\t\treturn error(\"malformed object name %s\", arg);\n+\tcommit = lookup_commit_reference(the_repository, &oid);\n+\tif (!commit)\n+\t\treturn error(\"no such commit %s\", arg);\n+\t*target = commit;\n+\treturn 0;\n+}\n+\n int parse_opt_object_name(const struct option *opt, const char *arg, int unset)\n {\n \tstruct object_id oid;\ndiff --git a/parse-options.h b/parse-options.h\nindex 7d83e2971d..5a75646618 100644\n--- a/parse-options.h\n+++ b/parse-options.h\n@@ -266,6 +266,7 @@ int parse_opt_color_flag_cb(const struct option *, const char *, int);\n int parse_opt_verbosity_cb(const struct option *, const char *, int);\n int parse_opt_object_name(const struct option *, const char *, int);\n int parse_opt_commits(const struct option *, const char *, int);\n+int parse_opt_commit(const struct option *, const char *, int);\n int parse_opt_tertiary(const struct option *, const char *, int);\n int parse_opt_string_list(const struct option *, const char *, int);\n int parse_opt_noop_cb(const struct option *, const char *, int);\ndiff --git a/sequencer.c b/sequencer.c\nindex ccc0160800..610b7ece14 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -2418,14 +2418,15 @@ static void write_strategy_opts(struct replay_opts *opts)\n }\n \n int write_basic_state(struct replay_opts *opts, const char *head_name,\n-\t\t      const char *onto, const char *orig_head)\n+\t\t      struct commit *onto, const char *orig_head)\n {\n \tconst char *quiet = getenv(\"GIT_QUIET\");\n \n \tif (head_name)\n \t\twrite_file(rebase_path_head_name(), \"%s\\n\", head_name);\n \tif (onto)\n-\t\twrite_file(rebase_path_onto(), \"%s\\n\", onto);\n+\t\twrite_file(rebase_path_onto(), \"%s\\n\",\n+\t\t\t   oid_to_hex(&onto->object.oid));\n \tif (orig_head)\n \t\twrite_file(rebase_path_orig_head(), \"%s\\n\", orig_head);\n \n@@ -3456,7 +3457,7 @@ int prepare_branch_to_be_rebased(struct repository *r, struct replay_opts *opts,\n }\n \n static int checkout_onto(struct repository *r, struct replay_opts *opts,\n-\t\t\t const char *onto_name, const char *onto,\n+\t\t\t const char *onto_name, const struct object_id *onto,\n \t\t\t const char *orig_head)\n {\n \tstruct object_id oid;\n@@ -3465,7 +3466,7 @@ static int checkout_onto(struct repository *r, struct replay_opts *opts,\n \tif (get_oid(orig_head, &oid))\n \t\treturn error(_(\"%s: not a valid OID\"), orig_head);\n \n-\tif (run_git_checkout(r, opts, onto, action)) {\n+\tif (run_git_checkout(r, opts, oid_to_hex(onto), action)) {\n \t\tapply_autostash(opts);\n \t\tsequencer_remove_state(opts);\n \t\treturn error(_(\"could not detach HEAD\"));\n@@ -4741,16 +4742,16 @@ static int skip_unnecessary_picks(struct repository *r,\n \n int complete_action(struct repository *r, struct replay_opts *opts, unsigned flags,\n \t\t    const char *shortrevisions, const char *onto_name,\n-\t\t    const char *onto, const char *orig_head, struct string_list *commands,\n-\t\t    unsigned autosquash, struct todo_list *todo_list)\n+\t\t    struct commit *onto, const char *orig_head,\n+\t\t    struct string_list *commands, unsigned autosquash,\n+\t\t    struct todo_list *todo_list)\n {\n \tconst char *shortonto, *todo_file = rebase_path_todo();\n \tstruct todo_list new_todo = TODO_LIST_INIT;\n \tstruct strbuf *buf = &todo_list->buf;\n-\tstruct object_id oid;\n+\tstruct object_id oid = onto->object.oid;\n \tint res;\n \n-\tget_oid(onto, &oid);\n \tshortonto = find_unique_abbrev(&oid, DEFAULT_ABBREV);\n \n \tif (buf->len == 0) {\n@@ -4793,7 +4794,7 @@ int complete_action(struct repository *r, struct replay_opts *opts, unsigned fla\n \tif (todo_list_parse_insn_buffer(r, new_todo.buf.buf, &new_todo) ||\n \t    todo_list_check(todo_list, &new_todo)) {\n \t\tfprintf(stderr, _(edit_todo_list_advice));\n-\t\tcheckout_onto(r, opts, onto_name, onto, orig_head);\n+\t\tcheckout_onto(r, opts, onto_name, &onto->object.oid, orig_head);\n \t\ttodo_list_release(&new_todo);\n \n \t\treturn -1;\n@@ -4812,7 +4813,7 @@ int complete_action(struct repository *r, struct replay_opts *opts, unsigned fla\n \n \ttodo_list_release(&new_todo);\n \n-\tif (checkout_onto(r, opts, onto_name, oid_to_hex(&oid), orig_head))\n+\tif (checkout_onto(r, opts, onto_name, &oid, orig_head))\n \t\treturn -1;\n \n \tif (require_clean_work_tree(r, \"rebase\", \"\", 1, 1))\ndiff --git a/sequencer.h b/sequencer.h\nindex 6c55aa4200..e640ca21f2 100644\n--- a/sequencer.h\n+++ b/sequencer.h\n@@ -150,7 +150,7 @@ void todo_list_add_exec_commands(struct todo_list *todo_list,\n int check_todo_list_from_file(struct repository *r);\n int complete_action(struct repository *r, struct replay_opts *opts, unsigned flags,\n \t\t    const char *shortrevisions, const char *onto_name,\n-\t\t    const char *onto, const char *orig_head, struct string_list *commands,\n+\t\t    struct commit *onto, const char *orig_head, struct string_list *commands,\n \t\t    unsigned autosquash, struct todo_list *todo_list);\n int todo_list_rearrange_squash(struct todo_list *todo_list);\n \n@@ -191,4 +191,4 @@ int read_author_script(const char *path, char **name, char **email, char **date,\n \n void parse_strategy_opts(struct replay_opts *opts, char *raw_opts);\n int write_basic_state(struct replay_opts *opts, const char *head_name,\n-\t\t      const char *onto, const char *orig_head);\n+\t\t      struct commit *onto, const char *orig_head);\n-- \n2.21.0\n\n"},{"id":"374046","messageId":"20190417143044.17655-10-phillip.wood123@gmail.com","threadId":"50780","inReplyTo":"20190417143044.17655-1-phillip.wood123@gmail.com","subject":"[PATCH v1 09/12] rebase -i: use struct rebase_options to parse args","fromName":"Phillip Wood","fromEmail":"phillip.wood123@gmail.com","sentAt":"2019-04-17T14:30:41Z","receivedAt":"2019-04-17T14:33:14Z","isPatch":true,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"From: Phillip Wood <phillip.wood@dunelm.org.uk>\n\nIn order to run `rebase -i` without forking `rebase--interactive` it\nwill be convenient to use the same structure when parsing the options in\ncmd_rebase() and cmd_rebase__interactive().\n\nSigned-off-by: Phillip Wood <phillip.wood@dunelm.org.uk>\n---\n builtin/rebase.c | 203 ++++++++++++++++++++++++++---------------------\n 1 file changed, 112 insertions(+), 91 deletions(-)\n\ndiff --git a/builtin/rebase.c b/builtin/rebase.c\nindex 3b9da69473..aa97d81ab8 100644\n--- a/builtin/rebase.c\n+++ b/builtin/rebase.c\n@@ -50,6 +50,73 @@ enum rebase_type {\n \tREBASE_PRESERVE_MERGES\n };\n \n+struct rebase_options {\n+\tenum rebase_type type;\n+\tconst char *state_dir;\n+\tstruct commit *upstream;\n+\tconst char *upstream_name;\n+\tconst char *upstream_arg;\n+\tchar *head_name;\n+\tstruct object_id orig_head;\n+\tstruct commit *onto;\n+\tconst char *onto_name;\n+\tconst char *revisions;\n+\tconst char *switch_to;\n+\tint root;\n+\tstruct object_id *squash_onto;\n+\tstruct commit *restrict_revision;\n+\tint dont_finish_rebase;\n+\tenum {\n+\t\tREBASE_NO_QUIET = 1<<0,\n+\t\tREBASE_VERBOSE = 1<<1,\n+\t\tREBASE_DIFFSTAT = 1<<2,\n+\t\tREBASE_FORCE = 1<<3,\n+\t\tREBASE_INTERACTIVE_EXPLICIT = 1<<4,\n+\t} flags;\n+\tstruct argv_array git_am_opts;\n+\tconst char *action;\n+\tint signoff;\n+\tint allow_rerere_autoupdate;\n+\tint keep_empty;\n+\tint autosquash;\n+\tchar *gpg_sign_opt;\n+\tint autostash;\n+\tchar *cmd;\n+\tint allow_empty_message;\n+\tint rebase_merges, rebase_cousins;\n+\tchar *strategy, *strategy_opts;\n+\tstruct strbuf git_format_patch_opt;\n+\tint reschedule_failed_exec;\n+};\n+\n+#define REBASE_OPTIONS_INIT {\t\t\t  \t\\\n+\t\t.type = REBASE_UNSPECIFIED,\t  \t\\\n+\t\t.flags = REBASE_NO_QUIET, \t\t\\\n+\t\t.git_am_opts = ARGV_ARRAY_INIT,\t\t\\\n+\t\t.git_format_patch_opt = STRBUF_INIT\t\\\n+\t}\n+\n+static struct replay_opts get_replay_opts(const struct rebase_options *opts)\n+{\n+\tstruct replay_opts replay = REPLAY_OPTS_INIT;\n+\n+\treplay.action = REPLAY_INTERACTIVE_REBASE;\n+\tsequencer_init_config(&replay);\n+\n+\treplay.signoff = opts->signoff;\n+\treplay.allow_ff = !(opts->flags & REBASE_FORCE);\n+\tif (opts->allow_rerere_autoupdate)\n+\t\treplay.allow_rerere_auto = opts->allow_rerere_autoupdate;\n+\treplay.allow_empty = 1;\n+\treplay.allow_empty_message = opts->allow_empty_message;\n+\treplay.verbose = opts->flags & REBASE_VERBOSE;\n+\treplay.reschedule_failed_exec = opts->reschedule_failed_exec;\n+\treplay.gpg_sign = xstrdup_or_null(opts->gpg_sign_opt);\n+\treplay.strategy = opts->strategy;\n+\n+\treturn replay;\n+}\n+\n static int add_exec_commands(struct string_list *commands)\n {\n \tconst char *todo_file = rebase_path_todo();\n@@ -265,32 +332,30 @@ static const char * const builtin_rebase_interactive_usage[] = {\n \n int cmd_rebase__interactive(int argc, const char **argv, const char *prefix)\n {\n-\tstruct replay_opts opts = REPLAY_OPTS_INIT;\n-\tunsigned flags = 0, keep_empty = 0, rebase_merges = 0, autosquash = 0;\n-\tint abbreviate_commands = 0, rebase_cousins = -1, ret = 0;\n-\tconst char *onto_name = NULL, *head_name = NULL, *switch_to = NULL,\n-\t\t*cmd = NULL;\n-\tstruct commit *onto = NULL, *upstream = NULL, *restrict_revision = NULL;\n+\tstruct rebase_options opts = REBASE_OPTIONS_INIT;\n+\tunsigned flags = 0;\n+\tint abbreviate_commands = 0, ret = 0;\n \tstruct object_id squash_onto = null_oid;\n-\tstruct object_id *squash_onto_opt = NULL;\n \tstruct string_list commands = STRING_LIST_INIT_DUP;\n-\tchar *raw_strategies = NULL;\n \tenum {\n \t\tNONE = 0, CONTINUE, SKIP, EDIT_TODO, SHOW_CURRENT_PATCH,\n \t\tSHORTEN_OIDS, EXPAND_OIDS, CHECK_TODO_LIST, REARRANGE_SQUASH, ADD_EXEC\n \t} command = 0;\n \tstruct option options[] = {\n-\t\tOPT_BOOL(0, \"ff\", &opts.allow_ff, N_(\"allow fast-forward\")),\n-\t\tOPT_BOOL(0, \"keep-empty\", &keep_empty, N_(\"keep empty commits\")),\n+\t\tOPT_NEGBIT(0, \"ff\", &opts.flags, N_(\"allow fast-forward\"),\n+\t\t\t   REBASE_FORCE),\n+\t\tOPT_BOOL(0, \"keep-empty\", &opts.keep_empty, N_(\"keep empty commits\")),\n \t\tOPT_BOOL(0, \"allow-empty-message\", &opts.allow_empty_message,\n \t\t\t N_(\"allow commits with empty messages\")),\n-\t\tOPT_BOOL(0, \"rebase-merges\", &rebase_merges, N_(\"rebase merge commits\")),\n-\t\tOPT_BOOL(0, \"rebase-cousins\", &rebase_cousins,\n+\t\tOPT_BOOL(0, \"rebase-merges\", &opts.rebase_merges, N_(\"rebase merge commits\")),\n+\t\tOPT_BOOL(0, \"rebase-cousins\", &opts.rebase_cousins,\n \t\t\t N_(\"keep original branch points of cousins\")),\n-\t\tOPT_BOOL(0, \"autosquash\", &autosquash,\n+\t\tOPT_BOOL(0, \"autosquash\", &opts.autosquash,\n \t\t\t N_(\"move commits that begin with squash!/fixup!\")),\n \t\tOPT_BOOL(0, \"signoff\", &opts.signoff, N_(\"sign commits\")),\n-\t\tOPT__VERBOSE(&opts.verbose, N_(\"be verbose\")),\n+\t\tOPT_BIT('v', \"verbose\", &opts.flags,\n+\t\t\tN_(\"display a diffstat of what changed upstream\"),\n+\t\t\tREBASE_NO_QUIET | REBASE_VERBOSE | REBASE_DIFFSTAT),\n \t\tOPT_CMDMODE(0, \"continue\", &command, N_(\"continue rebase\"),\n \t\t\t    CONTINUE),\n \t\tOPT_CMDMODE(0, \"skip\", &command, N_(\"skip commit\"), SKIP),\n@@ -308,86 +373,86 @@ int cmd_rebase__interactive(int argc, const char **argv, const char *prefix)\n \t\t\tN_(\"rearrange fixup/squash lines\"), REARRANGE_SQUASH),\n \t\tOPT_CMDMODE(0, \"add-exec-commands\", &command,\n \t\t\tN_(\"insert exec commands in todo list\"), ADD_EXEC),\n-\t\t{ OPTION_CALLBACK, 0, \"onto\", &onto, N_(\"onto\"), N_(\"onto\"),\n+\t\t{ OPTION_CALLBACK, 0, \"onto\", &opts.onto, N_(\"onto\"), N_(\"onto\"),\n \t\t  PARSE_OPT_NONEG, parse_opt_commit, 0 },\n-\t\t{ OPTION_CALLBACK, 0, \"restrict-revision\", &restrict_revision,\n+\t\t{ OPTION_CALLBACK, 0, \"restrict-revision\", &opts.restrict_revision,\n \t\t  N_(\"restrict-revision\"), N_(\"restrict revision\"),\n \t\t  PARSE_OPT_NONEG, parse_opt_commit, 0 },\n \t\t{ OPTION_CALLBACK, 0, \"squash-onto\", &squash_onto, N_(\"squash-onto\"),\n \t\t  N_(\"squash onto\"), PARSE_OPT_NONEG, parse_opt_object_id, 0 },\n-\t\t{ OPTION_CALLBACK, 0, \"upstream\", &upstream, N_(\"upstream\"),\n+\t\t{ OPTION_CALLBACK, 0, \"upstream\", &opts.upstream, N_(\"upstream\"),\n \t\t  N_(\"the upstream commit\"), PARSE_OPT_NONEG, parse_opt_commit,\n \t\t  0 },\n-\t\tOPT_STRING(0, \"head-name\", &head_name, N_(\"head-name\"), N_(\"head name\")),\n-\t\t{ OPTION_STRING, 'S', \"gpg-sign\", &opts.gpg_sign, N_(\"key-id\"),\n+\t\tOPT_STRING(0, \"head-name\", &opts.head_name, N_(\"head-name\"), N_(\"head name\")),\n+\t\t{ OPTION_STRING, 'S', \"gpg-sign\", &opts.gpg_sign_opt, N_(\"key-id\"),\n \t\t\tN_(\"GPG-sign commits\"),\n \t\t\tPARSE_OPT_OPTARG, NULL, (intptr_t) \"\" },\n \t\tOPT_STRING(0, \"strategy\", &opts.strategy, N_(\"strategy\"),\n \t\t\t   N_(\"rebase strategy\")),\n-\t\tOPT_STRING(0, \"strategy-opts\", &raw_strategies, N_(\"strategy-opts\"),\n+\t\tOPT_STRING(0, \"strategy-opts\", &opts.strategy_opts, N_(\"strategy-opts\"),\n \t\t\t   N_(\"strategy options\")),\n-\t\tOPT_STRING(0, \"switch-to\", &switch_to, N_(\"switch-to\"),\n+\t\tOPT_STRING(0, \"switch-to\", &opts.switch_to, N_(\"switch-to\"),\n \t\t\t   N_(\"the branch or commit to checkout\")),\n-\t\tOPT_STRING(0, \"onto-name\", &onto_name, N_(\"onto-name\"), N_(\"onto name\")),\n-\t\tOPT_STRING(0, \"cmd\", &cmd, N_(\"cmd\"), N_(\"the command to run\")),\n-\t\tOPT_RERERE_AUTOUPDATE(&opts.allow_rerere_auto),\n+\t\tOPT_STRING(0, \"onto-name\", &opts.onto_name, N_(\"onto-name\"), N_(\"onto name\")),\n+\t\tOPT_STRING(0, \"cmd\", &opts.cmd, N_(\"cmd\"), N_(\"the command to run\")),\n+\t\tOPT_RERERE_AUTOUPDATE(&opts.allow_rerere_autoupdate),\n \t\tOPT_BOOL(0, \"reschedule-failed-exec\", &opts.reschedule_failed_exec,\n \t\t\t N_(\"automatically re-schedule any `exec` that fails\")),\n \t\tOPT_END()\n \t};\n \n-\tsequencer_init_config(&opts);\n+\topts.rebase_cousins = -1;\n+\n \tgit_config_get_bool(\"rebase.abbreviatecommands\", &abbreviate_commands);\n \n-\topts.action = REPLAY_INTERACTIVE_REBASE;\n-\topts.allow_ff = 1;\n-\topts.allow_empty = 1;\n-\n \tif (argc == 1)\n \t\tusage_with_options(builtin_rebase_interactive_usage, options);\n \n \targc = parse_options(argc, argv, NULL, options,\n \t\t\tbuiltin_rebase_interactive_usage, PARSE_OPT_KEEP_ARGV0);\n \n-\topts.gpg_sign = xstrdup_or_null(opts.gpg_sign);\n-\n \tif (!is_null_oid(&squash_onto))\n-\t\tsquash_onto_opt = &squash_onto;\n+\t\topts.squash_onto = &squash_onto;\n \n-\tflags |= keep_empty ? TODO_LIST_KEEP_EMPTY : 0;\n+\tflags |= opts.keep_empty ? TODO_LIST_KEEP_EMPTY : 0;\n \tflags |= abbreviate_commands ? TODO_LIST_ABBREVIATE_CMDS : 0;\n-\tflags |= rebase_merges ? TODO_LIST_REBASE_MERGES : 0;\n-\tflags |= rebase_cousins > 0 ? TODO_LIST_REBASE_COUSINS : 0;\n+\tflags |= opts.rebase_merges ? TODO_LIST_REBASE_MERGES : 0;\n+\tflags |= opts.rebase_cousins > 0 ? TODO_LIST_REBASE_COUSINS : 0;\n \tflags |= command == SHORTEN_OIDS ? TODO_LIST_SHORTEN_IDS : 0;\n \n-\tif (rebase_cousins >= 0 && !rebase_merges)\n+\tif (opts.rebase_cousins >= 0 && !opts.rebase_merges)\n \t\twarning(_(\"--[no-]rebase-cousins has no effect without \"\n \t\t\t  \"--rebase-merges\"));\n \n-\tif (cmd && *cmd) {\n-\t\tstring_list_split(&commands, cmd, '\\n', -1);\n+\tif (opts.cmd && *opts.cmd) {\n+\t\tstring_list_split(&commands, opts.cmd, '\\n', -1);\n \n \t\t/* rebase.c adds a new line to cmd after every command,\n \t\t * so here the last command is always empty */\n \t\tstring_list_remove_empty_items(&commands, 0);\n \t}\n \n \tswitch (command) {\n-\tcase NONE:\n-\t\tif (!onto && !upstream)\n+\tcase NONE: {\n+\t\tstruct replay_opts replay_opts = get_replay_opts(&opts);\n+\t\tif (!opts.onto && !opts.upstream)\n \t\t\tdie(_(\"a base commit must be provided with --upstream or --onto\"));\n \n-\t\tret = do_interactive_rebase(&opts, flags, switch_to, upstream, onto,\n-\t\t\t\t\t    onto_name, squash_onto_opt, head_name, restrict_revision,\n-\t\t\t\t\t    raw_strategies, &commands, autosquash);\n+\t\tret = do_interactive_rebase(&replay_opts, flags, opts.switch_to, opts.upstream, opts.onto,\n+\t\t\t\t\t    opts.onto_name, opts.squash_onto, opts.head_name, opts.restrict_revision,\n+\t\t\t\t\t    opts.strategy_opts, &commands, opts.autosquash);\n \t\tbreak;\n+\t}\n \tcase SKIP: {\n \t\tstruct string_list merge_rr = STRING_LIST_INIT_DUP;\n \n \t\trerere_clear(the_repository, &merge_rr);\n+\t}\n \t\t/* fallthrough */\n-\tcase CONTINUE:\n-\t\tret = sequencer_continue(the_repository, &opts);\n+\tcase CONTINUE: {\n+\t\tstruct replay_opts replay_opts = get_replay_opts(&opts);\n+\n+\t\tret = sequencer_continue(the_repository, &replay_opts);\n \t\tbreak;\n \t}\n \tcase EDIT_TODO:\n@@ -446,45 +511,6 @@ static int use_builtin_rebase(void)\n \treturn ret;\n }\n \n-struct rebase_options {\n-\tenum rebase_type type;\n-\tconst char *state_dir;\n-\tstruct commit *upstream;\n-\tconst char *upstream_name;\n-\tconst char *upstream_arg;\n-\tchar *head_name;\n-\tstruct object_id orig_head;\n-\tstruct commit *onto;\n-\tconst char *onto_name;\n-\tconst char *revisions;\n-\tconst char *switch_to;\n-\tint root;\n-\tstruct object_id *squash_onto;\n-\tstruct commit *restrict_revision;\n-\tint dont_finish_rebase;\n-\tenum {\n-\t\tREBASE_NO_QUIET = 1<<0,\n-\t\tREBASE_VERBOSE = 1<<1,\n-\t\tREBASE_DIFFSTAT = 1<<2,\n-\t\tREBASE_FORCE = 1<<3,\n-\t\tREBASE_INTERACTIVE_EXPLICIT = 1<<4,\n-\t} flags;\n-\tstruct argv_array git_am_opts;\n-\tconst char *action;\n-\tint signoff;\n-\tint allow_rerere_autoupdate;\n-\tint keep_empty;\n-\tint autosquash;\n-\tchar *gpg_sign_opt;\n-\tint autostash;\n-\tchar *cmd;\n-\tint allow_empty_message;\n-\tint rebase_merges, rebase_cousins;\n-\tchar *strategy, *strategy_opts;\n-\tstruct strbuf git_format_patch_opt;\n-\tint reschedule_failed_exec;\n-};\n-\n static int is_interactive(struct rebase_options *opts)\n {\n \treturn opts->type == REBASE_INTERACTIVE ||\n@@ -1380,13 +1406,7 @@ static int check_exec_cmd(const char *cmd)\n \n int cmd_rebase(int argc, const char **argv, const char *prefix)\n {\n-\tstruct rebase_options options = {\n-\t\t.type = REBASE_UNSPECIFIED,\n-\t\t.flags = REBASE_NO_QUIET,\n-\t\t.git_am_opts = ARGV_ARRAY_INIT,\n-\t\t.allow_empty_message = 1,\n-\t\t.git_format_patch_opt = STRBUF_INIT,\n-\t};\n+\tstruct rebase_options options = REBASE_OPTIONS_INIT;\n \tconst char *branch_name;\n \tint ret, flags, total_argc, in_progress = 0;\n \tint ok_to_skip_pre_rebase = 0;\n@@ -1539,6 +1559,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \ttrace_repo_setup(prefix);\n \tsetup_work_tree();\n \n+\toptions.allow_empty_message = 1;\n \tgit_config(rebase_config, &options);\n \n \tstrbuf_reset(&buf);\n-- \n2.21.0\n\n"},{"id":"374047","messageId":"20190417143044.17655-11-phillip.wood123@gmail.com","threadId":"50780","inReplyTo":"20190417143044.17655-1-phillip.wood123@gmail.com","subject":"[PATCH v1 10/12] rebase -i: use struct rebase_options in do_interactive_rebase()","fromName":"Phillip Wood","fromEmail":"phillip.wood123@gmail.com","sentAt":"2019-04-17T14:30:42Z","receivedAt":"2019-04-17T14:33:14Z","isPatch":true,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"From: Phillip Wood <phillip.wood@dunelm.org.uk>\n\nAll the parameters that are passed to do_interactive_rebase() apart from\n`flags` are already in `struct rebase_options` so there is no need to\npass them separately.\n\nSigned-off-by: Phillip Wood <phillip.wood@dunelm.org.uk>\n---\n builtin/rebase.c | 69 +++++++++++++++++++++++++-----------------------\n 1 file changed, 36 insertions(+), 33 deletions(-)\n\ndiff --git a/builtin/rebase.c b/builtin/rebase.c\nindex aa97d81ab8..277dbaadf4 100644\n--- a/builtin/rebase.c\n+++ b/builtin/rebase.c\n@@ -113,6 +113,8 @@ static struct replay_opts get_replay_opts(const struct rebase_options *opts)\n \treplay.reschedule_failed_exec = opts->reschedule_failed_exec;\n \treplay.gpg_sign = xstrdup_or_null(opts->gpg_sign_opt);\n \treplay.strategy = opts->strategy;\n+\tif (opts->strategy_opts)\n+\t\tparse_strategy_opts(&replay, opts->strategy_opts);\n \n \treturn replay;\n }\n@@ -262,44 +264,50 @@ static int init_basic_state(struct replay_opts *opts, const char *head_name,\n \treturn write_basic_state(opts, head_name, onto, orig_head);\n }\n \n-static int do_interactive_rebase(struct replay_opts *opts, unsigned flags,\n-\t\t\t\t const char *switch_to, struct commit *upstream,\n-\t\t\t\t struct commit *onto, const char *onto_name,\n-\t\t\t\t struct object_id *squash_onto, const char *head_name,\n-\t\t\t\t struct commit *restrict_revision, char *raw_strategies,\n-\t\t\t\t struct string_list *commands, unsigned autosquash)\n+static void split_exec_commands(const char *cmd, struct string_list *commands)\n+{\n+\tif (cmd && *cmd) {\n+\t\tstring_list_split(commands, cmd, '\\n', -1);\n+\n+\t\t/* rebase.c adds a new line to cmd after every command,\n+\t\t * so here the last command is always empty */\n+\t\tstring_list_remove_empty_items(commands, 0);\n+\t}\n+}\n+\n+static int do_interactive_rebase(struct rebase_options *opts, unsigned flags)\n {\n \tint ret;\n \tconst char *head_hash = NULL;\n \tchar *revisions = NULL, *shortrevisions = NULL;\n \tstruct argv_array make_script_args = ARGV_ARRAY_INIT;\n \tstruct todo_list todo_list = TODO_LIST_INIT;\n+\tstruct replay_opts replay = get_replay_opts(opts);\n+\tstruct string_list commands = STRING_LIST_INIT_DUP;\n \n-\tif (prepare_branch_to_be_rebased(the_repository, opts, switch_to))\n+\tif (prepare_branch_to_be_rebased(the_repository, &replay,\n+\t\t\t\t\t opts->switch_to))\n \t\treturn -1;\n \n-\tif (get_revision_ranges(upstream, onto, &head_hash,\n+\tif (get_revision_ranges(opts->upstream, opts->onto, &head_hash,\n \t\t\t\t&revisions, &shortrevisions))\n \t\treturn -1;\n \n-\tif (raw_strategies)\n-\t\tparse_strategy_opts(opts, raw_strategies);\n-\n-\tif (init_basic_state(opts, head_name, onto, head_hash)) {\n+\tif (init_basic_state(&replay, opts->head_name, opts->onto, head_hash)) {\n \t\tfree(revisions);\n \t\tfree(shortrevisions);\n \n \t\treturn -1;\n \t}\n \n-\tif (!upstream && squash_onto)\n+\tif (!opts->upstream && opts->squash_onto)\n \t\twrite_file(path_squash_onto(), \"%s\\n\",\n-\t\t\t   oid_to_hex(squash_onto));\n+\t\t\t   oid_to_hex(opts->squash_onto));\n \n \targv_array_pushl(&make_script_args, \"\", revisions, NULL);\n-\tif (restrict_revision)\n+\tif (opts->restrict_revision)\n \t\targv_array_push(&make_script_args,\n-\t\t\t\toid_to_hex(&restrict_revision->object.oid));\n+\t\t\t\toid_to_hex(&opts->restrict_revision->object.oid));\n \n \tret = sequencer_make_script(the_repository, &todo_list.buf,\n \t\t\t\t    make_script_args.argc, make_script_args.argv,\n@@ -313,10 +321,13 @@ static int do_interactive_rebase(struct replay_opts *opts, unsigned flags,\n \t\t\t\t\t\t&todo_list))\n \t\t\tBUG(\"unusable todo list\");\n \n-\t\tret = complete_action(the_repository, opts, flags, shortrevisions, onto_name,\n-\t\t\t\t      onto, head_hash, commands, autosquash, &todo_list);\n+\t\tsplit_exec_commands(opts->cmd, &commands);\n+\t\tret = complete_action(the_repository, &replay, flags,\n+\t\t\tshortrevisions, opts->onto_name, opts->onto, head_hash,\n+\t\t\t&commands, opts->autosquash, &todo_list);\n \t}\n \n+\tstring_list_clear(&commands, 0);\n \tfree(revisions);\n \tfree(shortrevisions);\n \ttodo_list_release(&todo_list);\n@@ -336,7 +347,6 @@ int cmd_rebase__interactive(int argc, const char **argv, const char *prefix)\n \tunsigned flags = 0;\n \tint abbreviate_commands = 0, ret = 0;\n \tstruct object_id squash_onto = null_oid;\n-\tstruct string_list commands = STRING_LIST_INIT_DUP;\n \tenum {\n \t\tNONE = 0, CONTINUE, SKIP, EDIT_TODO, SHOW_CURRENT_PATCH,\n \t\tSHORTEN_OIDS, EXPAND_OIDS, CHECK_TODO_LIST, REARRANGE_SQUASH, ADD_EXEC\n@@ -424,23 +434,12 @@ int cmd_rebase__interactive(int argc, const char **argv, const char *prefix)\n \t\twarning(_(\"--[no-]rebase-cousins has no effect without \"\n \t\t\t  \"--rebase-merges\"));\n \n-\tif (opts.cmd && *opts.cmd) {\n-\t\tstring_list_split(&commands, opts.cmd, '\\n', -1);\n-\n-\t\t/* rebase.c adds a new line to cmd after every command,\n-\t\t * so here the last command is always empty */\n-\t\tstring_list_remove_empty_items(&commands, 0);\n-\t}\n-\n \tswitch (command) {\n \tcase NONE: {\n-\t\tstruct replay_opts replay_opts = get_replay_opts(&opts);\n \t\tif (!opts.onto && !opts.upstream)\n \t\t\tdie(_(\"a base commit must be provided with --upstream or --onto\"));\n \n-\t\tret = do_interactive_rebase(&replay_opts, flags, opts.switch_to, opts.upstream, opts.onto,\n-\t\t\t\t\t    opts.onto_name, opts.squash_onto, opts.head_name, opts.restrict_revision,\n-\t\t\t\t\t    opts.strategy_opts, &commands, opts.autosquash);\n+\t\tret = do_interactive_rebase(&opts, flags);\n \t\tbreak;\n \t}\n \tcase SKIP: {\n@@ -477,14 +476,18 @@ int cmd_rebase__interactive(int argc, const char **argv, const char *prefix)\n \tcase REARRANGE_SQUASH:\n \t\tret = rearrange_squash_in_todo_file();\n \t\tbreak;\n-\tcase ADD_EXEC:\n+\tcase ADD_EXEC: {\n+\t\tstruct string_list commands = STRING_LIST_INIT_DUP;\n+\n+\t\tsplit_exec_commands(opts.cmd, &commands);\n \t\tret = add_exec_commands(&commands);\n+\t\tstring_list_clear(&commands, 0);\n \t\tbreak;\n+\t}\n \tdefault:\n \t\tBUG(\"invalid command '%d'\", command);\n \t}\n \n-\tstring_list_clear(&commands, 0);\n \treturn !!ret;\n }\n \n-- \n2.21.0\n\n"},{"id":"374048","messageId":"20190417143044.17655-13-phillip.wood123@gmail.com","threadId":"50780","inReplyTo":"20190417143044.17655-1-phillip.wood123@gmail.com","subject":"[PATCH v1 12/12] rebase -i: run without forking rebase--interactive","fromName":"Phillip Wood","fromEmail":"phillip.wood123@gmail.com","sentAt":"2019-04-17T14:30:44Z","receivedAt":"2019-04-17T14:33:16Z","isPatch":true,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"From: Phillip Wood <phillip.wood@dunelm.org.uk>\n\nWhen the builtin rebase starts an interactive rebase it parses the\noptions and then repackages them and forks\n`rebase--interactive`. Separate the option parsing in\ncmd_rebase__interactive() from the business logic to allow interactive\nrebases can be run without forking `rebase__interactive` by calling\nrun_rebase_interactive() directly.\n\nStarting interactive rebases without forking makes it easy to debug\nthe sequencer without worrying about attaching to child\nprocesses. Ævar has also reported that some of the rebase perf tests\nare 30% faster [1].\n\nThis patch also makes it easy to remove cmd_rebase__interactive() in\nthe future when git-legacy-rebase.sh and\ngit-rebase--preserve-merges.sh are retired.\n\n[1] https://public-inbox.org/git/87y359cfjj.fsf@evledraar.gmail.com/\n\nSigned-off-by: Phillip Wood <phillip.wood@dunelm.org.uk>\n---\n builtin/rebase.c | 221 ++++++++++++++++++-----------------------------\n 1 file changed, 86 insertions(+), 135 deletions(-)\n\ndiff --git a/builtin/rebase.c b/builtin/rebase.c\nindex 0020e1ecf6..cd233c6118 100644\n--- a/builtin/rebase.c\n+++ b/builtin/rebase.c\n@@ -316,7 +316,9 @@ static int do_interactive_rebase(struct rebase_options *opts, unsigned flags)\n \t\t\t\t&revisions, &shortrevisions))\n \t\treturn -1;\n \n-\tif (init_basic_state(&replay, opts->head_name, opts->onto, head_hash)) {\n+\tif (init_basic_state(&replay,\n+\t\t\t     opts->head_name ? opts->head_name : \"detached HEAD\",\n+\t\t\t     opts->onto, head_hash)) {\n \t\tfree(revisions);\n \t\tfree(shortrevisions);\n \n@@ -359,6 +361,77 @@ static int do_interactive_rebase(struct rebase_options *opts, unsigned flags)\n \treturn ret;\n }\n \n+static int run_rebase_interactive(struct rebase_options *opts,\n+\t\t\t\t  enum action command)\n+{\n+\tunsigned flags = 0;\n+\tint abbreviate_commands = 0, ret = 0;\n+\n+\tgit_config_get_bool(\"rebase.abbreviatecommands\", &abbreviate_commands);\n+\n+\tflags |= opts->keep_empty ? TODO_LIST_KEEP_EMPTY : 0;\n+\tflags |= abbreviate_commands ? TODO_LIST_ABBREVIATE_CMDS : 0;\n+\tflags |= opts->rebase_merges ? TODO_LIST_REBASE_MERGES : 0;\n+\tflags |= opts->rebase_cousins > 0 ? TODO_LIST_REBASE_COUSINS : 0;\n+\tflags |= command == ACTION_SHORTEN_OIDS ? TODO_LIST_SHORTEN_IDS : 0;\n+\n+\tswitch (command) {\n+\tcase ACTION_NONE: {\n+\t\tif (!opts->onto && !opts->upstream)\n+\t\t\tdie(_(\"a base commit must be provided with --upstream or --onto\"));\n+\n+\t\tret = do_interactive_rebase(opts, flags);\n+\t\tbreak;\n+\t}\n+\tcase ACTION_SKIP: {\n+\t\tstruct string_list merge_rr = STRING_LIST_INIT_DUP;\n+\n+\t\trerere_clear(the_repository, &merge_rr);\n+\t}\n+\t\t/* fallthrough */\n+\tcase ACTION_CONTINUE: {\n+\t\tstruct replay_opts replay_opts = get_replay_opts(opts);\n+\n+\t\tret = sequencer_continue(the_repository, &replay_opts);\n+\t\tbreak;\n+\t}\n+\tcase ACTION_EDIT_TODO:\n+\t\tret = edit_todo_file(flags);\n+\t\tbreak;\n+\tcase ACTION_SHOW_CURRENT_PATCH: {\n+\t\tstruct child_process cmd = CHILD_PROCESS_INIT;\n+\n+\t\tcmd.git_cmd = 1;\n+\t\targv_array_pushl(&cmd.args, \"show\", \"REBASE_HEAD\", \"--\", NULL);\n+\t\tret = run_command(&cmd);\n+\n+\t\tbreak;\n+\t}\n+\tcase ACTION_SHORTEN_OIDS:\n+\tcase ACTION_EXPAND_OIDS:\n+\t\tret = transform_todo_file(flags);\n+\t\tbreak;\n+\tcase ACTION_CHECK_TODO_LIST:\n+\t\tret = check_todo_list_from_file(the_repository);\n+\t\tbreak;\n+\tcase ACTION_REARRANGE_SQUASH:\n+\t\tret = rearrange_squash_in_todo_file();\n+\t\tbreak;\n+\tcase ACTION_ADD_EXEC: {\n+\t\tstruct string_list commands = STRING_LIST_INIT_DUP;\n+\n+\t\tsplit_exec_commands(opts->cmd, &commands);\n+\t\tret = add_exec_commands(&commands);\n+\t\tstring_list_clear(&commands, 0);\n+\t\tbreak;\n+\t}\n+\tdefault:\n+\t\tBUG(\"invalid command '%d'\", command);\n+\t}\n+\n+\treturn ret;\n+}\n+\n static const char * const builtin_rebase_interactive_usage[] = {\n \tN_(\"git rebase--interactive [<options>]\"),\n \tNULL\n@@ -367,8 +440,6 @@ static const char * const builtin_rebase_interactive_usage[] = {\n int cmd_rebase__interactive(int argc, const char **argv, const char *prefix)\n {\n \tstruct rebase_options opts = REBASE_OPTIONS_INIT;\n-\tunsigned flags = 0;\n-\tint abbreviate_commands = 0, ret = 0;\n \tstruct object_id squash_onto = null_oid;\n \tenum action command = ACTION_NONE;\n \tstruct option options[] = {\n@@ -433,8 +504,6 @@ int cmd_rebase__interactive(int argc, const char **argv, const char *prefix)\n \n \topts.rebase_cousins = -1;\n \n-\tgit_config_get_bool(\"rebase.abbreviatecommands\", &abbreviate_commands);\n-\n \tif (argc == 1)\n \t\tusage_with_options(builtin_rebase_interactive_usage, options);\n \n@@ -444,71 +513,11 @@ int cmd_rebase__interactive(int argc, const char **argv, const char *prefix)\n \tif (!is_null_oid(&squash_onto))\n \t\topts.squash_onto = &squash_onto;\n \n-\tflags |= opts.keep_empty ? TODO_LIST_KEEP_EMPTY : 0;\n-\tflags |= abbreviate_commands ? TODO_LIST_ABBREVIATE_CMDS : 0;\n-\tflags |= opts.rebase_merges ? TODO_LIST_REBASE_MERGES : 0;\n-\tflags |= opts.rebase_cousins > 0 ? TODO_LIST_REBASE_COUSINS : 0;\n-\tflags |= command == ACTION_SHORTEN_OIDS ? TODO_LIST_SHORTEN_IDS : 0;\n-\n \tif (opts.rebase_cousins >= 0 && !opts.rebase_merges)\n \t\twarning(_(\"--[no-]rebase-cousins has no effect without \"\n \t\t\t  \"--rebase-merges\"));\n \n-\tswitch (command) {\n-\tcase ACTION_NONE: {\n-\t\tif (!opts.onto && !opts.upstream)\n-\t\t\tdie(_(\"a base commit must be provided with --upstream or --onto\"));\n-\n-\t\tret = do_interactive_rebase(&opts, flags);\n-\t\tbreak;\n-\t}\n-\tcase ACTION_SKIP: {\n-\t\tstruct string_list merge_rr = STRING_LIST_INIT_DUP;\n-\n-\t\trerere_clear(the_repository, &merge_rr);\n-\t}\n-\t\t/* fallthrough */\n-\tcase ACTION_CONTINUE: {\n-\t\tstruct replay_opts replay_opts = get_replay_opts(&opts);\n-\n-\t\tret = sequencer_continue(the_repository, &replay_opts);\n-\t\tbreak;\n-\t}\n-\tcase ACTION_EDIT_TODO:\n-\t\tret = edit_todo_file(flags);\n-\t\tbreak;\n-\tcase ACTION_SHOW_CURRENT_PATCH: {\n-\t\tstruct child_process cmd = CHILD_PROCESS_INIT;\n-\n-\t\tcmd.git_cmd = 1;\n-\t\targv_array_pushl(&cmd.args, \"show\", \"REBASE_HEAD\", \"--\", NULL);\n-\t\tret = run_command(&cmd);\n-\n-\t\tbreak;\n-\t}\n-\tcase ACTION_SHORTEN_OIDS:\n-\tcase ACTION_EXPAND_OIDS:\n-\t\tret = transform_todo_file(flags);\n-\t\tbreak;\n-\tcase ACTION_CHECK_TODO_LIST:\n-\t\tret = check_todo_list_from_file(the_repository);\n-\t\tbreak;\n-\tcase ACTION_REARRANGE_SQUASH:\n-\t\tret = rearrange_squash_in_todo_file();\n-\t\tbreak;\n-\tcase ACTION_ADD_EXEC: {\n-\t\tstruct string_list commands = STRING_LIST_INIT_DUP;\n-\n-\t\tsplit_exec_commands(opts.cmd, &commands);\n-\t\tret = add_exec_commands(&commands);\n-\t\tstring_list_clear(&commands, 0);\n-\t\tbreak;\n-\t}\n-\tdefault:\n-\t\tBUG(\"invalid command '%d'\", command);\n-\t}\n-\n-\treturn !!ret;\n+\treturn !!run_rebase_interactive(&opts, command);\n }\n \n static int use_builtin_rebase(void)\n@@ -1071,7 +1080,7 @@ static int run_am(struct rebase_options *opts)\n \treturn status;\n }\n \n-static int run_specific_rebase(struct rebase_options *opts)\n+static int run_specific_rebase(struct rebase_options *opts, enum action action)\n {\n \tconst char *argv[] = { NULL, NULL };\n \tstruct strbuf script_snippet = STRBUF_INIT, buf = STRBUF_INIT;\n@@ -1080,77 +1089,19 @@ static int run_specific_rebase(struct rebase_options *opts)\n \n \tif (opts->type == REBASE_INTERACTIVE) {\n \t\t/* Run builtin interactive rebase */\n-\t\tstruct child_process child = CHILD_PROCESS_INIT;\n-\n-\t\targv_array_pushf(&child.env_array, \"GIT_CHERRY_PICK_HELP=%s\",\n-\t\t\t\t resolvemsg);\n+\t\tsetenv(\"GIT_CHERRY_PICK_HELP\", resolvemsg, 1);\n \t\tif (!(opts->flags & REBASE_INTERACTIVE_EXPLICIT)) {\n-\t\t\targv_array_push(&child.env_array,\n-\t\t\t\t\t\"GIT_SEQUENCE_EDITOR=:\");\n+\t\t\tsetenv(\"GIT_SEQUENCE_EDITOR\", \":\", 1);\n \t\t\topts->autosquash = 0;\n \t\t}\n+\t\tif (opts->gpg_sign_opt) {\n+\t\t\t/* remove the leading \"-S\" */\n+\t\t\tchar *tmp = xstrdup(opts->gpg_sign_opt + 2);\n+\t\t\tfree(opts->gpg_sign_opt);\n+\t\t\topts->gpg_sign_opt = tmp;\n+\t\t}\n \n-\t\tchild.git_cmd = 1;\n-\t\targv_array_push(&child.args, \"rebase--interactive\");\n-\n-\t\tif (opts->action)\n-\t\t\targv_array_pushf(&child.args, \"--%s\", opts->action);\n-\t\tif (opts->keep_empty)\n-\t\t\targv_array_push(&child.args, \"--keep-empty\");\n-\t\tif (opts->rebase_merges)\n-\t\t\targv_array_push(&child.args, \"--rebase-merges\");\n-\t\tif (opts->rebase_cousins)\n-\t\t\targv_array_push(&child.args, \"--rebase-cousins\");\n-\t\tif (opts->autosquash)\n-\t\t\targv_array_push(&child.args, \"--autosquash\");\n-\t\tif (opts->flags & REBASE_VERBOSE)\n-\t\t\targv_array_push(&child.args, \"--verbose\");\n-\t\tif (opts->flags & REBASE_FORCE)\n-\t\t\targv_array_push(&child.args, \"--no-ff\");\n-\t\tif (opts->restrict_revision)\n-\t\t\targv_array_pushf(&child.args,\n-\t\t\t\t\t \"--restrict-revision=^%s\",\n-\t\t\t\t\t oid_to_hex(&opts->restrict_revision->object.oid));\n-\t\tif (opts->upstream)\n-\t\t\targv_array_pushf(&child.args, \"--upstream=%s\",\n-\t\t\t\t\t oid_to_hex(&opts->upstream->object.oid));\n-\t\tif (opts->onto)\n-\t\t\targv_array_pushf(&child.args, \"--onto=%s\",\n-\t\t\t\t\t oid_to_hex(&opts->onto->object.oid));\n-\t\tif (opts->squash_onto)\n-\t\t\targv_array_pushf(&child.args, \"--squash-onto=%s\",\n-\t\t\t\t\t oid_to_hex(opts->squash_onto));\n-\t\tif (opts->onto_name)\n-\t\t\targv_array_pushf(&child.args, \"--onto-name=%s\",\n-\t\t\t\t\t opts->onto_name);\n-\t\targv_array_pushf(&child.args, \"--head-name=%s\",\n-\t\t\t\t opts->head_name ?\n-\t\t\t\t opts->head_name : \"detached HEAD\");\n-\t\tif (opts->strategy)\n-\t\t\targv_array_pushf(&child.args, \"--strategy=%s\",\n-\t\t\t\t\t opts->strategy);\n-\t\tif (opts->strategy_opts)\n-\t\t\targv_array_pushf(&child.args, \"--strategy-opts=%s\",\n-\t\t\t\t\t opts->strategy_opts);\n-\t\tif (opts->switch_to)\n-\t\t\targv_array_pushf(&child.args, \"--switch-to=%s\",\n-\t\t\t\t\t opts->switch_to);\n-\t\tif (opts->cmd)\n-\t\t\targv_array_pushf(&child.args, \"--cmd=%s\", opts->cmd);\n-\t\tif (opts->allow_empty_message)\n-\t\t\targv_array_push(&child.args, \"--allow-empty-message\");\n-\t\tif (opts->allow_rerere_autoupdate == RERERE_AUTOUPDATE)\n-\t\t\targv_array_push(&child.args, \"--rerere-autoupdate\");\n-\t\telse if (opts->allow_rerere_autoupdate == RERERE_NOAUTOUPDATE)\n-\t\t\targv_array_push(&child.args, \"--no-rerere-autoupdate\");\n-\t\tif (opts->gpg_sign_opt)\n-\t\t\targv_array_push(&child.args, opts->gpg_sign_opt);\n-\t\tif (opts->signoff)\n-\t\t\targv_array_push(&child.args, \"--signoff\");\n-\t\tif (opts->reschedule_failed_exec)\n-\t\t\targv_array_push(&child.args, \"--reschedule-failed-exec\");\n-\n-\t\tstatus = run_command(&child);\n+\t\tstatus = run_rebase_interactive(opts, action);\n \t\tgoto finished_rebase;\n \t}\n \n@@ -2211,7 +2162,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \toptions.revisions = revisions.buf;\n \n run_rebase:\n-\tret = !!run_specific_rebase(&options);\n+\tret = !!run_specific_rebase(&options, action);\n \n cleanup:\n \tstrbuf_release(&revisions);\n-- \n2.21.0\n\n"},{"id":"374049","messageId":"20190417143044.17655-12-phillip.wood123@gmail.com","threadId":"50780","inReplyTo":"20190417143044.17655-1-phillip.wood123@gmail.com","subject":"[PATCH v1 11/12] rebase: use a common action enum","fromName":"Phillip Wood","fromEmail":"phillip.wood123@gmail.com","sentAt":"2019-04-17T14:30:43Z","receivedAt":"2019-04-17T14:33:17Z","isPatch":true,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"From: Phillip Wood <phillip.wood@dunelm.org.uk>\n\ncmd_rebase() and cmd_rebase__interactive() used different enums to hold\nthe current action. Change to using a common enum so the values are the\nsame when we change `rebase -i` to avoid forking `rebase--interactive`.\n\nSigned-off-by: Phillip Wood <phillip.wood@dunelm.org.uk>\n---\n builtin/rebase.c | 91 +++++++++++++++++++++++++-----------------------\n 1 file changed, 48 insertions(+), 43 deletions(-)\n\ndiff --git a/builtin/rebase.c b/builtin/rebase.c\nindex 277dbaadf4..0020e1ecf6 100644\n--- a/builtin/rebase.c\n+++ b/builtin/rebase.c\n@@ -119,6 +119,29 @@ static struct replay_opts get_replay_opts(const struct rebase_options *opts)\n \treturn replay;\n }\n \n+enum action {\n+\tACTION_NONE = 0,\n+\tACTION_CONTINUE,\n+\tACTION_SKIP,\n+\tACTION_ABORT,\n+\tACTION_QUIT,\n+\tACTION_EDIT_TODO,\n+\tACTION_SHOW_CURRENT_PATCH,\n+\tACTION_SHORTEN_OIDS,\n+\tACTION_EXPAND_OIDS,\n+\tACTION_CHECK_TODO_LIST,\n+\tACTION_REARRANGE_SQUASH,\n+\tACTION_ADD_EXEC\n+};\n+\n+static const char *action_names[] = { \"undefined\",\n+\t\t\t\t      \"continue\",\n+\t\t\t\t      \"skip\",\n+\t\t\t\t      \"abort\",\n+\t\t\t\t      \"quit\",\n+\t\t\t\t      \"edit_todo\",\n+\t\t\t\t      \"show_current_patch\" };\n+\n static int add_exec_commands(struct string_list *commands)\n {\n \tconst char *todo_file = rebase_path_todo();\n@@ -347,10 +370,7 @@ int cmd_rebase__interactive(int argc, const char **argv, const char *prefix)\n \tunsigned flags = 0;\n \tint abbreviate_commands = 0, ret = 0;\n \tstruct object_id squash_onto = null_oid;\n-\tenum {\n-\t\tNONE = 0, CONTINUE, SKIP, EDIT_TODO, SHOW_CURRENT_PATCH,\n-\t\tSHORTEN_OIDS, EXPAND_OIDS, CHECK_TODO_LIST, REARRANGE_SQUASH, ADD_EXEC\n-\t} command = 0;\n+\tenum action command = ACTION_NONE;\n \tstruct option options[] = {\n \t\tOPT_NEGBIT(0, \"ff\", &opts.flags, N_(\"allow fast-forward\"),\n \t\t\t   REBASE_FORCE),\n@@ -367,22 +387,22 @@ int cmd_rebase__interactive(int argc, const char **argv, const char *prefix)\n \t\t\tN_(\"display a diffstat of what changed upstream\"),\n \t\t\tREBASE_NO_QUIET | REBASE_VERBOSE | REBASE_DIFFSTAT),\n \t\tOPT_CMDMODE(0, \"continue\", &command, N_(\"continue rebase\"),\n-\t\t\t    CONTINUE),\n-\t\tOPT_CMDMODE(0, \"skip\", &command, N_(\"skip commit\"), SKIP),\n+\t\t\t    ACTION_CONTINUE),\n+\t\tOPT_CMDMODE(0, \"skip\", &command, N_(\"skip commit\"), ACTION_SKIP),\n \t\tOPT_CMDMODE(0, \"edit-todo\", &command, N_(\"edit the todo list\"),\n-\t\t\t    EDIT_TODO),\n+\t\t\t    ACTION_EDIT_TODO),\n \t\tOPT_CMDMODE(0, \"show-current-patch\", &command, N_(\"show the current patch\"),\n-\t\t\t    SHOW_CURRENT_PATCH),\n+\t\t\t    ACTION_SHOW_CURRENT_PATCH),\n \t\tOPT_CMDMODE(0, \"shorten-ids\", &command,\n-\t\t\tN_(\"shorten commit ids in the todo list\"), SHORTEN_OIDS),\n+\t\t\tN_(\"shorten commit ids in the todo list\"), ACTION_SHORTEN_OIDS),\n \t\tOPT_CMDMODE(0, \"expand-ids\", &command,\n-\t\t\tN_(\"expand commit ids in the todo list\"), EXPAND_OIDS),\n+\t\t\tN_(\"expand commit ids in the todo list\"), ACTION_EXPAND_OIDS),\n \t\tOPT_CMDMODE(0, \"check-todo-list\", &command,\n-\t\t\tN_(\"check the todo list\"), CHECK_TODO_LIST),\n+\t\t\tN_(\"check the todo list\"), ACTION_CHECK_TODO_LIST),\n \t\tOPT_CMDMODE(0, \"rearrange-squash\", &command,\n-\t\t\tN_(\"rearrange fixup/squash lines\"), REARRANGE_SQUASH),\n+\t\t\tN_(\"rearrange fixup/squash lines\"), ACTION_REARRANGE_SQUASH),\n \t\tOPT_CMDMODE(0, \"add-exec-commands\", &command,\n-\t\t\tN_(\"insert exec commands in todo list\"), ADD_EXEC),\n+\t\t\tN_(\"insert exec commands in todo list\"), ACTION_ADD_EXEC),\n \t\t{ OPTION_CALLBACK, 0, \"onto\", &opts.onto, N_(\"onto\"), N_(\"onto\"),\n \t\t  PARSE_OPT_NONEG, parse_opt_commit, 0 },\n \t\t{ OPTION_CALLBACK, 0, \"restrict-revision\", &opts.restrict_revision,\n@@ -428,36 +448,36 @@ int cmd_rebase__interactive(int argc, const char **argv, const char *prefix)\n \tflags |= abbreviate_commands ? TODO_LIST_ABBREVIATE_CMDS : 0;\n \tflags |= opts.rebase_merges ? TODO_LIST_REBASE_MERGES : 0;\n \tflags |= opts.rebase_cousins > 0 ? TODO_LIST_REBASE_COUSINS : 0;\n-\tflags |= command == SHORTEN_OIDS ? TODO_LIST_SHORTEN_IDS : 0;\n+\tflags |= command == ACTION_SHORTEN_OIDS ? TODO_LIST_SHORTEN_IDS : 0;\n \n \tif (opts.rebase_cousins >= 0 && !opts.rebase_merges)\n \t\twarning(_(\"--[no-]rebase-cousins has no effect without \"\n \t\t\t  \"--rebase-merges\"));\n \n \tswitch (command) {\n-\tcase NONE: {\n+\tcase ACTION_NONE: {\n \t\tif (!opts.onto && !opts.upstream)\n \t\t\tdie(_(\"a base commit must be provided with --upstream or --onto\"));\n \n \t\tret = do_interactive_rebase(&opts, flags);\n \t\tbreak;\n \t}\n-\tcase SKIP: {\n+\tcase ACTION_SKIP: {\n \t\tstruct string_list merge_rr = STRING_LIST_INIT_DUP;\n \n \t\trerere_clear(the_repository, &merge_rr);\n \t}\n \t\t/* fallthrough */\n-\tcase CONTINUE: {\n+\tcase ACTION_CONTINUE: {\n \t\tstruct replay_opts replay_opts = get_replay_opts(&opts);\n \n \t\tret = sequencer_continue(the_repository, &replay_opts);\n \t\tbreak;\n \t}\n-\tcase EDIT_TODO:\n+\tcase ACTION_EDIT_TODO:\n \t\tret = edit_todo_file(flags);\n \t\tbreak;\n-\tcase SHOW_CURRENT_PATCH: {\n+\tcase ACTION_SHOW_CURRENT_PATCH: {\n \t\tstruct child_process cmd = CHILD_PROCESS_INIT;\n \n \t\tcmd.git_cmd = 1;\n@@ -466,17 +486,17 @@ int cmd_rebase__interactive(int argc, const char **argv, const char *prefix)\n \n \t\tbreak;\n \t}\n-\tcase SHORTEN_OIDS:\n-\tcase EXPAND_OIDS:\n+\tcase ACTION_SHORTEN_OIDS:\n+\tcase ACTION_EXPAND_OIDS:\n \t\tret = transform_todo_file(flags);\n \t\tbreak;\n-\tcase CHECK_TODO_LIST:\n+\tcase ACTION_CHECK_TODO_LIST:\n \t\tret = check_todo_list_from_file(the_repository);\n \t\tbreak;\n-\tcase REARRANGE_SQUASH:\n+\tcase ACTION_REARRANGE_SQUASH:\n \t\tret = rearrange_squash_in_todo_file();\n \t\tbreak;\n-\tcase ADD_EXEC: {\n+\tcase ACTION_ADD_EXEC: {\n \t\tstruct string_list commands = STRING_LIST_INIT_DUP;\n \n \t\tsplit_exec_commands(opts.cmd, &commands);\n@@ -1417,22 +1437,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \tstruct strbuf revisions = STRBUF_INIT;\n \tstruct strbuf buf = STRBUF_INIT;\n \tstruct object_id merge_base;\n-\tenum {\n-\t\tNO_ACTION,\n-\t\tACTION_CONTINUE,\n-\t\tACTION_SKIP,\n-\t\tACTION_ABORT,\n-\t\tACTION_QUIT,\n-\t\tACTION_EDIT_TODO,\n-\t\tACTION_SHOW_CURRENT_PATCH,\n-\t} action = NO_ACTION;\n-\tstatic const char *action_names[] = { \"undefined\",\n-\t\t\t\t\t      \"continue\",\n-\t\t\t\t\t      \"skip\",\n-\t\t\t\t\t      \"abort\",\n-\t\t\t\t\t      \"quit\",\n-\t\t\t\t\t      \"edit_todo\",\n-\t\t\t\t\t      \"show_current_patch\" };\n+\tenum action action = ACTION_NONE;\n \tconst char *gpg_sign = NULL;\n \tstruct string_list exec = STRING_LIST_INIT_NODUP;\n \tconst char *rebase_merges = NULL;\n@@ -1599,7 +1604,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \t\t\t     builtin_rebase_options,\n \t\t\t     builtin_rebase_usage, 0);\n \n-\tif (action != NO_ACTION && total_argc != 2) {\n+\tif (action != ACTION_NONE && total_argc != 2) {\n \t\tusage_with_options(builtin_rebase_usage,\n \t\t\t\t   builtin_rebase_options);\n \t}\n@@ -1608,7 +1613,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \t\tusage_with_options(builtin_rebase_usage,\n \t\t\t\t   builtin_rebase_options);\n \n-\tif (action != NO_ACTION && !in_progress)\n+\tif (action != ACTION_NONE && !in_progress)\n \t\tdie(_(\"No rebase in progress?\"));\n \tsetenv(GIT_REFLOG_ACTION_ENVIRONMENT, \"rebase\", 0);\n \n@@ -1708,7 +1713,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \t\toptions.action = \"show-current-patch\";\n \t\toptions.dont_finish_rebase = 1;\n \t\tgoto run_rebase;\n-\tcase NO_ACTION:\n+\tcase ACTION_NONE:\n \t\tbreak;\n \tdefault:\n \t\tBUG(\"action: %d\", action);\n-- \n2.21.0\n\n"},{"id":"374155","messageId":"xmqqy346czhj.fsf@gitster-ct.c.googlers.com","threadId":"50780","inReplyTo":"20190417143044.17655-3-phillip.wood123@gmail.com","subject":"Re: [PATCH v1 02/12] rebase: don't translate trace strings","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2019-04-19T05:53:28Z","receivedAt":"2019-04-19T19:23:00Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Phillip Wood <phillip.wood123@gmail.com> writes:\n\n> From: Phillip Wood <phillip.wood@dunelm.org.uk>\n>\n> commit b3a5d5a80c (\"trace2:data: add subverb for rebase\", 2019-02-22)\n> mistakenly marked the subverb names for translation and unnecessarily\n> NULL terminated the array.\n>\n> Signed-off-by: Phillip Wood <phillip.wood@dunelm.org.uk>\n> ---\n>  builtin/rebase.c | 15 +++++++--------\n>  1 file changed, 7 insertions(+), 8 deletions(-)\n>\n> diff --git a/builtin/rebase.c b/builtin/rebase.c\n> index 52114cbf0d..239a54ecfe 100644\n> --- a/builtin/rebase.c\n> +++ b/builtin/rebase.c\n> @@ -1027,14 +1027,13 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n>  \t\tACTION_EDIT_TODO,\n>  \t\tACTION_SHOW_CURRENT_PATCH,\n>  \t} action = NO_ACTION;\n> -\tstatic const char *action_names[] = { N_(\"undefined\"),\n> -\t\t\t\t\t      N_(\"continue\"),\n> -\t\t\t\t\t      N_(\"skip\"),\n> -\t\t\t\t\t      N_(\"abort\"),\n> -\t\t\t\t\t      N_(\"quit\"),\n> -\t\t\t\t\t      N_(\"edit_todo\"),\n> -\t\t\t\t\t      N_(\"show_current_patch\"),\n> -\t\t\t\t\t      NULL };\n> +\tstatic const char *action_names[] = { \"undefined\",\n> +\t\t\t\t\t      \"continue\",\n> +\t\t\t\t\t      \"skip\",\n> +\t\t\t\t\t      \"abort\",\n> +\t\t\t\t\t      \"quit\",\n> +\t\t\t\t\t      \"edit_todo\",\n> +\t\t\t\t\t      \"show_current_patch\" };\n\nThat's an improvement independent from the rest of the patches.\n\nNow we've had the C99 designated initialisers weather balloon\nchanges for some time in our codebase, perhaps we can ensure that\nthese entries match the intended & corresponding \"enum action\"\nconstants?  If we can also ensure that the array is large enough so\nthat the trace2 call done like so\n\n\ttrace2_cmd_mode(action_names[action])\n\nis safe, that would be good, but that is secondary.\n\nThanks.\n"},{"id":"374519","messageId":"41344c53-5b57-3d97-7b64-9128f7cba6af@gmail.com","threadId":"50780","inReplyTo":"xmqqy346czhj.fsf@gitster-ct.c.googlers.com","subject":"Re: [PATCH v1 02/12] rebase: don't translate trace strings","fromName":"Phillip Wood","fromEmail":"phillip.wood123@gmail.com","sentAt":"2019-04-25T17:47:09Z","receivedAt":"2019-04-25T17:47:15Z","isPatch":true,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"On 19/04/2019 06:53, Junio C Hamano wrote:\n> Phillip Wood <phillip.wood123@gmail.com> writes:\n> \n>> From: Phillip Wood <phillip.wood@dunelm.org.uk>\n>>\n>> commit b3a5d5a80c (\"trace2:data: add subverb for rebase\", 2019-02-22)\n>> mistakenly marked the subverb names for translation and unnecessarily\n>> NULL terminated the array.\n>>\n>> Signed-off-by: Phillip Wood <phillip.wood@dunelm.org.uk>\n>> ---\n>>  builtin/rebase.c | 15 +++++++--------\n>>  1 file changed, 7 insertions(+), 8 deletions(-)\n>>\n>> diff --git a/builtin/rebase.c b/builtin/rebase.c\n>> index 52114cbf0d..239a54ecfe 100644\n>> --- a/builtin/rebase.c\n>> +++ b/builtin/rebase.c\n>> @@ -1027,14 +1027,13 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n>>  \t\tACTION_EDIT_TODO,\n>>  \t\tACTION_SHOW_CURRENT_PATCH,\n>>  \t} action = NO_ACTION;\n>> -\tstatic const char *action_names[] = { N_(\"undefined\"),\n>> -\t\t\t\t\t      N_(\"continue\"),\n>> -\t\t\t\t\t      N_(\"skip\"),\n>> -\t\t\t\t\t      N_(\"abort\"),\n>> -\t\t\t\t\t      N_(\"quit\"),\n>> -\t\t\t\t\t      N_(\"edit_todo\"),\n>> -\t\t\t\t\t      N_(\"show_current_patch\"),\n>> -\t\t\t\t\t      NULL };\n>> +\tstatic const char *action_names[] = { \"undefined\",\n>> +\t\t\t\t\t      \"continue\",\n>> +\t\t\t\t\t      \"skip\",\n>> +\t\t\t\t\t      \"abort\",\n>> +\t\t\t\t\t      \"quit\",\n>> +\t\t\t\t\t      \"edit_todo\",\n>> +\t\t\t\t\t      \"show_current_patch\" };\n> \n> That's an improvement independent from the rest of the patches.\n\nYes I only included it as I move the definition later in the series\n\n> Now we've had the C99 designated initialisers weather balloon\n> changes for some time in our codebase, perhaps we can ensure that\n> these entries match the intended & corresponding \"enum action\"\n> constants?  If we can also ensure that the array is large enough so\n> that the trace2 call done like so\n> \n> \ttrace2_cmd_mode(action_names[action])\n> \n> is safe, that would be good, but that is secondary.\n> \n> Thanks.\n\nIf what's below is ok, I'll send a re-roll, I wasn't sure if it was best\nto die if action is larger than the array of names or just use a\ndefault. My worrying with dying is that it wont be caught by tests and\nwill cause a problem for users who enable tracing. At least with what's\nbelow they can still rebase and hopefully report a bug about unknown\naction in their trace output.\n\nBest Wishes\n\nPhillip\n\ndiff --git a/builtin/rebase.c b/builtin/rebase.c\nindex 52114cbf0d..3f56be230e 100644\n--- a/builtin/rebase.c\n+++ b/builtin/rebase.c\n@@ -1027,14 +1027,15 @@ int cmd_rebase(int argc, const char **argv,\nconst char *prefix)\n                ACTION_EDIT_TODO,\n                ACTION_SHOW_CURRENT_PATCH,\n        } action = NO_ACTION;\n-       static const char *action_names[] = { N_(\"undefined\"),\n-                                             N_(\"continue\"),\n-                                             N_(\"skip\"),\n-                                             N_(\"abort\"),\n-                                             N_(\"quit\"),\n-                                             N_(\"edit_todo\"),\n-                                             N_(\"show_current_patch\"),\n-                                             NULL };\n+       static const char *action_names[] = {\n+               [NO_ACTION] = \"undefined\",\n+               [ACTION_CONTINUE] = \"continue\",\n+               [ACTION_SKIP] = \"skip\",\n+               [ACTION_ABORT] = \"abort\",\n+               [ACTION_QUIT] = \"quit\",\n+               [ACTION_EDIT_TODO] = \"edit_todo\",\n+               [ACTION_SHOW_CURRENT_PATCH] = \"show_current_patch\"\n+       };\n        const char *gpg_sign = NULL;\n        struct string_list exec = STRING_LIST_INIT_NODUP;\n        const char *rebase_merges = NULL;\n@@ -1225,8 +1226,10 @@ int cmd_rebase(int argc, const char **argv, const\nchar *prefix)\n                        trace2_cmd_mode(\"interactive\");\n                else if (exec.nr)\n                        trace2_cmd_mode(\"interactive-exec\");\n-               else\n+               else if (action < ARRAY_SIZE(action_names))\n                        trace2_cmd_mode(action_names[action]);\n+               else\n+                       trace2_cmd_mode(\"unknown rebase action\");\n        }\n\n        switch (action) {\n\n\n"}]}