{"thread":{"id":"48814","subject":"[GSoC][PATCH v2 0/7] rebase -i: rewrite some parts in C","startedAt":"2018-07-02T10:58:04Z","lastAt":"2018-09-27T22:00:58Z","messageCount":193,"participants":["Alban Gruin","Junio C Hamano","Johannes Schindelin","Stefan Beller","SZEDER Gábor","Jeff King","Phillip Wood","Christian Couder","Duy Nguyen"],"isPatch":true,"patchVersion":2,"patchTotal":7},"messages":[{"id":"351516","messageId":"20180702105717.26386-1-alban.gruin@gmail.com","threadId":"48814","inReplyTo":null,"subject":"[GSoC][PATCH v2 0/7] rebase -i: rewrite some parts in C","fromName":"Alban Gruin","fromEmail":"alban.gruin@gmail.com","sentAt":"2018-07-02T10:57:10Z","receivedAt":"2018-07-02T10:58:04Z","isPatch":true,"sender":{"key":"alban.gruin@gmail.com","avatar":"https://avatars.githubusercontent.com/u/6310153?v=4"},"body":"This patch series rewrites some parts of interactive rebase from shell\nto C:\n\n - append_todo_help(). The C version covers a bit more than the shell\n   version.\n\n - The edit-todo functionnality.\n\n - The reflog operations.\n\nThe v1 of this series is an aggregate made by Junio of my patch series\nabout append_todo_help() (v3), edit-todo (v2) and reflog (v5), and can\nbe found in the branch `ag/rebase-i-in-c`.\n\nThis branch is based on master (as of 2018-07-02).\n\nChanges since v1:\n\n - Introducing rebase-interactive.c to contain functions necessary for\n   interactive rebase.\n\n - Show an error message when append_todo_help() fails to edit the todo\n   list.\n\n - Renaming enumeration check_level and its values to avoid namespace\n   pollution.\n\n - Moving append_todo_help() and edit_todo() from sequencer.c to\n   interactive-rebase.c.\n\nAlban Gruin (7):\n  sequencer: make two functions and an enum from sequencer.c public\n  rebase--interactive: rewrite append_todo_help() in C\n  editor: add a function to launch the sequence editor\n  rebase-interactive: rewrite the edit-todo functionality in C\n  sequencer: add a new function to silence a command, except if it\n    fails.\n  rebase -i: rewrite setup_reflog_action() in C\n  rebase -i: rewrite checkout_onto() in C\n\n Makefile                   |   1 +\n builtin/rebase--helper.c   |  24 +++++++-\n cache.h                    |   1 +\n editor.c                   |  27 ++++++++-\n git-rebase--interactive.sh | 100 +++----------------------------\n rebase-interactive.c       |  99 ++++++++++++++++++++++++++++++\n rebase-interactive.h       |   7 +++\n sequencer.c                | 120 +++++++++++++++++++++++++------------\n sequencer.h                |  14 +++++\n strbuf.h                   |   2 +\n 10 files changed, 260 insertions(+), 135 deletions(-)\n create mode 100644 rebase-interactive.c\n create mode 100644 rebase-interactive.h\n\n-- \n2.18.0\n\n"},{"id":"351517","messageId":"20180702105717.26386-2-alban.gruin@gmail.com","threadId":"48814","inReplyTo":"20180702105717.26386-1-alban.gruin@gmail.com","subject":"[GSoC][PATCH v2 1/7] sequencer: make two functions and an enum from sequencer.c public","fromName":"Alban Gruin","fromEmail":"alban.gruin@gmail.com","sentAt":"2018-07-02T10:57:11Z","receivedAt":"2018-07-02T10:58:07Z","isPatch":true,"sender":{"key":"alban.gruin@gmail.com","avatar":"https://avatars.githubusercontent.com/u/6310153?v=4"},"body":"This makes rebase_path_todo(), get_missing_commit_check_level() and the\nenum check_level accessible outside sequencer.c.  check_level is renamed\nmissing_commit_check_level, and its value names are prefixed by\nMISSING_COMMIT_ to avoid namespace pollution.\n\nThis will be needed for the rewrite of append_todo_help() from shell to\nC, as it will be in a new library source file, rebase-interactive.c.\n\nSigned-off-by: Alban Gruin <alban.gruin@gmail.com>\n---\n sequencer.c | 22 +++++++++-------------\n sequencer.h |  8 ++++++++\n 2 files changed, 17 insertions(+), 13 deletions(-)\n\ndiff --git a/sequencer.c b/sequencer.c\nindex 5354d4d51..57fd58bc1 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -51,7 +51,7 @@ static GIT_PATH_FUNC(rebase_path, \"rebase-merge\")\n  * the lines are processed, they are removed from the front of this\n  * file and written to the tail of 'done'.\n  */\n-static GIT_PATH_FUNC(rebase_path_todo, \"rebase-merge/git-rebase-todo\")\n+GIT_PATH_FUNC(rebase_path_todo, \"rebase-merge/git-rebase-todo\")\n /*\n  * The rebase command lines that have already been processed. A line\n  * is moved here when it is first handled, before any associated user\n@@ -4221,24 +4221,20 @@ int transform_todos(unsigned flags)\n \treturn i;\n }\n \n-enum check_level {\n-\tCHECK_IGNORE = 0, CHECK_WARN, CHECK_ERROR\n-};\n-\n-static enum check_level get_missing_commit_check_level(void)\n+enum missing_commit_check_level get_missing_commit_check_level(void)\n {\n \tconst char *value;\n \n \tif (git_config_get_value(\"rebase.missingcommitscheck\", &value) ||\n \t\t\t!strcasecmp(\"ignore\", value))\n-\t\treturn CHECK_IGNORE;\n+\t\treturn MISSING_COMMIT_CHECK_IGNORE;\n \tif (!strcasecmp(\"warn\", value))\n-\t\treturn CHECK_WARN;\n+\t\treturn MISSING_COMMIT_CHECK_WARN;\n \tif (!strcasecmp(\"error\", value))\n-\t\treturn CHECK_ERROR;\n+\t\treturn MISSING_COMMIT_CHECK_ERROR;\n \twarning(_(\"unrecognized setting %s for option \"\n \t\t  \"rebase.missingCommitsCheck. Ignoring.\"), value);\n-\treturn CHECK_IGNORE;\n+\treturn MISSING_COMMIT_CHECK_IGNORE;\n }\n \n define_commit_slab(commit_seen, unsigned char);\n@@ -4250,7 +4246,7 @@ define_commit_slab(commit_seen, unsigned char);\n  */\n int check_todo_list(void)\n {\n-\tenum check_level check_level = get_missing_commit_check_level();\n+\tenum missing_commit_check_level check_level = get_missing_commit_check_level();\n \tstruct strbuf todo_file = STRBUF_INIT;\n \tstruct todo_list todo_list = TODO_LIST_INIT;\n \tstruct strbuf missing = STRBUF_INIT;\n@@ -4267,7 +4263,7 @@ int check_todo_list(void)\n \tadvise_to_edit_todo = res =\n \t\tparse_insn_buffer(todo_list.buf.buf, &todo_list);\n \n-\tif (res || check_level == CHECK_IGNORE)\n+\tif (res || check_level == MISSING_COMMIT_CHECK_IGNORE)\n \t\tgoto leave_check;\n \n \t/* Mark the commits in git-rebase-todo as seen */\n@@ -4302,7 +4298,7 @@ int check_todo_list(void)\n \tif (!missing.len)\n \t\tgoto leave_check;\n \n-\tif (check_level == CHECK_ERROR)\n+\tif (check_level == MISSING_COMMIT_CHECK_ERROR)\n \t\tadvise_to_edit_todo = res = 1;\n \n \tfprintf(stderr,\ndiff --git a/sequencer.h b/sequencer.h\nindex c5787c6b5..ffab798f1 100644\n--- a/sequencer.h\n+++ b/sequencer.h\n@@ -3,6 +3,7 @@\n \n const char *git_path_commit_editmsg(void);\n const char *git_path_seq_dir(void);\n+const char *rebase_path_todo(void);\n \n #define APPEND_SIGNOFF_DEDUP (1u << 0)\n \n@@ -57,6 +58,12 @@ struct replay_opts {\n };\n #define REPLAY_OPTS_INIT { .action = -1, .current_fixups = STRBUF_INIT }\n \n+enum missing_commit_check_level {\n+\tMISSING_COMMIT_CHECK_IGNORE = 0,\n+\tMISSING_COMMIT_CHECK_WARN,\n+\tMISSING_COMMIT_CHECK_ERROR\n+};\n+\n /* Call this to setup defaults before parsing command line options */\n void sequencer_init_config(struct replay_opts *opts);\n int sequencer_pick_revisions(struct replay_opts *opts);\n@@ -79,6 +86,7 @@ int sequencer_make_script(FILE *out, int argc, const char **argv,\n \n int sequencer_add_exec_commands(const char *command);\n int transform_todos(unsigned flags);\n+enum missing_commit_check_level get_missing_commit_check_level(void);\n int check_todo_list(void);\n int skip_unnecessary_picks(void);\n int rearrange_squash(void);\n-- \n2.18.0\n\n"},{"id":"351518","messageId":"20180702105717.26386-3-alban.gruin@gmail.com","threadId":"48814","inReplyTo":"20180702105717.26386-1-alban.gruin@gmail.com","subject":"[GSoC][PATCH v2 2/7] rebase--interactive: rewrite append_todo_help() in C","fromName":"Alban Gruin","fromEmail":"alban.gruin@gmail.com","sentAt":"2018-07-02T10:57:12Z","receivedAt":"2018-07-02T10:58:10Z","isPatch":true,"sender":{"key":"alban.gruin@gmail.com","avatar":"https://avatars.githubusercontent.com/u/6310153?v=4"},"body":"This rewrites append_todo_help() from shell to C. It also incorporates\nsome parts of initiate_action() and complete_action() that also write\nhelp texts to the todo file.\n\nThis also introduces the source file rebase-interactive.c. This file\nwill contain functions necessary for interactive rebase that are too\nspecific for the sequencer, and is part of libgit.a.\n\nTwo flags are added to rebase--helper.c: one to call\nappend_todo_help() (`--append-todo-help`), and another one to tell\nappend_todo_help() to write the help text suited for the edit-todo\nmode (`--write-edit-todo`).\n\nFinally, append_todo_help() is removed from git-rebase--interactive.sh\nto use `rebase--helper --append-todo-help` instead.\n\nSigned-off-by: Alban Gruin <alban.gruin@gmail.com>\n---\n Makefile                   |  1 +\n builtin/rebase--helper.c   | 11 ++++--\n git-rebase--interactive.sh | 52 ++---------------------------\n rebase-interactive.c       | 68 ++++++++++++++++++++++++++++++++++++++\n rebase-interactive.h       |  6 ++++\n 5 files changed, 86 insertions(+), 52 deletions(-)\n create mode 100644 rebase-interactive.c\n create mode 100644 rebase-interactive.h\n\ndiff --git a/Makefile b/Makefile\nindex 0cb6590f2..a281139ef 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -922,6 +922,7 @@ LIB_OBJS += protocol.o\n LIB_OBJS += quote.o\n LIB_OBJS += reachable.o\n LIB_OBJS += read-cache.o\n+LIB_OBJS += rebase-interactive.o\n LIB_OBJS += reflog-walk.o\n LIB_OBJS += refs.o\n LIB_OBJS += refs/files-backend.o\ndiff --git a/builtin/rebase--helper.c b/builtin/rebase--helper.c\nindex f7c2a5fdc..05e73e71d 100644\n--- a/builtin/rebase--helper.c\n+++ b/builtin/rebase--helper.c\n@@ -3,6 +3,7 @@\n #include \"config.h\"\n #include \"parse-options.h\"\n #include \"sequencer.h\"\n+#include \"rebase-interactive.h\"\n \n static const char * const builtin_rebase_helper_usage[] = {\n \tN_(\"git rebase--helper [<options>]\"),\n@@ -12,12 +13,12 @@ static const char * const builtin_rebase_helper_usage[] = {\n int cmd_rebase__helper(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;\n+\tunsigned flags = 0, keep_empty = 0, rebase_merges = 0, write_edit_todo = 0;\n \tint abbreviate_commands = 0, rebase_cousins = -1;\n \tenum {\n \t\tCONTINUE = 1, ABORT, MAKE_SCRIPT, SHORTEN_OIDS, EXPAND_OIDS,\n \t\tCHECK_TODO_LIST, SKIP_UNNECESSARY_PICKS, REARRANGE_SQUASH,\n-\t\tADD_EXEC\n+\t\tADD_EXEC, APPEND_TODO_HELP\n \t} command = 0;\n \tstruct option options[] = {\n \t\tOPT_BOOL(0, \"ff\", &opts.allow_ff, N_(\"allow fast-forward\")),\n@@ -27,6 +28,8 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\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, \"write-edit-todo\", &write_edit_todo,\n+\t\t\t N_(\"append the edit-todo message to the todo-list\")),\n \t\tOPT_CMDMODE(0, \"continue\", &command, N_(\"continue rebase\"),\n \t\t\t\tCONTINUE),\n \t\tOPT_CMDMODE(0, \"abort\", &command, N_(\"abort rebase\"),\n@@ -45,6 +48,8 @@ int cmd_rebase__helper(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_CMDMODE(0, \"append-todo-help\", &command,\n+\t\t\t    N_(\"insert the help in the todo list\"), APPEND_TODO_HELP),\n \t\tOPT_END()\n \t};\n \n@@ -84,5 +89,7 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\n \t\treturn !!rearrange_squash();\n \tif (command == ADD_EXEC && argc == 2)\n \t\treturn !!sequencer_add_exec_commands(argv[1]);\n+\tif (command == APPEND_TODO_HELP && argc == 1)\n+\t\treturn !!append_todo_help(write_edit_todo, keep_empty);\n \tusage_with_options(builtin_rebase_helper_usage, options);\n }\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex 299ded213..94c23a7af 100644\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -39,38 +39,6 @@ comment_for_reflog () {\n \tesac\n }\n \n-append_todo_help () {\n-\tgettext \"\n-Commands:\n-p, pick <commit> = use commit\n-r, reword <commit> = use commit, but edit the commit message\n-e, edit <commit> = use commit, but stop for amending\n-s, squash <commit> = use commit, but meld into previous commit\n-f, fixup <commit> = like \\\"squash\\\", but discard this commit's log message\n-x, exec <command> = run command (the rest of the line) using shell\n-d, drop <commit> = remove commit\n-l, label <label> = label current HEAD with a name\n-t, reset <label> = reset HEAD to a label\n-m, merge [-C <commit> | -c <commit>] <label> [# <oneline>]\n-.       create a merge commit using the original merge commit's\n-.       message (or the oneline, if no original merge commit was\n-.       specified). Use -c <commit> to reword the commit message.\n-\n-These lines can be re-ordered; they are executed from top to bottom.\n-\" | git stripspace --comment-lines >>\"$todo\"\n-\n-\tif test $(get_missing_commit_check_level) = error\n-\tthen\n-\t\tgettext \"\n-Do not remove any line. Use 'drop' explicitly to remove a commit.\n-\" | git stripspace --comment-lines >>\"$todo\"\n-\telse\n-\t\tgettext \"\n-If you remove a line here THAT COMMIT WILL BE LOST.\n-\" | git stripspace --comment-lines >>\"$todo\"\n-\tfi\n-}\n-\n die_abort () {\n \tapply_autostash\n \trm -rf \"$state_dir\"\n@@ -143,13 +111,7 @@ initiate_action () {\n \t\tgit stripspace --strip-comments <\"$todo\" >\"$todo\".new\n \t\tmv -f \"$todo\".new \"$todo\"\n \t\tcollapse_todo_ids\n-\t\tappend_todo_help\n-\t\tgettext \"\n-You are editing the todo file of an ongoing interactive rebase.\n-To continue rebase after editing, run:\n-    git rebase --continue\n-\n-\" | git stripspace --comment-lines >>\"$todo\"\n+\t\tgit rebase--helper --append-todo-help --write-edit-todo\n \n \t\tgit_sequence_editor \"$todo\" ||\n \t\t\tdie \"$(gettext \"Could not execute editor\")\"\n@@ -220,17 +182,7 @@ $comment_char $(eval_ngettext \\\n \t\"Rebase \\$shortrevisions onto \\$shortonto (\\$todocount commands)\" \\\n \t\"$todocount\")\n EOF\n-\tappend_todo_help\n-\tgettext \"\n-\tHowever, if you remove everything, the rebase will be aborted.\n-\n-\t\" | git stripspace --comment-lines >>\"$todo\"\n-\n-\tif test -z \"$keep_empty\"\n-\tthen\n-\t\tprintf '%s\\n' \"$comment_char $(gettext \"Note that empty commits are commented out\")\" >>\"$todo\"\n-\tfi\n-\n+\tgit rebase--helper --append-todo-help ${keep_empty:+--keep-empty}\n \n \thas_action \"$todo\" ||\n \t\treturn 2\ndiff --git a/rebase-interactive.c b/rebase-interactive.c\nnew file mode 100644\nindex 000000000..015e08cd0\n--- /dev/null\n+++ b/rebase-interactive.c\n@@ -0,0 +1,68 @@\n+#include \"cache.h\"\n+#include \"commit.h\"\n+#include \"rebase-interactive.h\"\n+#include \"sequencer.h\"\n+#include \"strbuf.h\"\n+\n+int append_todo_help(unsigned edit_todo, unsigned keep_empty)\n+{\n+\tstruct strbuf buf = STRBUF_INIT;\n+\tFILE *todo;\n+\tint ret;\n+\tconst char *msg = _(\"\\nCommands:\\n\"\n+\"p, pick <commit> = use commit\\n\"\n+\"r, reword <commit> = use commit, but edit the commit message\\n\"\n+\"e, edit <commit> = use commit, but stop for amending\\n\"\n+\"s, squash <commit> = use commit, but meld into previous commit\\n\"\n+\"f, fixup <commit> = like \\\"squash\\\", but discard this commit's log message\\n\"\n+\"x, exec <command> = run command (the rest of the line) using shell\\n\"\n+\"d, drop <commit> = remove commit\\n\"\n+\"l, label <label> = label current HEAD with a name\\n\"\n+\"t, reset <label> = reset HEAD to a label\\n\"\n+\"m, merge [-C <commit> | -c <commit>] <label> [# <oneline>]\\n\"\n+\".       create a merge commit using the original merge commit's\\n\"\n+\".       message (or the oneline, if no original merge commit was\\n\"\n+\".       specified). Use -c <commit> to reword the commit message.\\n\"\n+\"\\n\"\n+\"These lines can be re-ordered; they are executed from top to bottom.\\n\");\n+\n+\ttodo = fopen_or_warn(rebase_path_todo(), \"a\");\n+\tif (!todo)\n+\t\treturn 1;\n+\n+\tstrbuf_add_commented_lines(&buf, msg, strlen(msg));\n+\n+\tif (get_missing_commit_check_level() == MISSING_COMMIT_CHECK_ERROR)\n+\t\tmsg = _(\"\\nDo not remove any line. Use 'drop' \"\n+\t\t\t \"explicitly to remove a commit.\\n\");\n+\telse\n+\t\tmsg = _(\"\\nIf you remove a line here \"\n+\t\t\t \"THAT COMMIT WILL BE LOST.\\n\");\n+\n+\tstrbuf_add_commented_lines(&buf, msg, strlen(msg));\n+\n+\tif (edit_todo)\n+\t\tmsg = _(\"\\nYou are editing the todo file \"\n+\t\t\t\"of an ongoing interactive rebase.\\n\"\n+\t\t\t\"To continue rebase after editing, run:\\n\"\n+\t\t\t\"    git rebase --continue\\n\\n\");\n+\telse\n+\t\tmsg = _(\"\\nHowever, if you remove everything, \"\n+\t\t\t\"the rebase will be aborted.\\n\\n\");\n+\n+\tstrbuf_add_commented_lines(&buf, msg, strlen(msg));\n+\n+\tif (!keep_empty) {\n+\t\tmsg = _(\"Note that empty commits are commented out\");\n+\t\tstrbuf_add_commented_lines(&buf, msg, strlen(msg));\n+\t}\n+\n+\tret = fputs(buf.buf, todo);\n+\tif (ret < 0)\n+\t\terror_errno(_(\"Could not append help text to '%s'\"), rebase_path_todo());\n+\n+\tfclose(todo);\n+\tstrbuf_release(&buf);\n+\n+\treturn ret;\n+}\ndiff --git a/rebase-interactive.h b/rebase-interactive.h\nnew file mode 100644\nindex 000000000..47372624e\n--- /dev/null\n+++ b/rebase-interactive.h\n@@ -0,0 +1,6 @@\n+#ifndef REBASE_INTERACTIVE_H\n+#define REBASE_INTERACTIVE_H\n+\n+int append_todo_help(unsigned edit_todo, unsigned keep_empty);\n+\n+#endif\n-- \n2.18.0\n\n"},{"id":"351519","messageId":"20180702105717.26386-5-alban.gruin@gmail.com","threadId":"48814","inReplyTo":"20180702105717.26386-1-alban.gruin@gmail.com","subject":"[GSoC][PATCH v2 4/7] rebase-interactive: rewrite the edit-todo functionality in C","fromName":"Alban Gruin","fromEmail":"alban.gruin@gmail.com","sentAt":"2018-07-02T10:57:14Z","receivedAt":"2018-07-02T10:58:14Z","isPatch":true,"sender":{"key":"alban.gruin@gmail.com","avatar":"https://avatars.githubusercontent.com/u/6310153?v=4"},"body":"This rewrites the edit-todo functionality from shell to C.\n\nTo achieve that, a new command mode, `edit-todo`, is added, and the\n`write-edit-todo` flag is removed, as the shell script does not need to\nwrite the edit todo help message to the todo list anymore.\n\nThe shell version is then stripped in favour of a call to the helper.\n\nSigned-off-by: Alban Gruin <alban.gruin@gmail.com>\n---\n builtin/rebase--helper.c   | 13 ++++++++-----\n git-rebase--interactive.sh | 11 +----------\n rebase-interactive.c       | 31 +++++++++++++++++++++++++++++++\n rebase-interactive.h       |  1 +\n 4 files changed, 41 insertions(+), 15 deletions(-)\n\ndiff --git a/builtin/rebase--helper.c b/builtin/rebase--helper.c\nindex 05e73e71d..731a64971 100644\n--- a/builtin/rebase--helper.c\n+++ b/builtin/rebase--helper.c\n@@ -13,12 +13,12 @@ static const char * const builtin_rebase_helper_usage[] = {\n int cmd_rebase__helper(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, write_edit_todo = 0;\n+\tunsigned flags = 0, keep_empty = 0, rebase_merges = 0;\n \tint abbreviate_commands = 0, rebase_cousins = -1;\n \tenum {\n \t\tCONTINUE = 1, ABORT, MAKE_SCRIPT, SHORTEN_OIDS, EXPAND_OIDS,\n \t\tCHECK_TODO_LIST, SKIP_UNNECESSARY_PICKS, REARRANGE_SQUASH,\n-\t\tADD_EXEC, APPEND_TODO_HELP\n+\t\tADD_EXEC, APPEND_TODO_HELP, EDIT_TODO\n \t} command = 0;\n \tstruct option options[] = {\n \t\tOPT_BOOL(0, \"ff\", &opts.allow_ff, N_(\"allow fast-forward\")),\n@@ -28,8 +28,6 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\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, \"write-edit-todo\", &write_edit_todo,\n-\t\t\t N_(\"append the edit-todo message to the todo-list\")),\n \t\tOPT_CMDMODE(0, \"continue\", &command, N_(\"continue rebase\"),\n \t\t\t\tCONTINUE),\n \t\tOPT_CMDMODE(0, \"abort\", &command, N_(\"abort rebase\"),\n@@ -50,6 +48,9 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\n \t\t\tN_(\"insert exec commands in todo list\"), ADD_EXEC),\n \t\tOPT_CMDMODE(0, \"append-todo-help\", &command,\n \t\t\t    N_(\"insert the help in the todo list\"), APPEND_TODO_HELP),\n+\t\tOPT_CMDMODE(0, \"edit-todo\", &command,\n+\t\t\t    N_(\"edit the todo list during an interactive rebase\"),\n+\t\t\t    EDIT_TODO),\n \t\tOPT_END()\n \t};\n \n@@ -90,6 +91,8 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\n \tif (command == ADD_EXEC && argc == 2)\n \t\treturn !!sequencer_add_exec_commands(argv[1]);\n \tif (command == APPEND_TODO_HELP && argc == 1)\n-\t\treturn !!append_todo_help(write_edit_todo, keep_empty);\n+\t\treturn !!append_todo_help(0, keep_empty);\n+\tif (command == EDIT_TODO && argc == 1)\n+\t\treturn !!edit_todo_list(flags);\n \tusage_with_options(builtin_rebase_helper_usage, options);\n }\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex 94c23a7af..2defe607f 100644\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -108,16 +108,7 @@ initiate_action () {\n \t\t     --continue\n \t\t;;\n \tedit-todo)\n-\t\tgit stripspace --strip-comments <\"$todo\" >\"$todo\".new\n-\t\tmv -f \"$todo\".new \"$todo\"\n-\t\tcollapse_todo_ids\n-\t\tgit rebase--helper --append-todo-help --write-edit-todo\n-\n-\t\tgit_sequence_editor \"$todo\" ||\n-\t\t\tdie \"$(gettext \"Could not execute editor\")\"\n-\t\texpand_todo_ids\n-\n-\t\texit\n+\t\texec git rebase--helper --edit-todo\n \t\t;;\n \tshow-current-patch)\n \t\texec git show REBASE_HEAD --\ndiff --git a/rebase-interactive.c b/rebase-interactive.c\nindex 015e08cd0..fb7ad401a 100644\n--- a/rebase-interactive.c\n+++ b/rebase-interactive.c\n@@ -66,3 +66,34 @@ int append_todo_help(unsigned edit_todo, unsigned keep_empty)\n \n \treturn ret;\n }\n+\n+int edit_todo_list(unsigned flags)\n+{\n+\tstruct strbuf buf = STRBUF_INIT;\n+\tconst char *todo_file = rebase_path_todo();\n+\tFILE *todo;\n+\n+\tif (strbuf_read_file(&buf, todo_file, 0) < 0)\n+\t\treturn error_errno(_(\"could not read '%s'.\"), todo_file);\n+\n+\tstrbuf_stripspace(&buf, 1);\n+\ttodo = fopen_or_warn(todo_file, \"w\");\n+\tif (!todo) {\n+\t\tstrbuf_release(&buf);\n+\t\treturn 1;\n+\t}\n+\n+\tstrbuf_write(&buf, todo);\n+\tfclose(todo);\n+\tstrbuf_release(&buf);\n+\n+\ttransform_todos(flags | TODO_LIST_SHORTEN_IDS);\n+\tappend_todo_help(1, 0);\n+\n+\tif (launch_sequence_editor(todo_file, NULL, NULL))\n+\t\treturn 1;\n+\n+\ttransform_todos(flags & ~(TODO_LIST_SHORTEN_IDS));\n+\n+\treturn 0;\n+}\ndiff --git a/rebase-interactive.h b/rebase-interactive.h\nindex 47372624e..155219e74 100644\n--- a/rebase-interactive.h\n+++ b/rebase-interactive.h\n@@ -2,5 +2,6 @@\n #define REBASE_INTERACTIVE_H\n \n int append_todo_help(unsigned edit_todo, unsigned keep_empty);\n+int edit_todo_list(unsigned flags);\n \n #endif\n-- \n2.18.0\n\n"},{"id":"351520","messageId":"20180702105717.26386-4-alban.gruin@gmail.com","threadId":"48814","inReplyTo":"20180702105717.26386-1-alban.gruin@gmail.com","subject":"[GSoC][PATCH v2 3/7] editor: add a function to launch the sequence editor","fromName":"Alban Gruin","fromEmail":"alban.gruin@gmail.com","sentAt":"2018-07-02T10:57:13Z","receivedAt":"2018-07-02T10:58:17Z","isPatch":true,"sender":{"key":"alban.gruin@gmail.com","avatar":"https://avatars.githubusercontent.com/u/6310153?v=4"},"body":"As part of the rewrite of interactive rebase, the sequencer will need to\nopen the sequence editor to allow the user to edit the todo list.\nInstead of duplicating the existing launch_editor() function, this\nrefactors it to a new function, launch_specified_editor(), which takes\nthe editor as a parameter, in addition to the path, the buffer and the\nenvironment variables.  launch_sequence_editor() is then added to launch\nthe sequence editor.\n\nSigned-off-by: Alban Gruin <alban.gruin@gmail.com>\n---\n cache.h  |  1 +\n editor.c | 27 +++++++++++++++++++++++++--\n strbuf.h |  2 ++\n 3 files changed, 28 insertions(+), 2 deletions(-)\n\ndiff --git a/cache.h b/cache.h\nindex d49092d94..33fa70f55 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -1472,6 +1472,7 @@ extern const char *fmt_name(const char *name, const char *email);\n extern const char *ident_default_name(void);\n extern const char *ident_default_email(void);\n extern const char *git_editor(void);\n+extern const char *git_sequence_editor(void);\n extern const char *git_pager(int stdout_is_tty);\n extern int is_terminal_dumb(void);\n extern int git_ident_config(const char *, const char *, void *);\ndiff --git a/editor.c b/editor.c\nindex 9a9b4e12d..c985eee1f 100644\n--- a/editor.c\n+++ b/editor.c\n@@ -1,4 +1,5 @@\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"strbuf.h\"\n #include \"run-command.h\"\n #include \"sigchain.h\"\n@@ -34,10 +35,21 @@ const char *git_editor(void)\n \treturn editor;\n }\n \n-int launch_editor(const char *path, struct strbuf *buffer, const char *const *env)\n+const char *git_sequence_editor(void)\n {\n-\tconst char *editor = git_editor();\n+\tconst char *editor = getenv(\"GIT_SEQUENCE_EDITOR\");\n+\n+\tif (!editor)\n+\t\tgit_config_get_string_const(\"sequence.editor\", &editor);\n+\tif (!editor)\n+\t\teditor = git_editor();\n \n+\treturn editor;\n+}\n+\n+static int launch_specified_editor(const char *editor, const char *path,\n+\t\t\t\t   struct strbuf *buffer, const char *const *env)\n+{\n \tif (!editor)\n \t\treturn error(\"Terminal is dumb, but EDITOR unset\");\n \n@@ -95,3 +107,14 @@ int launch_editor(const char *path, struct strbuf *buffer, const char *const *en\n \t\treturn error_errno(\"could not read file '%s'\", path);\n \treturn 0;\n }\n+\n+int launch_editor(const char *path, struct strbuf *buffer, const char *const *env)\n+{\n+\treturn launch_specified_editor(git_editor(), path, buffer, env);\n+}\n+\n+int launch_sequence_editor(const char *path, struct strbuf *buffer,\n+\t\t\t   const char *const *env)\n+{\n+\treturn launch_specified_editor(git_sequence_editor(), path, buffer, env);\n+}\ndiff --git a/strbuf.h b/strbuf.h\nindex 60a35aef1..66da9822f 100644\n--- a/strbuf.h\n+++ b/strbuf.h\n@@ -575,6 +575,8 @@ extern void strbuf_add_unique_abbrev(struct strbuf *sb,\n  * file's contents are not read into the buffer upon completion.\n  */\n extern int launch_editor(const char *path, struct strbuf *buffer, const char *const *env);\n+extern int launch_sequence_editor(const char *path, struct strbuf *buffer,\n+\t\t\t\t  const char *const *env);\n \n extern void strbuf_add_lines(struct strbuf *sb, const char *prefix, const char *buf, size_t size);\n \n-- \n2.18.0\n\n"},{"id":"351521","messageId":"20180702105717.26386-7-alban.gruin@gmail.com","threadId":"48814","inReplyTo":"20180702105717.26386-1-alban.gruin@gmail.com","subject":"[GSoC][PATCH v2 6/7] rebase -i: rewrite setup_reflog_action() in C","fromName":"Alban Gruin","fromEmail":"alban.gruin@gmail.com","sentAt":"2018-07-02T10:57:16Z","receivedAt":"2018-07-02T10:58:20Z","isPatch":true,"sender":{"key":"alban.gruin@gmail.com","avatar":"https://avatars.githubusercontent.com/u/6310153?v=4"},"body":"This rewrites (the misnamed) setup_reflog_action() from shell to C. The\nnew version is called prepare_branch_to_be_rebased().\n\nA new command is added to rebase--helper.c, “checkout-base”, as well as\na new flag, “verbose”, to avoid silencing the output of the checkout\noperation called by checkout_base_commit().\n\nThe function `run_git_checkout()` will also be used in the next commit,\ntherefore its code is not part of `checkout_base_commit()`.\n\nThe shell version is then stripped in favour of a call to the helper.\n\nAs $GIT_REFLOG_ACTION is no longer set at the first call of\ncheckout_onto(), a call to comment_for_reflog() is added at the\nbeginning of this function.\n\nSigned-off-by: Alban Gruin <alban.gruin@gmail.com>\n---\n builtin/rebase--helper.c   |  9 +++++++--\n git-rebase--interactive.sh | 16 ++--------------\n sequencer.c                | 30 ++++++++++++++++++++++++++++++\n sequencer.h                |  3 +++\n 4 files changed, 42 insertions(+), 16 deletions(-)\n\ndiff --git a/builtin/rebase--helper.c b/builtin/rebase--helper.c\nindex 731a64971..6c789e78b 100644\n--- a/builtin/rebase--helper.c\n+++ b/builtin/rebase--helper.c\n@@ -13,12 +13,12 @@ static const char * const builtin_rebase_helper_usage[] = {\n int cmd_rebase__helper(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;\n+\tunsigned flags = 0, keep_empty = 0, rebase_merges = 0, verbose = 0;\n \tint abbreviate_commands = 0, rebase_cousins = -1;\n \tenum {\n \t\tCONTINUE = 1, ABORT, MAKE_SCRIPT, SHORTEN_OIDS, EXPAND_OIDS,\n \t\tCHECK_TODO_LIST, SKIP_UNNECESSARY_PICKS, REARRANGE_SQUASH,\n-\t\tADD_EXEC, APPEND_TODO_HELP, EDIT_TODO\n+\t\tADD_EXEC, APPEND_TODO_HELP, EDIT_TODO, PREPARE_BRANCH\n \t} command = 0;\n \tstruct option options[] = {\n \t\tOPT_BOOL(0, \"ff\", &opts.allow_ff, N_(\"allow fast-forward\")),\n@@ -28,6 +28,7 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\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__VERBOSE(&verbose, N_(\"be verbose\")),\n \t\tOPT_CMDMODE(0, \"continue\", &command, N_(\"continue rebase\"),\n \t\t\t\tCONTINUE),\n \t\tOPT_CMDMODE(0, \"abort\", &command, N_(\"abort rebase\"),\n@@ -51,6 +52,8 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\n \t\tOPT_CMDMODE(0, \"edit-todo\", &command,\n \t\t\t    N_(\"edit the todo list during an interactive rebase\"),\n \t\t\t    EDIT_TODO),\n+\t\tOPT_CMDMODE(0, \"prepare-branch\", &command,\n+\t\t\t    N_(\"prepare the branch to be rebased\"), PREPARE_BRANCH),\n \t\tOPT_END()\n \t};\n \n@@ -94,5 +97,7 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\n \t\treturn !!append_todo_help(0, keep_empty);\n \tif (command == EDIT_TODO && argc == 1)\n \t\treturn !!edit_todo_list(flags);\n+\tif (command == PREPARE_BRANCH && argc == 2)\n+\t\treturn !!prepare_branch_to_be_rebased(&opts, argv[1], verbose);\n \tusage_with_options(builtin_rebase_helper_usage, options);\n }\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex 2defe607f..77e972bb6 100644\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -72,6 +72,7 @@ collapse_todo_ids() {\n \n # Switch to the branch in $into and notify it in the reflog\n checkout_onto () {\n+\tcomment_for_reflog start\n \tGIT_REFLOG_ACTION=\"$GIT_REFLOG_ACTION: checkout $onto_name\"\n \toutput git checkout $onto || die_abort \"$(gettext \"could not detach HEAD\")\"\n \tgit update-ref ORIG_HEAD $orig_head\n@@ -119,19 +120,6 @@ initiate_action () {\n \tesac\n }\n \n-setup_reflog_action () {\n-\tcomment_for_reflog start\n-\n-\tif test ! -z \"$switch_to\"\n-\tthen\n-\t\tGIT_REFLOG_ACTION=\"$GIT_REFLOG_ACTION: checkout $switch_to\"\n-\t\toutput git checkout \"$switch_to\" -- ||\n-\t\t\tdie \"$(eval_gettext \"Could not checkout \\$switch_to\")\"\n-\n-\t\tcomment_for_reflog start\n-\tfi\n-}\n-\n init_basic_state () {\n \torig_head=$(git rev-parse --verify HEAD) || die \"$(gettext \"No HEAD?\")\"\n \tmkdir -p \"$state_dir\" || die \"$(eval_gettext \"Could not create temporary \\$state_dir\")\"\n@@ -211,7 +199,7 @@ git_rebase__interactive () {\n \t\treturn 0\n \tfi\n \n-\tsetup_reflog_action\n+\tgit rebase--helper --prepare-branch \"$switch_to\" ${verbose:+--verbose}\n \tinit_basic_state\n \n \tinit_revisions_and_shortrevisions\ndiff --git a/sequencer.c b/sequencer.c\nindex 9e2b34a49..a61276d2c 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -3132,6 +3132,36 @@ 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\tint verbose, const char *action)\n+{\n+\tstruct child_process cmd = CHILD_PROCESS_INIT;\n+\n+\tcmd.git_cmd = 1;\n+\n+\targv_array_push(&cmd.args, \"checkout\");\n+\targv_array_push(&cmd.args, commit);\n+\targv_array_pushf(&cmd.env_array, GIT_REFLOG_ACTION \"=%s\", action);\n+\n+\tif (verbose)\n+\t\treturn run_command(&cmd);\n+\treturn run_command_silent_on_success(&cmd);\n+}\n+\n+int prepare_branch_to_be_rebased(struct replay_opts *opts, const char *commit,\n+\t\t\t\t int verbose)\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, verbose, action))\n+\t\t\treturn error(_(\"Could not checkout %s\"), commit);\n+\t}\n+\n+\treturn 0;\n+}\n+\n static const char rescheduled_advice[] =\n N_(\"Could not execute the todo command\\n\"\n \"\\n\"\ndiff --git a/sequencer.h b/sequencer.h\nindex ffab798f1..3821420b0 100644\n--- a/sequencer.h\n+++ b/sequencer.h\n@@ -106,6 +106,9 @@ int update_head_with_reflog(const struct commit *old_head,\n void commit_post_rewrite(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+\t\t\t\t int verbose);\n+\n #define SUMMARY_INITIAL_COMMIT   (1 << 0)\n #define SUMMARY_SHOW_AUTHOR_DATE (1 << 1)\n void print_commit_summary(const char *prefix, const struct object_id *oid,\n-- \n2.18.0\n\n"},{"id":"351522","messageId":"20180702105717.26386-8-alban.gruin@gmail.com","threadId":"48814","inReplyTo":"20180702105717.26386-1-alban.gruin@gmail.com","subject":"[GSoC][PATCH v2 7/7] rebase -i: rewrite checkout_onto() in C","fromName":"Alban Gruin","fromEmail":"alban.gruin@gmail.com","sentAt":"2018-07-02T10:57:17Z","receivedAt":"2018-07-02T10:58:23Z","isPatch":true,"sender":{"key":"alban.gruin@gmail.com","avatar":"https://avatars.githubusercontent.com/u/6310153?v=4"},"body":"This rewrites checkout_onto() from shell to C.\n\nA new command (“checkout-onto”) is added to rebase--helper.c. The shell\nversion is then stripped.\n\nSigned-off-by: Alban Gruin <alban.gruin@gmail.com>\n---\n builtin/rebase--helper.c   |  7 ++++++-\n git-rebase--interactive.sh | 25 ++++---------------------\n sequencer.c                | 19 +++++++++++++++++++\n sequencer.h                |  3 +++\n 4 files changed, 32 insertions(+), 22 deletions(-)\n\ndiff --git a/builtin/rebase--helper.c b/builtin/rebase--helper.c\nindex 6c789e78b..0091e094b 100644\n--- a/builtin/rebase--helper.c\n+++ b/builtin/rebase--helper.c\n@@ -18,7 +18,8 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\n \tenum {\n \t\tCONTINUE = 1, ABORT, MAKE_SCRIPT, SHORTEN_OIDS, EXPAND_OIDS,\n \t\tCHECK_TODO_LIST, SKIP_UNNECESSARY_PICKS, REARRANGE_SQUASH,\n-\t\tADD_EXEC, APPEND_TODO_HELP, EDIT_TODO, PREPARE_BRANCH\n+\t\tADD_EXEC, APPEND_TODO_HELP, EDIT_TODO, PREPARE_BRANCH,\n+\t\tCHECKOUT_ONTO\n \t} command = 0;\n \tstruct option options[] = {\n \t\tOPT_BOOL(0, \"ff\", &opts.allow_ff, N_(\"allow fast-forward\")),\n@@ -54,6 +55,8 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\n \t\t\t    EDIT_TODO),\n \t\tOPT_CMDMODE(0, \"prepare-branch\", &command,\n \t\t\t    N_(\"prepare the branch to be rebased\"), PREPARE_BRANCH),\n+\t\tOPT_CMDMODE(0, \"checkout-onto\", &command,\n+\t\t\t    N_(\"checkout a commit\"), CHECKOUT_ONTO),\n \t\tOPT_END()\n \t};\n \n@@ -99,5 +102,7 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\n \t\treturn !!edit_todo_list(flags);\n \tif (command == PREPARE_BRANCH && argc == 2)\n \t\treturn !!prepare_branch_to_be_rebased(&opts, argv[1], verbose);\n+\tif (command == CHECKOUT_ONTO && argc == 4)\n+\t\treturn !!checkout_onto(&opts, argv[1], argv[2], argv[3], verbose);\n \tusage_with_options(builtin_rebase_helper_usage, options);\n }\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex 77e972bb6..b68f108f2 100644\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -28,17 +28,6 @@ case \"$comment_char\" in\n \t;;\n esac\n \n-orig_reflog_action=\"$GIT_REFLOG_ACTION\"\n-\n-comment_for_reflog () {\n-\tcase \"$orig_reflog_action\" in\n-\t''|rebase*)\n-\t\tGIT_REFLOG_ACTION=\"rebase -i ($1)\"\n-\t\texport GIT_REFLOG_ACTION\n-\t\t;;\n-\tesac\n-}\n-\n die_abort () {\n \tapply_autostash\n \trm -rf \"$state_dir\"\n@@ -70,14 +59,6 @@ collapse_todo_ids() {\n \tgit rebase--helper --shorten-ids\n }\n \n-# Switch to the branch in $into and notify it in the reflog\n-checkout_onto () {\n-\tcomment_for_reflog start\n-\tGIT_REFLOG_ACTION=\"$GIT_REFLOG_ACTION: checkout $onto_name\"\n-\toutput git checkout $onto || die_abort \"$(gettext \"could not detach HEAD\")\"\n-\tgit update-ref ORIG_HEAD $orig_head\n-}\n-\n get_missing_commit_check_level () {\n \tcheck_level=$(git config --get rebase.missingCommitsCheck)\n \tcheck_level=${check_level:-ignore}\n@@ -176,7 +157,8 @@ EOF\n \n \tgit rebase--helper --check-todo-list || {\n \t\tret=$?\n-\t\tcheckout_onto\n+\t\tgit rebase--helper --checkout-onto \"$onto_name\" \"$onto\" \\\n+\t\t    \"$orig_head\" ${verbose:+--verbose}\n \t\texit $ret\n \t}\n \n@@ -186,7 +168,8 @@ EOF\n \tonto=\"$(git rebase--helper --skip-unnecessary-picks)\" ||\n \tdie \"Could not skip unnecessary pick commands\"\n \n-\tcheckout_onto\n+\tgit rebase--helper --checkout-onto \"$onto_name\" \"$onto\" \"$orig_head\" \\\n+\t    ${verbose:+--verbose}\n \trequire_clean_work_tree \"rebase\"\n \texec git rebase--helper ${force_rebase:+--no-ff} $allow_empty_message \\\n \t     --continue\ndiff --git a/sequencer.c b/sequencer.c\nindex a61276d2c..bc0836ac9 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -3162,6 +3162,25 @@ int prepare_branch_to_be_rebased(struct replay_opts *opts, const char *commit,\n \treturn 0;\n }\n \n+int checkout_onto(struct replay_opts *opts,\n+\t\t  const char *onto_name, const char *onto,\n+\t\t  const char *orig_head, unsigned verbose)\n+{\n+\tstruct object_id oid;\n+\tconst char *action = reflog_message(opts, \"start\", \"checkout %s\", onto_name);\n+\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, verbose, action)) {\n+\t\tapply_autostash(opts);\n+\t\tsequencer_remove_state(opts);\n+\t\treturn error(_(\"could not detach HEAD\"));\n+\t}\n+\n+\treturn update_ref(NULL, \"ORIG_HEAD\", &oid, NULL, 0, UPDATE_REFS_MSG_ON_ERR);\n+}\n+\n static const char rescheduled_advice[] =\n N_(\"Could not execute the todo command\\n\"\n \"\\n\"\ndiff --git a/sequencer.h b/sequencer.h\nindex 3821420b0..ba5e59f02 100644\n--- a/sequencer.h\n+++ b/sequencer.h\n@@ -108,6 +108,9 @@ void commit_post_rewrite(const struct commit *current_head,\n \n int prepare_branch_to_be_rebased(struct replay_opts *opts, const char *commit,\n \t\t\t\t int verbose);\n+int checkout_onto(struct replay_opts *opts,\n+\t\t  const char *onto_name, const char *onto,\n+\t\t  const char *orig_head, unsigned verbose);\n \n #define SUMMARY_INITIAL_COMMIT   (1 << 0)\n #define SUMMARY_SHOW_AUTHOR_DATE (1 << 1)\n-- \n2.18.0\n\n"},{"id":"351523","messageId":"20180702105717.26386-6-alban.gruin@gmail.com","threadId":"48814","inReplyTo":"20180702105717.26386-1-alban.gruin@gmail.com","subject":"[GSoC][PATCH v2 5/7] sequencer: add a new function to silence a command, except if it fails.","fromName":"Alban Gruin","fromEmail":"alban.gruin@gmail.com","sentAt":"2018-07-02T10:57:15Z","receivedAt":"2018-07-02T10:58:26Z","isPatch":true,"sender":{"key":"alban.gruin@gmail.com","avatar":"https://avatars.githubusercontent.com/u/6310153?v=4"},"body":"This adds a new function, run_command_silent_on_success(), to\nredirect the stdout and stderr of a command to a strbuf, and then to run\nthat command. This strbuf is printed only if the command fails. It is\nfunctionnaly similar to output() from git-rebase.sh.\n\nrun_git_commit() is then refactored to use of\nrun_command_silent_on_success().\n\nSigned-off-by: Alban Gruin <alban.gruin@gmail.com>\n---\n sequencer.c | 49 ++++++++++++++++++++++++-------------------------\n 1 file changed, 24 insertions(+), 25 deletions(-)\n\ndiff --git a/sequencer.c b/sequencer.c\nindex 57fd58bc1..9e2b34a49 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -768,6 +768,24 @@ N_(\"you have staged changes in your working tree\\n\"\n #define VERIFY_MSG  (1<<4)\n #define CREATE_ROOT_COMMIT (1<<5)\n \n+static int run_command_silent_on_success(struct child_process *cmd)\n+{\n+\tstruct strbuf buf = STRBUF_INIT;\n+\tint rc;\n+\n+\tcmd->stdout_to_stderr = 1;\n+\trc = pipe_command(cmd,\n+\t\t\t  NULL, 0,\n+\t\t\t  /* stdout is already redirected */\n+\t\t\t  NULL, 0,\n+\t\t\t  &buf, 0);\n+\n+\tif (rc)\n+\t\tfputs(buf.buf, stderr);\n+\tstrbuf_release(&buf);\n+\treturn rc;\n+}\n+\n /*\n  * If we are cherry-pick, and if the merge did not result in\n  * hand-editing, we will hit this commit and inherit the original\n@@ -822,18 +840,11 @@ static int run_git_commit(const char *defmsg, struct replay_opts *opts,\n \n \tcmd.git_cmd = 1;\n \n-\tif (is_rebase_i(opts)) {\n-\t\tif (!(flags & EDIT_MSG)) {\n-\t\t\tcmd.stdout_to_stderr = 1;\n-\t\t\tcmd.err = -1;\n-\t\t}\n+\tif (is_rebase_i(opts) && read_env_script(&cmd.env_array)) {\n+\t\tconst char *gpg_opt = gpg_sign_opt_quoted(opts);\n \n-\t\tif (read_env_script(&cmd.env_array)) {\n-\t\t\tconst char *gpg_opt = gpg_sign_opt_quoted(opts);\n-\n-\t\t\treturn error(_(staged_changes_advice),\n-\t\t\t\t     gpg_opt, gpg_opt);\n-\t\t}\n+\t\treturn error(_(staged_changes_advice),\n+\t\t\t     gpg_opt, gpg_opt);\n \t}\n \n \targv_array_push(&cmd.args, \"commit\");\n@@ -863,20 +874,8 @@ static int run_git_commit(const char *defmsg, struct replay_opts *opts,\n \tif (opts->allow_empty_message)\n \t\targv_array_push(&cmd.args, \"--allow-empty-message\");\n \n-\tif (cmd.err == -1) {\n-\t\t/* hide stderr on success */\n-\t\tstruct strbuf buf = STRBUF_INIT;\n-\t\tint rc = pipe_command(&cmd,\n-\t\t\t\t      NULL, 0,\n-\t\t\t\t      /* stdout is already redirected */\n-\t\t\t\t      NULL, 0,\n-\t\t\t\t      &buf, 0);\n-\t\tif (rc)\n-\t\t\tfputs(buf.buf, stderr);\n-\t\tstrbuf_release(&buf);\n-\t\treturn rc;\n-\t}\n-\n+\tif (is_rebase_i(opts) && !(flags & EDIT_MSG))\n+\t\treturn run_command_silent_on_success(&cmd);\n \treturn run_command(&cmd);\n }\n \n-- \n2.18.0\n\n"},{"id":"351647","messageId":"xmqqsh50oyu4.fsf@gitster-ct.c.googlers.com","threadId":"48814","inReplyTo":"20180702105717.26386-2-alban.gruin@gmail.com","subject":"Re: [GSoC][PATCH v2 1/7] sequencer: make two functions and an enum from sequencer.c public","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2018-07-03T20:20:51Z","receivedAt":"2018-07-03T20:20:56Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Alban Gruin <alban.gruin@gmail.com> writes:\n\n> -enum check_level {\n> -\tCHECK_IGNORE = 0, CHECK_WARN, CHECK_ERROR\n> -};\n> -\n> -static enum check_level get_missing_commit_check_level(void)\n> +enum missing_commit_check_level get_missing_commit_check_level(void)\n\nThe new name definitely is better than \"check_level\" in the global\ncontext, but \"missing_commit\" is much less important thing to say\nthan \"this symbol is to be used when driving 'rebase' (or even\n'rebase-i')\", I think.  \"enum rebase_i_drop_commit_check\" with\n\"get_rebase_i_drop_commit_check()\" perhaps?\n"},{"id":"351648","messageId":"xmqqlgasoyfd.fsf@gitster-ct.c.googlers.com","threadId":"48814","inReplyTo":"20180702105717.26386-3-alban.gruin@gmail.com","subject":"Re: [GSoC][PATCH v2 2/7] rebase--interactive: rewrite append_todo_help() in C","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2018-07-03T20:29:42Z","receivedAt":"2018-07-03T20:29:47Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Alban Gruin <alban.gruin@gmail.com> writes:\n\n> +\tret = fputs(buf.buf, todo);\n> +\tif (ret < 0)\n> +\t\terror_errno(_(\"Could not append help text to '%s'\"), rebase_path_todo());\n\nError checking fputs() return is an improvement from the version\nthat has been queued on 'pu'.  I think messages given to error() and\nfriends begin with lowercase uncapitalized by convention, though.\n\n> +\tfclose(todo);\n> +\tstrbuf_release(&buf);\n> +\n> +\treturn ret;\n> +}\n> diff --git a/rebase-interactive.h b/rebase-interactive.h\n> new file mode 100644\n> index 000000000..47372624e\n> --- /dev/null\n> +++ b/rebase-interactive.h\n> @@ -0,0 +1,6 @@\n> +#ifndef REBASE_INTERACTIVE_H\n> +#define REBASE_INTERACTIVE_H\n> +\n> +int append_todo_help(unsigned edit_todo, unsigned keep_empty);\n> +\n> +#endif\n"},{"id":"351649","messageId":"xmqqh8lgoyaa.fsf@gitster-ct.c.googlers.com","threadId":"48814","inReplyTo":"20180702105717.26386-4-alban.gruin@gmail.com","subject":"Re: [GSoC][PATCH v2 3/7] editor: add a function to launch the sequence editor","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2018-07-03T20:32:45Z","receivedAt":"2018-07-03T20:33:55Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Alban Gruin <alban.gruin@gmail.com> writes:\n\n> As part of the rewrite of interactive rebase, the sequencer will need to\n> open the sequence editor to allow the user to edit the todo list.\n> Instead of duplicating the existing launch_editor() function, this\n> refactors it to a new function, launch_specified_editor(), which takes\n> the editor as a parameter, in addition to the path, the buffer and the\n> environment variables.  launch_sequence_editor() is then added to launch\n> the sequence editor.\n>\n> Signed-off-by: Alban Gruin <alban.gruin@gmail.com>\n> ---\n\nLooks the same from the previous round, and the changes look good.\n\nYou can say \"Unchanged from what has been queued on 'pu'\" or\nsomesuch to save reviewer's time after the line with three-dashes\n\nThansk.\n"},{"id":"351650","messageId":"xmqqd0w4oy4q.fsf@gitster-ct.c.googlers.com","threadId":"48814","inReplyTo":"20180702105717.26386-6-alban.gruin@gmail.com","subject":"Re: [GSoC][PATCH v2 5/7] sequencer: add a new function to silence a command, except if it fails.","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2018-07-03T20:36:05Z","receivedAt":"2018-07-03T20:36:11Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Alban Gruin <alban.gruin@gmail.com> writes:\n\n> Subject: Re: [GSoC][PATCH v2 5/7] sequencer: add a new function to silence a command, except if it fails.\n\nLose the full-stop at the end.\n\n> This adds a new function, run_command_silent_on_success(), to\n> redirect the stdout and stderr of a command to a strbuf, and then to run\n> that command. This strbuf is printed only if the command fails. It is\n> functionnaly similar to output() from git-rebase.sh.\n>\n> run_git_commit() is then refactored to use of\n> run_command_silent_on_success().\n>\n> Signed-off-by: Alban Gruin <alban.gruin@gmail.com>\n> ---\n>  sequencer.c | 49 ++++++++++++++++++++++++-------------------------\n>  1 file changed, 24 insertions(+), 25 deletions(-)\n>\n> diff --git a/sequencer.c b/sequencer.c\n> index 57fd58bc1..9e2b34a49 100644\n> --- a/sequencer.c\n> +++ b/sequencer.c\n> @@ -768,6 +768,24 @@ N_(\"you have staged changes in your working tree\\n\"\n>  #define VERIFY_MSG  (1<<4)\n>  #define CREATE_ROOT_COMMIT (1<<5)\n>  \n> +static int run_command_silent_on_success(struct child_process *cmd)\n> +{\n> +\tstruct strbuf buf = STRBUF_INIT;\n> +\tint rc;\n> +\n> +\tcmd->stdout_to_stderr = 1;\n> +\trc = pipe_command(cmd,\n> +\t\t\t  NULL, 0,\n> +\t\t\t  /* stdout is already redirected */\n\nAre we reviewing the correct version?\n\nI thought we discarded this comment in the previous round.\n\n> +\t\t\t  NULL, 0,\n> +\t\t\t  &buf, 0);\n\n"},{"id":"351651","messageId":"xmqq8t6soy2f.fsf@gitster-ct.c.googlers.com","threadId":"48814","inReplyTo":"20180702105717.26386-7-alban.gruin@gmail.com","subject":"Re: [GSoC][PATCH v2 6/7] rebase -i: rewrite setup_reflog_action() in C","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2018-07-03T20:37:28Z","receivedAt":"2018-07-03T20:37:33Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Alban Gruin <alban.gruin@gmail.com> writes:\n\n> +static int run_git_checkout(struct replay_opts *opts, const char *commit,\n> +\t\t\t\tint verbose, const char *action)\n> +{\n> +\tstruct child_process cmd = CHILD_PROCESS_INIT;\n> +\n> +\tcmd.git_cmd = 1;\n> +\n> +\targv_array_push(&cmd.args, \"checkout\");\n> +\targv_array_push(&cmd.args, commit);\n> +\targv_array_pushf(&cmd.env_array, GIT_REFLOG_ACTION \"=%s\", action);\n> +\n> +\tif (verbose)\n> +\t\treturn run_command(&cmd);\n> +\treturn run_command_silent_on_success(&cmd);\n\nI thought we made this into\n\n\tif verbose\n\t\treturn run_command\n\telse\n\t\treturn run_command_silently\n\nto help readers in the previous round already.\n\nAre we reviewing the correct version?\n"},{"id":"351708","messageId":"d9ee3afd-2464-0a7c-d55f-951b89777d27@gmail.com","threadId":"48814","inReplyTo":"xmqqsh50oyu4.fsf@gitster-ct.c.googlers.com","subject":"Re: [GSoC][PATCH v2 1/7] sequencer: make two functions and an enum from sequencer.c public","fromName":"Alban Gruin","fromEmail":"alban.gruin@gmail.com","sentAt":"2018-07-05T15:35:11Z","receivedAt":"2018-07-05T15:35:18Z","isPatch":true,"sender":{"key":"alban.gruin@gmail.com","avatar":"https://avatars.githubusercontent.com/u/6310153?v=4"},"body":"Hi Junio,\n\nLe 03/07/2018 à 22:20, Junio C Hamano a écrit :\n> Alban Gruin <alban.gruin@gmail.com> writes:\n> \n>> -enum check_level {\n>> -\tCHECK_IGNORE = 0, CHECK_WARN, CHECK_ERROR\n>> -};\n>> -\n>> -static enum check_level get_missing_commit_check_level(void)\n>> +enum missing_commit_check_level get_missing_commit_check_level(void)\n> \n> The new name definitely is better than \"check_level\" in the global\n> context, but \"missing_commit\" is much less important thing to say\n> than \"this symbol is to be used when driving 'rebase' (or even\n> 'rebase-i')\", I think.  \"enum rebase_i_drop_commit_check\" with\n> \"get_rebase_i_drop_commit_check()\" perhaps?\n> \n\nI don’t really like those names, but the function and the enum should\neventually move to rebase-interactive.c and become static again, so we\ncould revert their names in due course.\n\nCheers,\nAlban\n\n"},{"id":"351777","messageId":"nycvar.QRO.7.76.6.1807061457250.75@tvgsbejvaqbjf.bet","threadId":"48814","inReplyTo":"xmqq8t6soy2f.fsf@gitster-ct.c.googlers.com","subject":"Re: [GSoC][PATCH v2 6/7] rebase -i: rewrite setup_reflog_action() in C","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2018-07-06T12:58:32Z","receivedAt":"2018-07-06T12:59:03Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Junio,\n\nOn Tue, 3 Jul 2018, Junio C Hamano wrote:\n\n> Alban Gruin <alban.gruin@gmail.com> writes:\n> \n> > +static int run_git_checkout(struct replay_opts *opts, const char *commit,\n> > +\t\t\t\tint verbose, const char *action)\n> > +{\n> > +\tstruct child_process cmd = CHILD_PROCESS_INIT;\n> > +\n> > +\tcmd.git_cmd = 1;\n> > +\n> > +\targv_array_push(&cmd.args, \"checkout\");\n> > +\targv_array_push(&cmd.args, commit);\n> > +\targv_array_pushf(&cmd.env_array, GIT_REFLOG_ACTION \"=%s\", action);\n> > +\n> > +\tif (verbose)\n> > +\t\treturn run_command(&cmd);\n> > +\treturn run_command_silent_on_success(&cmd);\n> \n> I thought we made this into\n> \n> \tif verbose\n> \t\treturn run_command\n> \telse\n> \t\treturn run_command_silently\n> \n> to help readers in the previous round already.\n\nFWIW we had quite a couple of reviews in the recent years which pointed\nout \"unnecessary else\" after returning or die()ing. Maybe we should make\nup our minds, and set a consistent rule to follow.\n\nCiao,\nDscho\n"},{"id":"351779","messageId":"xmqqy3eommq2.fsf@gitster-ct.c.googlers.com","threadId":"48814","inReplyTo":"nycvar.QRO.7.76.6.1807061457250.75@tvgsbejvaqbjf.bet","subject":"Re: [GSoC][PATCH v2 6/7] rebase -i: rewrite setup_reflog_action() in C","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2018-07-06T15:02:13Z","receivedAt":"2018-07-06T15:02:54Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n\n>> I thought we made this into\n>> \n>> \tif verbose\n>> \t\treturn run_command\n>> \telse\n>> \t\treturn run_command_silently\n>> \n>> to help readers in the previous round already.\n>\n> FWIW we had quite a couple of reviews in the recent years which pointed\n> out \"unnecessary else\" after returning or die()ing. Maybe we should make\n> up our minds, and set a consistent rule to follow.\n\nFWIW the pattern you are referring to is\n\n\tdo something;\n\tif (error detected) {\n\t\treturn error(...);\n\t} else {\n\t\tperform\n\t\tremaining\n\t\tactions\n\t\tthe function needs\n\t\tto complete\n\t        its task;\n\t}\n\nand those reviewers (including me) are absolutely right that such an\n\"else\" is not just unnecessary but actively harms readability of the\nflow of logic.\n\nI am also absolutely right when I say what is quoted at the top\nmakes 100% more sense than\n\n\tif (verbose)\n        \treturn run_command();\n\treturn run_command_silently();\n\nas these two are about doing the same thing a bit differently.  \n\nThe way to think about the latter is that we won't have this \"if\n(verbose)\" if there were a variant of run_command() that took a set\nof option bits among which is a verbose bit, but instead would have\na single call to that function that returns..  So it's not like \"in\nan exceptional case, return after calling this function; otherwise\nkeep going, which happens to only return after calling another\".  It\nis more like \"here we need to return after spawning a command, but\ndepending on this bit, we spawn the command using a different\nfunction\".\n\nGood programers recognize the difference between these two patterns\nwithout being told, and mentors should teach and GSoC student should\nlearn that an overly simplified rule like \"when 'if' block ends with\nreturn, do not write 'else'\" is harmful.\n"},{"id":"351791","messageId":"nycvar.QRO.7.76.6.1807062052230.75@tvgsbejvaqbjf.bet","threadId":"48814","inReplyTo":"xmqqy3eommq2.fsf@gitster-ct.c.googlers.com","subject":"Re: [GSoC][PATCH v2 6/7] rebase -i: rewrite setup_reflog_action() in C","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2018-07-06T18:54:35Z","receivedAt":"2018-07-06T18:55:05Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Junio,\n\nOn Fri, 6 Jul 2018, Junio C Hamano wrote:\n\n> Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n> \n> >> I thought we made this into\n> >> \n> >> \tif verbose\n> >> \t\treturn run_command\n> >> \telse\n> >> \t\treturn run_command_silently\n> >> \n> >> to help readers in the previous round already.\n> >\n> > FWIW we had quite a couple of reviews in the recent years which pointed\n> > out \"unnecessary else\" after returning or die()ing. Maybe we should make\n> > up our minds, and set a consistent rule to follow.\n> \n> FWIW the pattern you are referring to is\n> \n> \tdo something;\n> \tif (error detected) {\n> \t\treturn error(...);\n> \t} else {\n> \t\tperform\n> \t\tremaining\n> \t\tactions\n> \t\tthe function needs\n> \t\tto complete\n> \t        its task;\n> \t}\n> \n> and those reviewers (including me) are absolutely right that such an\n> \"else\" is not just unnecessary but actively harms readability of the\n> flow of logic.\n> \n> I am also absolutely right when I say what is quoted at the top\n> makes 100% more sense than\n> \n> \tif (verbose)\n>         \treturn run_command();\n> \treturn run_command_silently();\n> \n> as these two are about doing the same thing a bit differently.  \n> \n> The way to think about the latter is that we won't have this \"if\n> (verbose)\" if there were a variant of run_command() that took a set\n> of option bits among which is a verbose bit, but instead would have\n> a single call to that function that returns..  So it's not like \"in\n> an exceptional case, return after calling this function; otherwise\n> keep going, which happens to only return after calling another\".  It\n> is more like \"here we need to return after spawning a command, but\n> depending on this bit, we spawn the command using a different\n> function\".\n> \n> Good programers recognize the difference between these two patterns\n> without being told, and mentors should teach and GSoC student should\n> learn that an overly simplified rule like \"when 'if' block ends with\n> return, do not write 'else'\" is harmful.\n\nYou recently also suggested this if...else... dance to Pratik, where it\nwas not at all about doing the same thing slightly differently, but rather\ntwo different things: 1) return an error because execvp() returned an\nerror, 2) indicate a serious bug (and you did not even suggest using BUG()\nIIRC which is also wrong).\n\nMaybe I am the only one who finds this inconsistent and confusing. If that\nis that case, I'll quiet down.\n\nCiao,\nJohannes\n"},{"id":"351825","messageId":"xmqq7em8hvv9.fsf@gitster-ct.c.googlers.com","threadId":"48814","inReplyTo":"nycvar.QRO.7.76.6.1807062052230.75@tvgsbejvaqbjf.bet","subject":"Re: [GSoC][PATCH v2 6/7] rebase -i: rewrite setup_reflog_action() in C","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2018-07-06T21:55:54Z","receivedAt":"2018-07-06T21:56:00Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n\n> You recently also suggested this if...else... dance to Pratik, where it\n> was not at all about doing the same thing slightly differently, but rather\n> two different things: 1) return an error because execvp() returned an\n> error, 2) indicate a serious bug (and you did not even suggest using BUG()\n> IIRC which is also wrong).\n\nI was going to avoid wasting time on this topic, but I happened to\nhave a chance to review the execvp() thing.  \n\nI actually think that is a good example of doing the same thing\nslightly differently.  We want to abort the process when execvp()\ngives control back to that caller, and we want to do so with\ndie_errno() when we know we have errno (i.e. sane_execvp() gave us\nnegative).  When sane_execvp() gave control back to us with\nnon-negative return, we cannot use die_errno(), but we would want to\nabort the process regardless, as it is an indication that the callee\nis not sane after all ;-)  It is a bug in underlying execvp() that\nwe cannot do much about, though.\n\n\n"},{"id":"351849","messageId":"xmqq36wvgfs4.fsf@gitster-ct.c.googlers.com","threadId":"48814","inReplyTo":"xmqq7em8hvv9.fsf@gitster-ct.c.googlers.com","subject":"Re: [GSoC][PATCH v2 6/7] rebase -i: rewrite setup_reflog_action() in C","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2018-07-07T16:40:59Z","receivedAt":"2018-07-07T16:41:05Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Junio C Hamano <gitster@pobox.com> writes:\n\n> I actually think that is a good example of doing the same thing\n> slightly differently.  ...\n\n[jc: Beating the dead horse, only to avoid misleading those who are\nlearning from the sidelines...]\n\nThe above was a stupid thing to say and end the message with, as it\nmade it sound as if there are only two cases and we have a simple\n(but not that simple as alluded to earlier by Dscho that essentially\nsays not to write 'else' when 'if' body returns or exits) rule that\nyou should blindly apply after telling these two cases apart.  \n\nThat is a total opposite of the message that should be read from the\nwhole thread.\n\n"},{"id":"352088","messageId":"20180710121557.6698-1-alban.gruin@gmail.com","threadId":"48814","inReplyTo":"20180702105717.26386-1-alban.gruin@gmail.com","subject":"[GSoC][PATCH v3 00/13] rebase -i: rewrite some parts in C","fromName":"Alban Gruin","fromEmail":"alban.gruin@gmail.com","sentAt":"2018-07-10T12:15:44Z","receivedAt":"2018-07-10T12:17:15Z","isPatch":true,"sender":{"key":"alban.gruin@gmail.com","avatar":"https://avatars.githubusercontent.com/u/6310153?v=4"},"body":"This patch series rewrites some parts of interactive rebase from shell\nto C:\n\n - append_todo_help(). The C version covers a bit more than the shell\n   version.\n\n - The edit-todo functionnality.\n\n - The reflog operations.\n\n - complete_action().\n\n - init_revisions_and_shortrevisions().\n\nThis patch series is based on master (as of 2018-07-10).\n\nChanges since v2:\n\n - Lowercasing error messages.\n\n - Removing a comment from run_command_silent_on_success().\n\n - Using the `else` keyword to call run_command_silent_on_success() or\n   run_command() in run_git_commit() and run_git_checkout().\n\n - Dropping the `verbose` parameter in run_git_checkout(),\n   prepare_branch_to_be_rebased(), and checkout_onto(), as the\n   replay_opts structure already has a `verbose` field.\n\n - Rewriting complete_action() and init_revisions_and_shortrevisions().\n\nAlban Gruin (13):\n  sequencer: make two functions and an enum from sequencer.c public\n  rebase--interactive: rewrite append_todo_help() in C\n  editor: add a function to launch the sequence editor\n  rebase-interactive: rewrite the edit-todo functionality in C\n  sequencer: add a new function to silence a command, except if it fails\n  rebase -i: rewrite setup_reflog_action() in C\n  rebase -i: rewrite checkout_onto() in C\n  sequencer: refactor append_todo_help() to write its message to a\n    buffer\n  sequencer: change the way skip_unnecessary_picks() returns its result\n  rebase--interactive: rewrite complete_action() in C\n  rebase--interactive: remove unused modes and functions\n  rebase -i: implement the logic to initialize the variable $revision in\n    C\n  rebase -i: rewrite the rest of init_revisions_and_shortrevisions in C\n\n Makefile                   |   1 +\n builtin/rebase--helper.c   | 123 +++++++++++++++++----\n cache.h                    |   1 +\n editor.c                   |  27 ++++-\n git-rebase--interactive.sh | 216 ++-----------------------------------\n git-rebase.sh              |   2 +-\n rebase-interactive.c       |  96 +++++++++++++++++\n rebase-interactive.h       |  11 ++\n sequencer.c                | 215 +++++++++++++++++++++++++++++-------\n sequencer.h                |  15 ++-\n strbuf.h                   |   2 +\n 11 files changed, 439 insertions(+), 270 deletions(-)\n create mode 100644 rebase-interactive.c\n create mode 100644 rebase-interactive.h\n\n-- \n2.18.0\n\n"},{"id":"352089","messageId":"20180710121557.6698-2-alban.gruin@gmail.com","threadId":"48814","inReplyTo":"20180710121557.6698-1-alban.gruin@gmail.com","subject":"[GSoC][PATCH v3 01/13] sequencer: make two functions and an enum from sequencer.c public","fromName":"Alban Gruin","fromEmail":"alban.gruin@gmail.com","sentAt":"2018-07-10T12:15:45Z","receivedAt":"2018-07-10T12:17:19Z","isPatch":true,"sender":{"key":"alban.gruin@gmail.com","avatar":"https://avatars.githubusercontent.com/u/6310153?v=4"},"body":"This makes rebase_path_todo(), get_missing_commit_check_level() and the\nenum check_level accessible outside sequencer.c.  check_level is renamed\nmissing_commit_check_level, and its value names are prefixed by\nMISSING_COMMIT_ to avoid namespace pollution.\n\nThis function and this enum will eventually be moved to\nrebase-interactive.c and become static again, so no special attention\nwas given to the naming.\n\nThis will be needed for the rewrite of append_todo_help() from shell to\nC, as it will be in a new library source file, rebase-interactive.c.\n\nSigned-off-by: Alban Gruin <alban.gruin@gmail.com>\n---\nUnchanged from v2.\n\n sequencer.c | 22 +++++++++-------------\n sequencer.h |  8 ++++++++\n 2 files changed, 17 insertions(+), 13 deletions(-)\n\ndiff --git a/sequencer.c b/sequencer.c\nindex 5354d4d51..57fd58bc1 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -51,7 +51,7 @@ static GIT_PATH_FUNC(rebase_path, \"rebase-merge\")\n  * the lines are processed, they are removed from the front of this\n  * file and written to the tail of 'done'.\n  */\n-static GIT_PATH_FUNC(rebase_path_todo, \"rebase-merge/git-rebase-todo\")\n+GIT_PATH_FUNC(rebase_path_todo, \"rebase-merge/git-rebase-todo\")\n /*\n  * The rebase command lines that have already been processed. A line\n  * is moved here when it is first handled, before any associated user\n@@ -4221,24 +4221,20 @@ int transform_todos(unsigned flags)\n \treturn i;\n }\n \n-enum check_level {\n-\tCHECK_IGNORE = 0, CHECK_WARN, CHECK_ERROR\n-};\n-\n-static enum check_level get_missing_commit_check_level(void)\n+enum missing_commit_check_level get_missing_commit_check_level(void)\n {\n \tconst char *value;\n \n \tif (git_config_get_value(\"rebase.missingcommitscheck\", &value) ||\n \t\t\t!strcasecmp(\"ignore\", value))\n-\t\treturn CHECK_IGNORE;\n+\t\treturn MISSING_COMMIT_CHECK_IGNORE;\n \tif (!strcasecmp(\"warn\", value))\n-\t\treturn CHECK_WARN;\n+\t\treturn MISSING_COMMIT_CHECK_WARN;\n \tif (!strcasecmp(\"error\", value))\n-\t\treturn CHECK_ERROR;\n+\t\treturn MISSING_COMMIT_CHECK_ERROR;\n \twarning(_(\"unrecognized setting %s for option \"\n \t\t  \"rebase.missingCommitsCheck. Ignoring.\"), value);\n-\treturn CHECK_IGNORE;\n+\treturn MISSING_COMMIT_CHECK_IGNORE;\n }\n \n define_commit_slab(commit_seen, unsigned char);\n@@ -4250,7 +4246,7 @@ define_commit_slab(commit_seen, unsigned char);\n  */\n int check_todo_list(void)\n {\n-\tenum check_level check_level = get_missing_commit_check_level();\n+\tenum missing_commit_check_level check_level = get_missing_commit_check_level();\n \tstruct strbuf todo_file = STRBUF_INIT;\n \tstruct todo_list todo_list = TODO_LIST_INIT;\n \tstruct strbuf missing = STRBUF_INIT;\n@@ -4267,7 +4263,7 @@ int check_todo_list(void)\n \tadvise_to_edit_todo = res =\n \t\tparse_insn_buffer(todo_list.buf.buf, &todo_list);\n \n-\tif (res || check_level == CHECK_IGNORE)\n+\tif (res || check_level == MISSING_COMMIT_CHECK_IGNORE)\n \t\tgoto leave_check;\n \n \t/* Mark the commits in git-rebase-todo as seen */\n@@ -4302,7 +4298,7 @@ int check_todo_list(void)\n \tif (!missing.len)\n \t\tgoto leave_check;\n \n-\tif (check_level == CHECK_ERROR)\n+\tif (check_level == MISSING_COMMIT_CHECK_ERROR)\n \t\tadvise_to_edit_todo = res = 1;\n \n \tfprintf(stderr,\ndiff --git a/sequencer.h b/sequencer.h\nindex c5787c6b5..ffab798f1 100644\n--- a/sequencer.h\n+++ b/sequencer.h\n@@ -3,6 +3,7 @@\n \n const char *git_path_commit_editmsg(void);\n const char *git_path_seq_dir(void);\n+const char *rebase_path_todo(void);\n \n #define APPEND_SIGNOFF_DEDUP (1u << 0)\n \n@@ -57,6 +58,12 @@ struct replay_opts {\n };\n #define REPLAY_OPTS_INIT { .action = -1, .current_fixups = STRBUF_INIT }\n \n+enum missing_commit_check_level {\n+\tMISSING_COMMIT_CHECK_IGNORE = 0,\n+\tMISSING_COMMIT_CHECK_WARN,\n+\tMISSING_COMMIT_CHECK_ERROR\n+};\n+\n /* Call this to setup defaults before parsing command line options */\n void sequencer_init_config(struct replay_opts *opts);\n int sequencer_pick_revisions(struct replay_opts *opts);\n@@ -79,6 +86,7 @@ int sequencer_make_script(FILE *out, int argc, const char **argv,\n \n int sequencer_add_exec_commands(const char *command);\n int transform_todos(unsigned flags);\n+enum missing_commit_check_level get_missing_commit_check_level(void);\n int check_todo_list(void);\n int skip_unnecessary_picks(void);\n int rearrange_squash(void);\n-- \n2.18.0\n\n"},{"id":"352090","messageId":"20180710121557.6698-3-alban.gruin@gmail.com","threadId":"48814","inReplyTo":"20180710121557.6698-1-alban.gruin@gmail.com","subject":"[GSoC][PATCH v3 02/13] rebase--interactive: rewrite append_todo_help() in C","fromName":"Alban Gruin","fromEmail":"alban.gruin@gmail.com","sentAt":"2018-07-10T12:15:46Z","receivedAt":"2018-07-10T12:17:20Z","isPatch":true,"sender":{"key":"alban.gruin@gmail.com","avatar":"https://avatars.githubusercontent.com/u/6310153?v=4"},"body":"This rewrites append_todo_help() from shell to C. It also incorporates\nsome parts of initiate_action() and complete_action() that also write\nhelp texts to the todo file.\n\nThis also introduces the source file rebase-interactive.c. This file\nwill contain functions necessary for interactive rebase that are too\nspecific for the sequencer, and is part of libgit.a.\n\nTwo flags are added to rebase--helper.c: one to call\nappend_todo_help() (`--append-todo-help`), and another one to tell\nappend_todo_help() to write the help text suited for the edit-todo\nmode (`--write-edit-todo`).\n\nFinally, append_todo_help() is removed from git-rebase--interactive.sh\nto use `rebase--helper --append-todo-help` instead.\n\nSigned-off-by: Alban Gruin <alban.gruin@gmail.com>\n---\nUnchanged from what have been queued on `pu` (ag/rebase-i-in-c), and\nfrom v2.\n\n Makefile                   |  1 +\n builtin/rebase--helper.c   | 11 ++++--\n git-rebase--interactive.sh | 52 ++---------------------------\n rebase-interactive.c       | 68 ++++++++++++++++++++++++++++++++++++++\n rebase-interactive.h       |  6 ++++\n 5 files changed, 86 insertions(+), 52 deletions(-)\n create mode 100644 rebase-interactive.c\n create mode 100644 rebase-interactive.h\n\ndiff --git a/Makefile b/Makefile\nindex 0cb6590f2..a281139ef 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -922,6 +922,7 @@ LIB_OBJS += protocol.o\n LIB_OBJS += quote.o\n LIB_OBJS += reachable.o\n LIB_OBJS += read-cache.o\n+LIB_OBJS += rebase-interactive.o\n LIB_OBJS += reflog-walk.o\n LIB_OBJS += refs.o\n LIB_OBJS += refs/files-backend.o\ndiff --git a/builtin/rebase--helper.c b/builtin/rebase--helper.c\nindex f7c2a5fdc..05e73e71d 100644\n--- a/builtin/rebase--helper.c\n+++ b/builtin/rebase--helper.c\n@@ -3,6 +3,7 @@\n #include \"config.h\"\n #include \"parse-options.h\"\n #include \"sequencer.h\"\n+#include \"rebase-interactive.h\"\n \n static const char * const builtin_rebase_helper_usage[] = {\n \tN_(\"git rebase--helper [<options>]\"),\n@@ -12,12 +13,12 @@ static const char * const builtin_rebase_helper_usage[] = {\n int cmd_rebase__helper(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;\n+\tunsigned flags = 0, keep_empty = 0, rebase_merges = 0, write_edit_todo = 0;\n \tint abbreviate_commands = 0, rebase_cousins = -1;\n \tenum {\n \t\tCONTINUE = 1, ABORT, MAKE_SCRIPT, SHORTEN_OIDS, EXPAND_OIDS,\n \t\tCHECK_TODO_LIST, SKIP_UNNECESSARY_PICKS, REARRANGE_SQUASH,\n-\t\tADD_EXEC\n+\t\tADD_EXEC, APPEND_TODO_HELP\n \t} command = 0;\n \tstruct option options[] = {\n \t\tOPT_BOOL(0, \"ff\", &opts.allow_ff, N_(\"allow fast-forward\")),\n@@ -27,6 +28,8 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\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, \"write-edit-todo\", &write_edit_todo,\n+\t\t\t N_(\"append the edit-todo message to the todo-list\")),\n \t\tOPT_CMDMODE(0, \"continue\", &command, N_(\"continue rebase\"),\n \t\t\t\tCONTINUE),\n \t\tOPT_CMDMODE(0, \"abort\", &command, N_(\"abort rebase\"),\n@@ -45,6 +48,8 @@ int cmd_rebase__helper(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_CMDMODE(0, \"append-todo-help\", &command,\n+\t\t\t    N_(\"insert the help in the todo list\"), APPEND_TODO_HELP),\n \t\tOPT_END()\n \t};\n \n@@ -84,5 +89,7 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\n \t\treturn !!rearrange_squash();\n \tif (command == ADD_EXEC && argc == 2)\n \t\treturn !!sequencer_add_exec_commands(argv[1]);\n+\tif (command == APPEND_TODO_HELP && argc == 1)\n+\t\treturn !!append_todo_help(write_edit_todo, keep_empty);\n \tusage_with_options(builtin_rebase_helper_usage, options);\n }\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex 299ded213..94c23a7af 100644\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -39,38 +39,6 @@ comment_for_reflog () {\n \tesac\n }\n \n-append_todo_help () {\n-\tgettext \"\n-Commands:\n-p, pick <commit> = use commit\n-r, reword <commit> = use commit, but edit the commit message\n-e, edit <commit> = use commit, but stop for amending\n-s, squash <commit> = use commit, but meld into previous commit\n-f, fixup <commit> = like \\\"squash\\\", but discard this commit's log message\n-x, exec <command> = run command (the rest of the line) using shell\n-d, drop <commit> = remove commit\n-l, label <label> = label current HEAD with a name\n-t, reset <label> = reset HEAD to a label\n-m, merge [-C <commit> | -c <commit>] <label> [# <oneline>]\n-.       create a merge commit using the original merge commit's\n-.       message (or the oneline, if no original merge commit was\n-.       specified). Use -c <commit> to reword the commit message.\n-\n-These lines can be re-ordered; they are executed from top to bottom.\n-\" | git stripspace --comment-lines >>\"$todo\"\n-\n-\tif test $(get_missing_commit_check_level) = error\n-\tthen\n-\t\tgettext \"\n-Do not remove any line. Use 'drop' explicitly to remove a commit.\n-\" | git stripspace --comment-lines >>\"$todo\"\n-\telse\n-\t\tgettext \"\n-If you remove a line here THAT COMMIT WILL BE LOST.\n-\" | git stripspace --comment-lines >>\"$todo\"\n-\tfi\n-}\n-\n die_abort () {\n \tapply_autostash\n \trm -rf \"$state_dir\"\n@@ -143,13 +111,7 @@ initiate_action () {\n \t\tgit stripspace --strip-comments <\"$todo\" >\"$todo\".new\n \t\tmv -f \"$todo\".new \"$todo\"\n \t\tcollapse_todo_ids\n-\t\tappend_todo_help\n-\t\tgettext \"\n-You are editing the todo file of an ongoing interactive rebase.\n-To continue rebase after editing, run:\n-    git rebase --continue\n-\n-\" | git stripspace --comment-lines >>\"$todo\"\n+\t\tgit rebase--helper --append-todo-help --write-edit-todo\n \n \t\tgit_sequence_editor \"$todo\" ||\n \t\t\tdie \"$(gettext \"Could not execute editor\")\"\n@@ -220,17 +182,7 @@ $comment_char $(eval_ngettext \\\n \t\"Rebase \\$shortrevisions onto \\$shortonto (\\$todocount commands)\" \\\n \t\"$todocount\")\n EOF\n-\tappend_todo_help\n-\tgettext \"\n-\tHowever, if you remove everything, the rebase will be aborted.\n-\n-\t\" | git stripspace --comment-lines >>\"$todo\"\n-\n-\tif test -z \"$keep_empty\"\n-\tthen\n-\t\tprintf '%s\\n' \"$comment_char $(gettext \"Note that empty commits are commented out\")\" >>\"$todo\"\n-\tfi\n-\n+\tgit rebase--helper --append-todo-help ${keep_empty:+--keep-empty}\n \n \thas_action \"$todo\" ||\n \t\treturn 2\ndiff --git a/rebase-interactive.c b/rebase-interactive.c\nnew file mode 100644\nindex 000000000..d7996bc8d\n--- /dev/null\n+++ b/rebase-interactive.c\n@@ -0,0 +1,68 @@\n+#include \"cache.h\"\n+#include \"commit.h\"\n+#include \"rebase-interactive.h\"\n+#include \"sequencer.h\"\n+#include \"strbuf.h\"\n+\n+int append_todo_help(unsigned edit_todo, unsigned keep_empty)\n+{\n+\tstruct strbuf buf = STRBUF_INIT;\n+\tFILE *todo;\n+\tint ret;\n+\tconst char *msg = _(\"\\nCommands:\\n\"\n+\"p, pick <commit> = use commit\\n\"\n+\"r, reword <commit> = use commit, but edit the commit message\\n\"\n+\"e, edit <commit> = use commit, but stop for amending\\n\"\n+\"s, squash <commit> = use commit, but meld into previous commit\\n\"\n+\"f, fixup <commit> = like \\\"squash\\\", but discard this commit's log message\\n\"\n+\"x, exec <command> = run command (the rest of the line) using shell\\n\"\n+\"d, drop <commit> = remove commit\\n\"\n+\"l, label <label> = label current HEAD with a name\\n\"\n+\"t, reset <label> = reset HEAD to a label\\n\"\n+\"m, merge [-C <commit> | -c <commit>] <label> [# <oneline>]\\n\"\n+\".       create a merge commit using the original merge commit's\\n\"\n+\".       message (or the oneline, if no original merge commit was\\n\"\n+\".       specified). Use -c <commit> to reword the commit message.\\n\"\n+\"\\n\"\n+\"These lines can be re-ordered; they are executed from top to bottom.\\n\");\n+\n+\ttodo = fopen_or_warn(rebase_path_todo(), \"a\");\n+\tif (!todo)\n+\t\treturn 1;\n+\n+\tstrbuf_add_commented_lines(&buf, msg, strlen(msg));\n+\n+\tif (get_missing_commit_check_level() == MISSING_COMMIT_CHECK_ERROR)\n+\t\tmsg = _(\"\\nDo not remove any line. Use 'drop' \"\n+\t\t\t \"explicitly to remove a commit.\\n\");\n+\telse\n+\t\tmsg = _(\"\\nIf you remove a line here \"\n+\t\t\t \"THAT COMMIT WILL BE LOST.\\n\");\n+\n+\tstrbuf_add_commented_lines(&buf, msg, strlen(msg));\n+\n+\tif (edit_todo)\n+\t\tmsg = _(\"\\nYou are editing the todo file \"\n+\t\t\t\"of an ongoing interactive rebase.\\n\"\n+\t\t\t\"To continue rebase after editing, run:\\n\"\n+\t\t\t\"    git rebase --continue\\n\\n\");\n+\telse\n+\t\tmsg = _(\"\\nHowever, if you remove everything, \"\n+\t\t\t\"the rebase will be aborted.\\n\\n\");\n+\n+\tstrbuf_add_commented_lines(&buf, msg, strlen(msg));\n+\n+\tif (!keep_empty) {\n+\t\tmsg = _(\"Note that empty commits are commented out\");\n+\t\tstrbuf_add_commented_lines(&buf, msg, strlen(msg));\n+\t}\n+\n+\tret = fputs(buf.buf, todo);\n+\tif (ret < 0)\n+\t\terror_errno(_(\"could not append help text to '%s'\"), rebase_path_todo());\n+\n+\tfclose(todo);\n+\tstrbuf_release(&buf);\n+\n+\treturn ret;\n+}\ndiff --git a/rebase-interactive.h b/rebase-interactive.h\nnew file mode 100644\nindex 000000000..47372624e\n--- /dev/null\n+++ b/rebase-interactive.h\n@@ -0,0 +1,6 @@\n+#ifndef REBASE_INTERACTIVE_H\n+#define REBASE_INTERACTIVE_H\n+\n+int append_todo_help(unsigned edit_todo, unsigned keep_empty);\n+\n+#endif\n-- \n2.18.0\n\n"},{"id":"352091","messageId":"20180710121557.6698-8-alban.gruin@gmail.com","threadId":"48814","inReplyTo":"20180710121557.6698-1-alban.gruin@gmail.com","subject":"[GSoC][PATCH v3 07/13] rebase -i: rewrite checkout_onto() in C","fromName":"Alban Gruin","fromEmail":"alban.gruin@gmail.com","sentAt":"2018-07-10T12:15:51Z","receivedAt":"2018-07-10T12:17:27Z","isPatch":true,"sender":{"key":"alban.gruin@gmail.com","avatar":"https://avatars.githubusercontent.com/u/6310153?v=4"},"body":"This rewrites checkout_onto() from shell to C.\n\nA new command (“checkout-onto”) is added to rebase--helper.c. The shell\nversion is then stripped.\n\nSigned-off-by: Alban Gruin <alban.gruin@gmail.com>\n---\n builtin/rebase--helper.c   |  7 ++++++-\n git-rebase--interactive.sh | 25 ++++---------------------\n sequencer.c                | 19 +++++++++++++++++++\n sequencer.h                |  3 +++\n 4 files changed, 32 insertions(+), 22 deletions(-)\n\ndiff --git a/builtin/rebase--helper.c b/builtin/rebase--helper.c\nindex 76bdc6fdb..1d9595bdb 100644\n--- a/builtin/rebase--helper.c\n+++ b/builtin/rebase--helper.c\n@@ -18,7 +18,8 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\n \tenum {\n \t\tCONTINUE = 1, ABORT, MAKE_SCRIPT, SHORTEN_OIDS, EXPAND_OIDS,\n \t\tCHECK_TODO_LIST, SKIP_UNNECESSARY_PICKS, REARRANGE_SQUASH,\n-\t\tADD_EXEC, APPEND_TODO_HELP, EDIT_TODO, PREPARE_BRANCH\n+\t\tADD_EXEC, APPEND_TODO_HELP, EDIT_TODO, PREPARE_BRANCH,\n+\t\tCHECKOUT_ONTO\n \t} command = 0;\n \tstruct option options[] = {\n \t\tOPT_BOOL(0, \"ff\", &opts.allow_ff, N_(\"allow fast-forward\")),\n@@ -54,6 +55,8 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\n \t\t\t    EDIT_TODO),\n \t\tOPT_CMDMODE(0, \"prepare-branch\", &command,\n \t\t\t    N_(\"prepare the branch to be rebased\"), PREPARE_BRANCH),\n+\t\tOPT_CMDMODE(0, \"checkout-onto\", &command,\n+\t\t\t    N_(\"checkout a commit\"), CHECKOUT_ONTO),\n \t\tOPT_END()\n \t};\n \n@@ -100,5 +103,7 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\n \t\treturn !!edit_todo_list(flags);\n \tif (command == PREPARE_BRANCH && argc == 2)\n \t\treturn !!prepare_branch_to_be_rebased(&opts, argv[1]);\n+\tif (command == CHECKOUT_ONTO && argc == 4)\n+\t\treturn !!checkout_onto(&opts, argv[1], argv[2], argv[3]);\n \tusage_with_options(builtin_rebase_helper_usage, options);\n }\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex 77e972bb6..b68f108f2 100644\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -28,17 +28,6 @@ case \"$comment_char\" in\n \t;;\n esac\n \n-orig_reflog_action=\"$GIT_REFLOG_ACTION\"\n-\n-comment_for_reflog () {\n-\tcase \"$orig_reflog_action\" in\n-\t''|rebase*)\n-\t\tGIT_REFLOG_ACTION=\"rebase -i ($1)\"\n-\t\texport GIT_REFLOG_ACTION\n-\t\t;;\n-\tesac\n-}\n-\n die_abort () {\n \tapply_autostash\n \trm -rf \"$state_dir\"\n@@ -70,14 +59,6 @@ collapse_todo_ids() {\n \tgit rebase--helper --shorten-ids\n }\n \n-# Switch to the branch in $into and notify it in the reflog\n-checkout_onto () {\n-\tcomment_for_reflog start\n-\tGIT_REFLOG_ACTION=\"$GIT_REFLOG_ACTION: checkout $onto_name\"\n-\toutput git checkout $onto || die_abort \"$(gettext \"could not detach HEAD\")\"\n-\tgit update-ref ORIG_HEAD $orig_head\n-}\n-\n get_missing_commit_check_level () {\n \tcheck_level=$(git config --get rebase.missingCommitsCheck)\n \tcheck_level=${check_level:-ignore}\n@@ -176,7 +157,8 @@ EOF\n \n \tgit rebase--helper --check-todo-list || {\n \t\tret=$?\n-\t\tcheckout_onto\n+\t\tgit rebase--helper --checkout-onto \"$onto_name\" \"$onto\" \\\n+\t\t    \"$orig_head\" ${verbose:+--verbose}\n \t\texit $ret\n \t}\n \n@@ -186,7 +168,8 @@ EOF\n \tonto=\"$(git rebase--helper --skip-unnecessary-picks)\" ||\n \tdie \"Could not skip unnecessary pick commands\"\n \n-\tcheckout_onto\n+\tgit rebase--helper --checkout-onto \"$onto_name\" \"$onto\" \"$orig_head\" \\\n+\t    ${verbose:+--verbose}\n \trequire_clean_work_tree \"rebase\"\n \texec git rebase--helper ${force_rebase:+--no-ff} $allow_empty_message \\\n \t     --continue\ndiff --git a/sequencer.c b/sequencer.c\nindex b5ea35f21..2b6ddc6cf 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -3162,6 +3162,25 @@ int prepare_branch_to_be_rebased(struct replay_opts *opts, const char *commit)\n \treturn 0;\n }\n \n+int checkout_onto(struct replay_opts *opts,\n+\t\t  const char *onto_name, const char *onto,\n+\t\t  const char *orig_head)\n+{\n+\tstruct object_id oid;\n+\tconst char *action = reflog_message(opts, \"start\", \"checkout %s\", onto_name);\n+\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+\t\tapply_autostash(opts);\n+\t\tsequencer_remove_state(opts);\n+\t\treturn error(_(\"could not detach HEAD\"));\n+\t}\n+\n+\treturn update_ref(NULL, \"ORIG_HEAD\", &oid, NULL, 0, UPDATE_REFS_MSG_ON_ERR);\n+}\n+\n static const char rescheduled_advice[] =\n N_(\"Could not execute the todo command\\n\"\n \"\\n\"\ndiff --git a/sequencer.h b/sequencer.h\nindex 93da713fe..11a533461 100644\n--- a/sequencer.h\n+++ b/sequencer.h\n@@ -107,6 +107,9 @@ void commit_post_rewrite(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 checkout_onto(struct replay_opts *opts,\n+\t\t  const char *onto_name, const char *onto,\n+\t\t  const char *orig_head);\n \n #define SUMMARY_INITIAL_COMMIT   (1 << 0)\n #define SUMMARY_SHOW_AUTHOR_DATE (1 << 1)\n-- \n2.18.0\n\n"},{"id":"352092","messageId":"20180710121557.6698-9-alban.gruin@gmail.com","threadId":"48814","inReplyTo":"20180710121557.6698-1-alban.gruin@gmail.com","subject":"[GSoC][PATCH v3 08/13] sequencer: refactor append_todo_help() to write its message to a buffer","fromName":"Alban Gruin","fromEmail":"alban.gruin@gmail.com","sentAt":"2018-07-10T12:15:52Z","receivedAt":"2018-07-10T12:17:29Z","isPatch":true,"sender":{"key":"alban.gruin@gmail.com","avatar":"https://avatars.githubusercontent.com/u/6310153?v=4"},"body":"This refactors append_todo_help() to write its message to a buffer\ninstead of the todo-list.  This is needed for the rewrite of\ncomplete_action(), which will come after the next commit.\n\nAs rebase--helper still needs the file manipulation part of\nappend_todo_help(), it is extracted to a temporary function,\nappend_todo_help_to_file().  This function will go away after the\nrewrite of complete_action().\n\nSigned-off-by: Alban Gruin <alban.gruin@gmail.com>\n---\n builtin/rebase--helper.c |  2 +-\n rebase-interactive.c     | 45 ++++++++++++++++++++++++++++------------\n rebase-interactive.h     |  7 ++++++-\n 3 files changed, 39 insertions(+), 15 deletions(-)\n\ndiff --git a/builtin/rebase--helper.c b/builtin/rebase--helper.c\nindex 1d9595bdb..b9af96af7 100644\n--- a/builtin/rebase--helper.c\n+++ b/builtin/rebase--helper.c\n@@ -98,7 +98,7 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\n \tif (command == ADD_EXEC && argc == 2)\n \t\treturn !!sequencer_add_exec_commands(argv[1]);\n \tif (command == APPEND_TODO_HELP && argc == 1)\n-\t\treturn !!append_todo_help(0, keep_empty);\n+\t\treturn !!append_todo_help_to_file(0, keep_empty);\n \tif (command == EDIT_TODO && argc == 1)\n \t\treturn !!edit_todo_list(flags);\n \tif (command == PREPARE_BRANCH && argc == 2)\ndiff --git a/rebase-interactive.c b/rebase-interactive.c\nindex 403ecbf3c..d8b946559 100644\n--- a/rebase-interactive.c\n+++ b/rebase-interactive.c\n@@ -4,11 +4,9 @@\n #include \"sequencer.h\"\n #include \"strbuf.h\"\n \n-int append_todo_help(unsigned edit_todo, unsigned keep_empty)\n+void append_todo_help(unsigned edit_todo, unsigned keep_empty,\n+\t\t      struct strbuf *buf)\n {\n-\tstruct strbuf buf = STRBUF_INIT;\n-\tFILE *todo;\n-\tint ret;\n \tconst char *msg = _(\"\\nCommands:\\n\"\n \"p, pick <commit> = use commit\\n\"\n \"r, reword <commit> = use commit, but edit the commit message\\n\"\n@@ -26,11 +24,7 @@ int append_todo_help(unsigned edit_todo, unsigned keep_empty)\n \"\\n\"\n \"These lines can be re-ordered; they are executed from top to bottom.\\n\");\n \n-\ttodo = fopen_or_warn(rebase_path_todo(), \"a\");\n-\tif (!todo)\n-\t\treturn 1;\n-\n-\tstrbuf_add_commented_lines(&buf, msg, strlen(msg));\n+\tstrbuf_add_commented_lines(buf, msg, strlen(msg));\n \n \tif (get_missing_commit_check_level() == MISSING_COMMIT_CHECK_ERROR)\n \t\tmsg = _(\"\\nDo not remove any line. Use 'drop' \"\n@@ -39,7 +33,7 @@ int append_todo_help(unsigned edit_todo, unsigned keep_empty)\n \t\tmsg = _(\"\\nIf you remove a line here \"\n \t\t\t \"THAT COMMIT WILL BE LOST.\\n\");\n \n-\tstrbuf_add_commented_lines(&buf, msg, strlen(msg));\n+\tstrbuf_add_commented_lines(buf, msg, strlen(msg));\n \n \tif (edit_todo)\n \t\tmsg = _(\"\\nYou are editing the todo file \"\n@@ -50,12 +44,25 @@ int append_todo_help(unsigned edit_todo, unsigned keep_empty)\n \t\tmsg = _(\"\\nHowever, if you remove everything, \"\n \t\t\t\"the rebase will be aborted.\\n\\n\");\n \n-\tstrbuf_add_commented_lines(&buf, msg, strlen(msg));\n+\tstrbuf_add_commented_lines(buf, msg, strlen(msg));\n \n \tif (!keep_empty) {\n \t\tmsg = _(\"Note that empty commits are commented out\");\n-\t\tstrbuf_add_commented_lines(&buf, msg, strlen(msg));\n+\t\tstrbuf_add_commented_lines(buf, msg, strlen(msg));\n \t}\n+}\n+\n+int append_todo_help_to_file(unsigned edit_todo, unsigned keep_empty)\n+{\n+\tstruct strbuf buf = STRBUF_INIT;\n+\tFILE *todo;\n+\tint ret;\n+\n+\ttodo = fopen_or_warn(rebase_path_todo(), \"a\");\n+\tif (!todo)\n+\t\treturn 1;\n+\n+\tappend_todo_help(edit_todo, keep_empty, &buf);\n \n \tret = fputs(buf.buf, todo);\n \tif (ret < 0)\n@@ -88,7 +95,19 @@ int edit_todo_list(unsigned flags)\n \tstrbuf_release(&buf);\n \n \ttransform_todos(flags | TODO_LIST_SHORTEN_IDS);\n-\tappend_todo_help(1, 0);\n+\n+\tstrbuf_read_file(&buf, todo_file, 0);\n+\tappend_todo_help(1, 0, &buf);\n+\n+\ttodo = fopen_or_warn(todo_file, \"w\");\n+\tif (!todo) {\n+\t\tstrbuf_release(&buf);\n+\t\treturn 1;\n+\t}\n+\n+\tstrbuf_write(&buf, todo);\n+\tfclose(todo);\n+\tstrbuf_release(&buf);\n \n \tif (launch_sequence_editor(todo_file, NULL, NULL))\n \t\treturn 1;\ndiff --git a/rebase-interactive.h b/rebase-interactive.h\nindex 155219e74..c0ba83be3 100644\n--- a/rebase-interactive.h\n+++ b/rebase-interactive.h\n@@ -1,7 +1,12 @@\n #ifndef REBASE_INTERACTIVE_H\n #define REBASE_INTERACTIVE_H\n \n-int append_todo_help(unsigned edit_todo, unsigned keep_empty);\n+#include <cache.h>\n+#include <strbuf.h>\n+\n+void append_todo_help(unsigned edit_todo, unsigned keep_empty,\n+\t\t      struct strbuf *buf);\n+int append_todo_help_to_file(unsigned edit_todo, unsigned keep_empty);\n int edit_todo_list(unsigned flags);\n \n #endif\n-- \n2.18.0\n\n"},{"id":"352093","messageId":"20180710121557.6698-11-alban.gruin@gmail.com","threadId":"48814","inReplyTo":"20180710121557.6698-1-alban.gruin@gmail.com","subject":"[GSoC][PATCH v3 10/13] rebase--interactive: rewrite complete_action() in C","fromName":"Alban Gruin","fromEmail":"alban.gruin@gmail.com","sentAt":"2018-07-10T12:15:54Z","receivedAt":"2018-07-10T12:17:34Z","isPatch":true,"sender":{"key":"alban.gruin@gmail.com","avatar":"https://avatars.githubusercontent.com/u/6310153?v=4"},"body":"This rewrites complete_action() from shell to C.\n\nA new mode is added to rebase--helper (`--complete-action`), as well as\na new flag (`--autosquash`).\n\nFinally, complete_action() is stripped from git-rebase--interactive.sh.\n\nThe original complete_action() checked twice that the todo-list had at\nleast one operations (the first check took place after the help message\nwas inserted, the second after the user edited the todo-list).  If there\nare no actions, complete_action() would return with the code 2.  This is\na special case for rebase -i and -p; git-rebase.sh would then apply the\nautostash, delete the state directory, and die with the message \"nothing\nto do\".  This rewrite remove the first check (because a noop is added to\nthe todo-list if it is empty).  For the second case, the cleanup is\nrewritten in C instead of returning 2.\n\nAs rebase -i no longer returns 2, the comment describing this behaviour\nin git-rebase.sh is updated to reflect this change.\n\nSigned-off-by: Alban Gruin <alban.gruin@gmail.com>\n---\n builtin/rebase--helper.c   | 13 +++++-\n git-rebase--interactive.sh | 53 ++---------------------\n git-rebase.sh              |  2 +-\n sequencer.c                | 89 ++++++++++++++++++++++++++++++++++++++\n sequencer.h                |  4 ++\n 5 files changed, 109 insertions(+), 52 deletions(-)\n\ndiff --git a/builtin/rebase--helper.c b/builtin/rebase--helper.c\nindex d4cfe43e7..bb3698dba 100644\n--- a/builtin/rebase--helper.c\n+++ b/builtin/rebase--helper.c\n@@ -13,14 +13,15 @@ static const char * const builtin_rebase_helper_usage[] = {\n int cmd_rebase__helper(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, verbose = 0;\n+\tunsigned flags = 0, keep_empty = 0, rebase_merges = 0, verbose = 0,\n+\t\tautosquash = 0;\n \tint abbreviate_commands = 0, rebase_cousins = -1, ret;\n \tconst char *oid = NULL;\n \tenum {\n \t\tCONTINUE = 1, ABORT, MAKE_SCRIPT, SHORTEN_OIDS, EXPAND_OIDS,\n \t\tCHECK_TODO_LIST, SKIP_UNNECESSARY_PICKS, REARRANGE_SQUASH,\n \t\tADD_EXEC, APPEND_TODO_HELP, EDIT_TODO, PREPARE_BRANCH,\n-\t\tCHECKOUT_ONTO\n+\t\tCHECKOUT_ONTO, COMPLETE_ACTION\n \t} command = 0;\n \tstruct option options[] = {\n \t\tOPT_BOOL(0, \"ff\", &opts.allow_ff, N_(\"allow fast-forward\")),\n@@ -30,6 +31,8 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\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 thas begin with squash!/fixup!\")),\n \t\tOPT__VERBOSE(&verbose, N_(\"be verbose\")),\n \t\tOPT_CMDMODE(0, \"continue\", &command, N_(\"continue rebase\"),\n \t\t\t\tCONTINUE),\n@@ -58,6 +61,8 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\n \t\t\t    N_(\"prepare the branch to be rebased\"), PREPARE_BRANCH),\n \t\tOPT_CMDMODE(0, \"checkout-onto\", &command,\n \t\t\t    N_(\"checkout a commit\"), CHECKOUT_ONTO),\n+\t\tOPT_CMDMODE(0, \"complete-action\", &command,\n+\t\t\t    N_(\"complete the action\"), COMPLETE_ACTION),\n \t\tOPT_END()\n \t};\n \n@@ -110,5 +115,9 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\n \t\treturn !!prepare_branch_to_be_rebased(&opts, argv[1]);\n \tif (command == CHECKOUT_ONTO && argc == 4)\n \t\treturn !!checkout_onto(&opts, argv[1], argv[2], argv[3]);\n+\tif (command == COMPLETE_ACTION && argc == 6)\n+\t\treturn !!complete_action(&opts, flags, argv[1], argv[2], argv[3],\n+\t\t\t\t\t argv[4], argv[5], autosquash, keep_empty);\n+\n \tusage_with_options(builtin_rebase_helper_usage, options);\n }\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex b68f108f2..59dc4888a 100644\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -127,54 +127,6 @@ init_revisions_and_shortrevisions () {\n \tfi\n }\n \n-complete_action() {\n-\ttest -s \"$todo\" || echo noop >> \"$todo\"\n-\ttest -z \"$autosquash\" || git rebase--helper --rearrange-squash || exit\n-\ttest -n \"$cmd\" && git rebase--helper --add-exec-commands \"$cmd\"\n-\n-\ttodocount=$(git stripspace --strip-comments <\"$todo\" | wc -l)\n-\ttodocount=${todocount##* }\n-\n-cat >>\"$todo\" <<EOF\n-\n-$comment_char $(eval_ngettext \\\n-\t\"Rebase \\$shortrevisions onto \\$shortonto (\\$todocount command)\" \\\n-\t\"Rebase \\$shortrevisions onto \\$shortonto (\\$todocount commands)\" \\\n-\t\"$todocount\")\n-EOF\n-\tgit rebase--helper --append-todo-help ${keep_empty:+--keep-empty}\n-\n-\thas_action \"$todo\" ||\n-\t\treturn 2\n-\n-\tcp \"$todo\" \"$todo\".backup\n-\tcollapse_todo_ids\n-\tgit_sequence_editor \"$todo\" ||\n-\t\tdie_abort \"$(gettext \"Could not execute editor\")\"\n-\n-\thas_action \"$todo\" ||\n-\t\treturn 2\n-\n-\tgit rebase--helper --check-todo-list || {\n-\t\tret=$?\n-\t\tgit rebase--helper --checkout-onto \"$onto_name\" \"$onto\" \\\n-\t\t    \"$orig_head\" ${verbose:+--verbose}\n-\t\texit $ret\n-\t}\n-\n-\texpand_todo_ids\n-\n-\ttest -n \"$force_rebase\" ||\n-\tonto=\"$(git rebase--helper --skip-unnecessary-picks)\" ||\n-\tdie \"Could not skip unnecessary pick commands\"\n-\n-\tgit rebase--helper --checkout-onto \"$onto_name\" \"$onto\" \"$orig_head\" \\\n-\t    ${verbose:+--verbose}\n-\trequire_clean_work_tree \"rebase\"\n-\texec git rebase--helper ${force_rebase:+--no-ff} $allow_empty_message \\\n-\t     --continue\n-}\n-\n git_rebase__interactive () {\n \tinitiate_action \"$action\"\n \tret=$?\n@@ -193,5 +145,8 @@ git_rebase__interactive () {\n \t\t$revisions ${restrict_revision+^$restrict_revision} >\"$todo\" ||\n \tdie \"$(gettext \"Could not generate todo list\")\"\n \n-\tcomplete_action\n+\texec git rebase--helper --complete-action \"$shortrevisions\" \"$onto_name\" \\\n+\t\t\"$shortonto\" \"$orig_head\" \"$cmd\" $allow_empty_message \\\n+\t\t${autosquash:+--autosquash} ${keep_empty:+--keep-empty} \\\n+\t\t${verbose:+--verbose} ${force_rebase:+--no-ff}\n }\ndiff --git a/git-rebase.sh b/git-rebase.sh\nindex 19bdebb48..de2a9f39f 100755\n--- a/git-rebase.sh\n+++ b/git-rebase.sh\n@@ -219,7 +219,7 @@ run_specific_rebase () {\n \tif test $ret -eq 0\n \tthen\n \t\tfinish_rebase\n-\telif test $ret -eq 2 # special exit status for rebase -i\n+\telif test $ret -eq 2 # special exit status for rebase -p\n \tthen\n \t\tapply_autostash &&\n \t\trm -rf \"$state_dir\" &&\ndiff --git a/sequencer.c b/sequencer.c\nindex 676ac1320..da975285d 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -29,6 +29,7 @@\n #include \"oidset.h\"\n #include \"commit-slab.h\"\n #include \"alias.h\"\n+#include \"rebase-interactive.h\"\n \n #define GIT_REFLOG_ACTION \"GIT_REFLOG_ACTION\"\n \n@@ -52,6 +53,9 @@ static GIT_PATH_FUNC(rebase_path, \"rebase-merge\")\n  * file and written to the tail of 'done'.\n  */\n GIT_PATH_FUNC(rebase_path_todo, \"rebase-merge/git-rebase-todo\")\n+static GIT_PATH_FUNC(rebase_path_todo_backup,\n+\t\t     \"rebase-merge/git-rebase-todo.backup\")\n+\n /*\n  * The rebase command lines that have already been processed. A line\n  * is moved here when it is first handled, before any associated user\n@@ -4472,6 +4476,91 @@ int skip_unnecessary_picks(const char **output_oid)\n \treturn 0;\n }\n \n+int complete_action(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, const char *cmd,\n+\t\t    unsigned autosquash, unsigned keep_empty)\n+{\n+\tconst char *shortonto, *todo_file = rebase_path_todo();\n+\tstruct todo_list todo_list = TODO_LIST_INIT;\n+\tstruct strbuf *buf = &(todo_list.buf);\n+\tstruct object_id oid;\n+\tstruct stat st;\n+\n+\tget_oid(onto, &oid);\n+\tshortonto = find_unique_abbrev(&oid, DEFAULT_ABBREV);\n+\n+\tif (!lstat(todo_file, &st) && st.st_size == 0 &&\n+\t    write_message(\"noop\\n\", 5, todo_file, 0))\n+\t\treturn error_errno(_(\"could not write '%s'\"), todo_file);\n+\n+\tif (autosquash && rearrange_squash())\n+\t\treturn 0;\n+\n+\tif (cmd && *cmd)\n+\t\tsequencer_add_exec_commands(cmd);\n+\n+\tif (strbuf_read_file(buf, todo_file, 0) < 0)\n+\t\treturn error_errno(_(\"could not read '%s'.\"), todo_file);\n+\n+\tif (parse_insn_buffer(buf->buf, &todo_list)) {\n+\t\ttodo_list_release(&todo_list);\n+\t\treturn error(_(\"unusable todo list: '%s'\"), todo_file);\n+\t}\n+\n+\tstrbuf_addch(buf, '\\n');\n+\tstrbuf_commented_addf(buf, Q_(\"Rebase %s onto %s (%d command)\",\n+\t\t\t\t      \"Rebase %s onto %s (%d commands)\",\n+\t\t\t\t      todo_list.nr),\n+\t\t\t      shortrevisions, shortonto, todo_list.nr);\n+\tappend_todo_help(0, keep_empty, buf);\n+\n+\tif (write_message(buf->buf, buf->len, todo_file, 0)) {\n+\t\ttodo_list_release(&todo_list);\n+\t\treturn error_errno(_(\"could not write '%s'\"), todo_file);\n+\t}\n+\n+\tcopy_file(rebase_path_todo_backup(), todo_file, 0666);\n+\ttransform_todos(flags | TODO_LIST_SHORTEN_IDS);\n+\n+\tstrbuf_reset(buf);\n+\n+\tif (launch_sequence_editor(todo_file, buf, NULL)) {\n+\t\tapply_autostash(opts);\n+\t\tsequencer_remove_state(opts);\n+\t\ttodo_list_release(&todo_list);\n+\n+\t\treturn error(_(\"could not execute editor\"));\n+\t}\n+\n+\tstrbuf_stripspace(buf, 1);\n+\tif (buf->len == 0) {\n+\t\tapply_autostash(opts);\n+\t\tsequencer_remove_state(opts);\n+\t\ttodo_list_release(&todo_list);\n+\n+\t\treturn error(_(\"nothing to do\"));\n+\t}\n+\n+\ttodo_list_release(&todo_list);\n+\n+\tif (check_todo_list()) {\n+\t\tcheckout_onto(opts, onto_name, onto, orig_head);\n+\t\treturn 1;\n+\t}\n+\n+\ttransform_todos(flags & ~(TODO_LIST_SHORTEN_IDS));\n+\n+\tif (opts->allow_ff && skip_unnecessary_picks(&onto))\n+\t\treturn error(_(\"could not skip unnecessary pick commands\"));\n+\n+\tcheckout_onto(opts, onto_name, onto, orig_head);\n+\tif (require_clean_work_tree(\"rebase\", \"\", 1, 1))\n+\t\treturn 1;\n+\n+\treturn sequencer_continue(opts);\n+}\n+\n struct subject2item_entry {\n \tstruct hashmap_entry entry;\n \tint i;\ndiff --git a/sequencer.h b/sequencer.h\nindex 25b50efe2..02772b927 100644\n--- a/sequencer.h\n+++ b/sequencer.h\n@@ -89,6 +89,10 @@ int transform_todos(unsigned flags);\n enum missing_commit_check_level get_missing_commit_check_level(void);\n int check_todo_list(void);\n int skip_unnecessary_picks(const char **output_oid);\n+int complete_action(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, const char *cmd,\n+\t\t    unsigned autosquash, unsigned keep_empty);\n int rearrange_squash(void);\n \n extern const char sign_off_header[];\n-- \n2.18.0\n\n"},{"id":"352094","messageId":"20180710121557.6698-14-alban.gruin@gmail.com","threadId":"48814","inReplyTo":"20180710121557.6698-1-alban.gruin@gmail.com","subject":"[GSoC][PATCH v3 13/13] rebase -i: rewrite the rest of init_revisions_and_shortrevisions in C","fromName":"Alban Gruin","fromEmail":"alban.gruin@gmail.com","sentAt":"2018-07-10T12:15:57Z","receivedAt":"2018-07-10T12:17:40Z","isPatch":true,"sender":{"key":"alban.gruin@gmail.com","avatar":"https://avatars.githubusercontent.com/u/6310153?v=4"},"body":"This rewrites the part of init_revisions_and_shortrevisions() needed by\n`--complete-action` (which initialize $shortrevisions) from shell to C.\n\nWhen `upstream` is empty, it means that the user launched a `rebase\n--root`, and `onto` contains the ID of an empty commit.  As a range\nbetween an empty commit and `head` is not really meaningful, `onto` is\nnot used to initialize `shortrevisions` in this case.\n\nThe corresponding arguments passed to `--complete-action` are then\ndropped, and init_revisions_and_shortrevisions is stripped from\ngit-rebase--interactive.sh\n\nSigned-off-by: Alban Gruin <alban.gruin@gmail.com>\n---\n builtin/rebase--helper.c   | 40 ++++++++++++++++++++++++++++++++------\n git-rebase--interactive.sh | 27 ++++---------------------\n 2 files changed, 38 insertions(+), 29 deletions(-)\n\ndiff --git a/builtin/rebase--helper.c b/builtin/rebase--helper.c\nindex 5845f80de..59e788f22 100644\n--- a/builtin/rebase--helper.c\n+++ b/builtin/rebase--helper.c\n@@ -10,7 +10,7 @@ static GIT_PATH_FUNC(path_squash_onto, \"rebase-merge/squash-onto\")\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)\n+\t\t\t       char **revisions, char **shortrevisions)\n {\n \tconst char *base_rev = upstream ? upstream : onto;\n \tstruct object_id orig_head;\n@@ -19,7 +19,25 @@ static int get_revision_ranges(const char *upstream, const char *onto,\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+\tif (revisions)\n+\t\t*revisions = xstrfmt(\"%s...%s\", base_rev, *head_hash);\n+\tif (shortrevisions) {\n+\t\tconst char *shorthead;\n+\n+\t\tshorthead = find_unique_abbrev(&orig_head, DEFAULT_ABBREV);\n+\n+\t\tif (upstream) {\n+\t\t\tconst char *shortrev;\n+\t\t\tstruct object_id rev_oid;\n+\n+\t\t\tget_oid(base_rev, &rev_oid);\n+\t\t\tshortrev = find_unique_abbrev(&rev_oid, DEFAULT_ABBREV);\n+\n+\t\t\t*shortrevisions = xstrfmt(\"%s..%s\", shortrev, shorthead);\n+\t\t} else\n+\t\t\t*shortrevisions = xstrdup(shorthead);\n+\t}\n \n \treturn 0;\n }\n@@ -112,7 +130,7 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\n \t\tif (!upstream && squash_onto)\n \t\t\twrite_file(path_squash_onto(), \"%s\\n\", squash_onto);\n \n-\t\tret = get_revision_ranges(upstream, onto, &head_hash, &revisions);\n+\t\tret = get_revision_ranges(upstream, onto, &head_hash, &revisions, NULL);\n \t\tif (ret)\n \t\t\treturn ret;\n \n@@ -139,9 +157,19 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\n \t\treturn !!edit_todo_list(flags);\n \tif (command == PREPARE_BRANCH && argc == 2)\n \t\treturn !!prepare_branch_to_be_rebased(&opts, argv[1]);\n-\tif (command == COMPLETE_ACTION && argc == 6)\n-\t\treturn !!complete_action(&opts, flags, argv[1], argv[2], argv[3],\n-\t\t\t\t\t argv[4], argv[5], autosquash, keep_empty);\n+\tif (command == COMPLETE_ACTION && argc == 3) {\n+\t\tchar *shortrevisions = NULL;\n+\n+\t\tret = get_revision_ranges(upstream, onto, &head_hash, NULL, &shortrevisions);\n+\t\tif (ret)\n+\t\t\treturn ret;\n+\n+\t\tret = !!complete_action(&opts, flags, shortrevisions, argv[1], onto,\n+\t\t\t\t\thead_hash, argv[2], autosquash, keep_empty);\n+\n+\t\tfree(shortrevisions);\n+\t\treturn ret;\n+\t}\n \n \tusage_with_options(builtin_rebase_helper_usage, options);\n }\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex 4ca47aed1..08e9a21c2 100644\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -60,23 +60,6 @@ init_basic_state () {\n \twrite_basic_state\n }\n \n-init_revisions_and_shortrevisions () {\n-\tshorthead=$(git rev-parse --short $orig_head)\n-\tshortonto=$(git rev-parse --short $onto)\n-\tif test -z \"$rebase_root\"\n-\t\t# this is now equivalent to ! -z \"$upstream\"\n-\tthen\n-\t\tshortupstream=$(git rev-parse --short $upstream)\n-\t\trevisions=$upstream...$orig_head\n-\t\tshortrevisions=$shortupstream..$shorthead\n-\telse\n-\t\trevisions=$onto...$orig_head\n-\t\tshortrevisions=$shorthead\n-\t\ttest -z \"$squash_onto\" ||\n-\t\techo \"$squash_onto\" >\"$state_dir\"/squash-onto\n-\tfi\n-}\n-\n git_rebase__interactive () {\n \tinitiate_action \"$action\"\n \tret=$?\n@@ -87,8 +70,6 @@ git_rebase__interactive () {\n \tgit rebase--helper --prepare-branch \"$switch_to\" ${verbose:+--verbose}\n \tinit_basic_state\n \n-\tinit_revisions_and_shortrevisions\n-\n \tgit rebase--helper --make-script ${keep_empty:+--keep-empty} \\\n \t\t${rebase_merges:+--rebase-merges} \\\n \t\t${rebase_cousins:+--rebase-cousins} \\\n@@ -97,8 +78,8 @@ git_rebase__interactive () {\n \t\t${restrict_revision:+--restrict-revision ^\"$restrict_revision\"} >\"$todo\" ||\n \tdie \"$(gettext \"Could not generate todo list\")\"\n \n-\texec git rebase--helper --complete-action \"$shortrevisions\" \"$onto_name\" \\\n-\t\t\"$shortonto\" \"$orig_head\" \"$cmd\" $allow_empty_message \\\n-\t\t${autosquash:+--autosquash} ${keep_empty:+--keep-empty} \\\n-\t\t${verbose:+--verbose} ${force_rebase:+--no-ff}\n+\texec git rebase--helper --complete-action \"$onto_name\" \"$cmd\" \\\n+\t\t$allow_empty_message ${autosquash:+--autosquash} ${verbose:+--verbose} \\\n+\t\t${keep_empty:+--keep-empty} ${force_rebase:+--no-ff} \\\n+\t\t${upstream:+--upstream \"$upstream\"} ${onto:+--onto \"$onto\"}\n }\n-- \n2.18.0\n\n"},{"id":"352095","messageId":"20180710121557.6698-12-alban.gruin@gmail.com","threadId":"48814","inReplyTo":"20180710121557.6698-1-alban.gruin@gmail.com","subject":"[GSoC][PATCH v3 11/13] rebase--interactive: remove unused modes and functions","fromName":"Alban Gruin","fromEmail":"alban.gruin@gmail.com","sentAt":"2018-07-10T12:15:55Z","receivedAt":"2018-07-10T12:17:42Z","isPatch":true,"sender":{"key":"alban.gruin@gmail.com","avatar":"https://avatars.githubusercontent.com/u/6310153?v=4"},"body":"This removes the modes `--skip-unnecessary-picks`, `--append-todo-help`,\n`--checkout-onto`, `--shorten-ids` and `--expand-ids` from\nrebase--helper.c, the functions of git-rebase--interactive.sh that were\nrendered useless by the rewrite of complete_action(), and\nappend_todo_help_to_file() from rebase-interactive.c.\n\nskip_unnecessary_picks() and checkout_onto() becomes static, as they are\nonly used inside of the sequencer.\n\nSigned-off-by: Alban Gruin <alban.gruin@gmail.com>\n---\n builtin/rebase--helper.c   | 32 +++---------------------\n git-rebase--interactive.sh | 50 --------------------------------------\n rebase-interactive.c       | 22 -----------------\n rebase-interactive.h       |  1 -\n sequencer.c                |  8 +++---\n sequencer.h                |  4 ---\n 6 files changed, 7 insertions(+), 110 deletions(-)\n\ndiff --git a/builtin/rebase--helper.c b/builtin/rebase--helper.c\nindex bb3698dba..8ab808da4 100644\n--- a/builtin/rebase--helper.c\n+++ b/builtin/rebase--helper.c\n@@ -15,13 +15,10 @@ int cmd_rebase__helper(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, verbose = 0,\n \t\tautosquash = 0;\n-\tint abbreviate_commands = 0, rebase_cousins = -1, ret;\n-\tconst char *oid = NULL;\n+\tint abbreviate_commands = 0, rebase_cousins = -1;\n \tenum {\n-\t\tCONTINUE = 1, ABORT, MAKE_SCRIPT, SHORTEN_OIDS, EXPAND_OIDS,\n-\t\tCHECK_TODO_LIST, SKIP_UNNECESSARY_PICKS, REARRANGE_SQUASH,\n-\t\tADD_EXEC, APPEND_TODO_HELP, EDIT_TODO, PREPARE_BRANCH,\n-\t\tCHECKOUT_ONTO, COMPLETE_ACTION\n+\t\tCONTINUE = 1, ABORT, MAKE_SCRIPT, CHECK_TODO_LIST, REARRANGE_SQUASH,\n+\t\tADD_EXEC, EDIT_TODO, PREPARE_BRANCH, COMPLETE_ACTION\n \t} command = 0;\n \tstruct option options[] = {\n \t\tOPT_BOOL(0, \"ff\", &opts.allow_ff, N_(\"allow fast-forward\")),\n@@ -40,27 +37,17 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\n \t\t\t\tABORT),\n \t\tOPT_CMDMODE(0, \"make-script\", &command,\n \t\t\tN_(\"make rebase script\"), MAKE_SCRIPT),\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, \"skip-unnecessary-picks\", &command,\n-\t\t\tN_(\"skip unnecessary picks\"), SKIP_UNNECESSARY_PICKS),\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_CMDMODE(0, \"append-todo-help\", &command,\n-\t\t\t    N_(\"insert the help in the todo list\"), APPEND_TODO_HELP),\n \t\tOPT_CMDMODE(0, \"edit-todo\", &command,\n \t\t\t    N_(\"edit the todo list during an interactive rebase\"),\n \t\t\t    EDIT_TODO),\n \t\tOPT_CMDMODE(0, \"prepare-branch\", &command,\n \t\t\t    N_(\"prepare the branch to be rebased\"), PREPARE_BRANCH),\n-\t\tOPT_CMDMODE(0, \"checkout-onto\", &command,\n-\t\t\t    N_(\"checkout a commit\"), CHECKOUT_ONTO),\n \t\tOPT_CMDMODE(0, \"complete-action\", &command,\n \t\t\t    N_(\"complete the action\"), COMPLETE_ACTION),\n \t\tOPT_END()\n@@ -81,7 +68,6 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\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@@ -93,28 +79,16 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\n \t\treturn !!sequencer_remove_state(&opts);\n \tif (command == MAKE_SCRIPT && argc > 1)\n \t\treturn !!sequencer_make_script(stdout, argc, argv, flags);\n-\tif ((command == SHORTEN_OIDS || command == EXPAND_OIDS) && argc == 1)\n-\t\treturn !!transform_todos(flags);\n \tif (command == CHECK_TODO_LIST && argc == 1)\n \t\treturn !!check_todo_list();\n-\tif (command == SKIP_UNNECESSARY_PICKS && argc == 1) {\n-\t\tret = !!skip_unnecessary_picks(&oid);\n-\t\tif (!ret && oid)\n-\t\t\tputs(oid);\n-\t\treturn ret;\n-\t}\n \tif (command == REARRANGE_SQUASH && argc == 1)\n \t\treturn !!rearrange_squash();\n \tif (command == ADD_EXEC && argc == 2)\n \t\treturn !!sequencer_add_exec_commands(argv[1]);\n-\tif (command == APPEND_TODO_HELP && argc == 1)\n-\t\treturn !!append_todo_help_to_file(0, keep_empty);\n \tif (command == EDIT_TODO && argc == 1)\n \t\treturn !!edit_todo_list(flags);\n \tif (command == PREPARE_BRANCH && argc == 2)\n \t\treturn !!prepare_branch_to_be_rebased(&opts, argv[1]);\n-\tif (command == CHECKOUT_ONTO && argc == 4)\n-\t\treturn !!checkout_onto(&opts, argv[1], argv[2], argv[3]);\n \tif (command == COMPLETE_ACTION && argc == 6)\n \t\treturn !!complete_action(&opts, flags, argv[1], argv[2], argv[3],\n \t\t\t\t\t argv[4], argv[5], autosquash, keep_empty);\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex 59dc4888a..0d66c0f8b 100644\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -16,56 +16,6 @@ todo=\"$state_dir\"/git-rebase-todo\n GIT_CHERRY_PICK_HELP=\"$resolvemsg\"\n export GIT_CHERRY_PICK_HELP\n \n-comment_char=$(git config --get core.commentchar 2>/dev/null)\n-case \"$comment_char\" in\n-'' | auto)\n-\tcomment_char=\"#\"\n-\t;;\n-?)\n-\t;;\n-*)\n-\tcomment_char=$(echo \"$comment_char\" | cut -c1)\n-\t;;\n-esac\n-\n-die_abort () {\n-\tapply_autostash\n-\trm -rf \"$state_dir\"\n-\tdie \"$1\"\n-}\n-\n-has_action () {\n-\ttest -n \"$(git stripspace --strip-comments <\"$1\")\"\n-}\n-\n-git_sequence_editor () {\n-\tif test -z \"$GIT_SEQUENCE_EDITOR\"\n-\tthen\n-\t\tGIT_SEQUENCE_EDITOR=\"$(git config sequence.editor)\"\n-\t\tif [ -z \"$GIT_SEQUENCE_EDITOR\" ]\n-\t\tthen\n-\t\t\tGIT_SEQUENCE_EDITOR=\"$(git var GIT_EDITOR)\" || return $?\n-\t\tfi\n-\tfi\n-\n-\teval \"$GIT_SEQUENCE_EDITOR\" '\"$@\"'\n-}\n-\n-expand_todo_ids() {\n-\tgit rebase--helper --expand-ids\n-}\n-\n-collapse_todo_ids() {\n-\tgit rebase--helper --shorten-ids\n-}\n-\n-get_missing_commit_check_level () {\n-\tcheck_level=$(git config --get rebase.missingCommitsCheck)\n-\tcheck_level=${check_level:-ignore}\n-\t# Don't be case sensitive\n-\tprintf '%s' \"$check_level\" | tr 'A-Z' 'a-z'\n-}\n-\n # Initiate an action. If the cannot be any\n # further action it  may exec a command\n # or exit and not return.\ndiff --git a/rebase-interactive.c b/rebase-interactive.c\nindex d8b946559..f99e596d2 100644\n--- a/rebase-interactive.c\n+++ b/rebase-interactive.c\n@@ -52,28 +52,6 @@ void append_todo_help(unsigned edit_todo, unsigned keep_empty,\n \t}\n }\n \n-int append_todo_help_to_file(unsigned edit_todo, unsigned keep_empty)\n-{\n-\tstruct strbuf buf = STRBUF_INIT;\n-\tFILE *todo;\n-\tint ret;\n-\n-\ttodo = fopen_or_warn(rebase_path_todo(), \"a\");\n-\tif (!todo)\n-\t\treturn 1;\n-\n-\tappend_todo_help(edit_todo, keep_empty, &buf);\n-\n-\tret = fputs(buf.buf, todo);\n-\tif (ret < 0)\n-\t\terror_errno(_(\"could not append help text to '%s'\"), rebase_path_todo());\n-\n-\tfclose(todo);\n-\tstrbuf_release(&buf);\n-\n-\treturn ret;\n-}\n-\n int edit_todo_list(unsigned flags)\n {\n \tstruct strbuf buf = STRBUF_INIT;\ndiff --git a/rebase-interactive.h b/rebase-interactive.h\nindex c0ba83be3..47025c47a 100644\n--- a/rebase-interactive.h\n+++ b/rebase-interactive.h\n@@ -6,7 +6,6 @@\n \n void append_todo_help(unsigned edit_todo, unsigned keep_empty,\n \t\t      struct strbuf *buf);\n-int append_todo_help_to_file(unsigned edit_todo, unsigned keep_empty);\n int edit_todo_list(unsigned flags);\n \n #endif\ndiff --git a/sequencer.c b/sequencer.c\nindex da975285d..6ceada4a9 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -3166,9 +3166,9 @@ int prepare_branch_to_be_rebased(struct replay_opts *opts, const char *commit)\n \treturn 0;\n }\n \n-int checkout_onto(struct replay_opts *opts,\n-\t\t  const char *onto_name, const char *onto,\n-\t\t  const char *orig_head)\n+static int checkout_onto(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 \tstruct object_id oid;\n \tconst char *action = reflog_message(opts, \"start\", \"checkout %s\", onto_name);\n@@ -4396,7 +4396,7 @@ static int rewrite_file(const char *path, const char *buf, size_t len)\n }\n \n /* skip picking commits whose parents are unchanged */\n-int skip_unnecessary_picks(const char **output_oid)\n+static int skip_unnecessary_picks(const char **output_oid)\n {\n \tconst char *todo_file = rebase_path_todo();\n \tstruct strbuf buf = STRBUF_INIT;\ndiff --git a/sequencer.h b/sequencer.h\nindex 02772b927..b9f9e7827 100644\n--- a/sequencer.h\n+++ b/sequencer.h\n@@ -88,7 +88,6 @@ int sequencer_add_exec_commands(const char *command);\n int transform_todos(unsigned flags);\n enum missing_commit_check_level get_missing_commit_check_level(void);\n int check_todo_list(void);\n-int skip_unnecessary_picks(const char **output_oid);\n int complete_action(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, const char *cmd,\n@@ -111,9 +110,6 @@ void commit_post_rewrite(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 checkout_onto(struct replay_opts *opts,\n-\t\t  const char *onto_name, const char *onto,\n-\t\t  const char *orig_head);\n \n #define SUMMARY_INITIAL_COMMIT   (1 << 0)\n #define SUMMARY_SHOW_AUTHOR_DATE (1 << 1)\n-- \n2.18.0\n\n"},{"id":"352096","messageId":"20180710121557.6698-13-alban.gruin@gmail.com","threadId":"48814","inReplyTo":"20180710121557.6698-1-alban.gruin@gmail.com","subject":"[GSoC][PATCH v3 12/13] rebase -i: implement the logic to initialize the variable $revision in C","fromName":"Alban Gruin","fromEmail":"alban.gruin@gmail.com","sentAt":"2018-07-10T12:15:56Z","receivedAt":"2018-07-10T12:17:47Z","isPatch":true,"sender":{"key":"alban.gruin@gmail.com","avatar":"https://avatars.githubusercontent.com/u/6310153?v=4"},"body":"This rewrites the part of init_revisions_and_shortrevisions() needed by\n`--make-script` from shell to C.  The new version is called\nget_revision_ranges(), and is a static function inside of\nrebase--helper.c.\n\nUnlike init_revisions_and_shortrevisions(), get_revision_ranges()\ndoesn’t write $squash_onto to the state directory, it’s done by the\nhandler of `--make-script` instead.\n\nFinally, this drops the $revision argument passed to `--make-script` in\ngit-rebase--interactive.sh, and rebase--helper is changed accordingly.\n\nSigned-off-by: Alban Gruin <alban.gruin@gmail.com>\n---\n builtin/rebase--helper.c   | 56 ++++++++++++++++++++++++++++++++++++--\n git-rebase--interactive.sh |  4 ++-\n 2 files changed, 56 insertions(+), 4 deletions(-)\n\ndiff --git a/builtin/rebase--helper.c b/builtin/rebase--helper.c\nindex 8ab808da4..5845f80de 100644\n--- a/builtin/rebase--helper.c\n+++ b/builtin/rebase--helper.c\n@@ -4,6 +4,25 @@\n #include \"parse-options.h\"\n #include \"sequencer.h\"\n #include \"rebase-interactive.h\"\n+#include \"argv-array.h\"\n+\n+static GIT_PATH_FUNC(path_squash_onto, \"rebase-merge/squash-onto\")\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)\n+{\n+\tconst char *base_rev = upstream ? upstream : onto;\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+\treturn 0;\n+}\n \n static const char * const builtin_rebase_helper_usage[] = {\n \tN_(\"git rebase--helper [<options>]\"),\n@@ -15,7 +34,9 @@ int cmd_rebase__helper(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, verbose = 0,\n \t\tautosquash = 0;\n-\tint abbreviate_commands = 0, rebase_cousins = -1;\n+\tint abbreviate_commands = 0, rebase_cousins = -1, ret;\n+\tconst char *head_hash = NULL, *onto = NULL, *restrict_revisions = NULL,\n+\t\t*squash_onto = NULL, *upstream = NULL;\n \tenum {\n \t\tCONTINUE = 1, ABORT, MAKE_SCRIPT, CHECK_TODO_LIST, REARRANGE_SQUASH,\n \t\tADD_EXEC, EDIT_TODO, PREPARE_BRANCH, COMPLETE_ACTION\n@@ -50,6 +71,13 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\n \t\t\t    N_(\"prepare the branch to be rebased\"), PREPARE_BRANCH),\n \t\tOPT_CMDMODE(0, \"complete-action\", &command,\n \t\t\t    N_(\"complete the action\"), COMPLETE_ACTION),\n+\t\tOPT_STRING(0, \"onto\", &onto, N_(\"onto\"), N_(\"onto\")),\n+\t\tOPT_STRING(0, \"restrict-revision\", &restrict_revisions,\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_END()\n \t};\n \n@@ -77,8 +105,30 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\n \t\treturn !!sequencer_continue(&opts);\n \tif (command == ABORT && argc == 1)\n \t\treturn !!sequencer_remove_state(&opts);\n-\tif (command == MAKE_SCRIPT && argc > 1)\n-\t\treturn !!sequencer_make_script(stdout, argc, argv, flags);\n+\tif (command == MAKE_SCRIPT && (argc == 1 || argc == 2)) {\n+\t\tchar *revisions = NULL;\n+\t\tstruct argv_array make_script_args = ARGV_ARRAY_INIT;\n+\n+\t\tif (!upstream && squash_onto)\n+\t\t\twrite_file(path_squash_onto(), \"%s\\n\", squash_onto);\n+\n+\t\tret = get_revision_ranges(upstream, onto, &head_hash, &revisions);\n+\t\tif (ret)\n+\t\t\treturn ret;\n+\n+\t\targv_array_pushl(&make_script_args, \"\", revisions, NULL);\n+\t\tif (argc == 2)\n+\t\t\targv_array_push(&make_script_args, restrict_revisions);\n+\n+\t\tret = !!sequencer_make_script(stdout,\n+\t\t\t\t\t      make_script_args.argc, make_script_args.argv,\n+\t\t\t\t\t      flags);\n+\n+\t\tfree(revisions);\n+\t\targv_array_clear(&make_script_args);\n+\n+\t\treturn ret;\n+\t}\n \tif (command == CHECK_TODO_LIST && argc == 1)\n \t\treturn !!check_todo_list();\n \tif (command == REARRANGE_SQUASH && argc == 1)\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex 0d66c0f8b..4ca47aed1 100644\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -92,7 +92,9 @@ git_rebase__interactive () {\n \tgit rebase--helper --make-script ${keep_empty:+--keep-empty} \\\n \t\t${rebase_merges:+--rebase-merges} \\\n \t\t${rebase_cousins:+--rebase-cousins} \\\n-\t\t$revisions ${restrict_revision+^$restrict_revision} >\"$todo\" ||\n+\t\t${upstream:+--upstream \"$upstream\"} ${onto:+--onto \"$onto\"} \\\n+\t\t${squash_onto:+--squash-onto \"$squash_onto\"} \\\n+\t\t${restrict_revision:+--restrict-revision ^\"$restrict_revision\"} >\"$todo\" ||\n \tdie \"$(gettext \"Could not generate todo list\")\"\n \n \texec git rebase--helper --complete-action \"$shortrevisions\" \"$onto_name\" \\\n-- \n2.18.0\n\n"},{"id":"352097","messageId":"20180710121557.6698-10-alban.gruin@gmail.com","threadId":"48814","inReplyTo":"20180710121557.6698-1-alban.gruin@gmail.com","subject":"[GSoC][PATCH v3 09/13] sequencer: change the way skip_unnecessary_picks() returns its result","fromName":"Alban Gruin","fromEmail":"alban.gruin@gmail.com","sentAt":"2018-07-10T12:15:53Z","receivedAt":"2018-07-10T12:17:50Z","isPatch":true,"sender":{"key":"alban.gruin@gmail.com","avatar":"https://avatars.githubusercontent.com/u/6310153?v=4"},"body":"Instead of skip_unnecessary_picks() printing its result to stdout, it\nreturns it into a const char *, as the rewrite of complete_action()\n(to come in the next commit) will need it.\n\nrebase--helper then is modified to fit this change.\n\nSigned-off-by: Alban Gruin <alban.gruin@gmail.com>\n---\n builtin/rebase--helper.c | 11 ++++++++---\n sequencer.c              |  4 ++--\n sequencer.h              |  2 +-\n 3 files changed, 11 insertions(+), 6 deletions(-)\n\ndiff --git a/builtin/rebase--helper.c b/builtin/rebase--helper.c\nindex b9af96af7..d4cfe43e7 100644\n--- a/builtin/rebase--helper.c\n+++ b/builtin/rebase--helper.c\n@@ -14,7 +14,8 @@ int cmd_rebase__helper(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, verbose = 0;\n-\tint abbreviate_commands = 0, rebase_cousins = -1;\n+\tint abbreviate_commands = 0, rebase_cousins = -1, ret;\n+\tconst char *oid = NULL;\n \tenum {\n \t\tCONTINUE = 1, ABORT, MAKE_SCRIPT, SHORTEN_OIDS, EXPAND_OIDS,\n \t\tCHECK_TODO_LIST, SKIP_UNNECESSARY_PICKS, REARRANGE_SQUASH,\n@@ -91,8 +92,12 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\n \t\treturn !!transform_todos(flags);\n \tif (command == CHECK_TODO_LIST && argc == 1)\n \t\treturn !!check_todo_list();\n-\tif (command == SKIP_UNNECESSARY_PICKS && argc == 1)\n-\t\treturn !!skip_unnecessary_picks();\n+\tif (command == SKIP_UNNECESSARY_PICKS && argc == 1) {\n+\t\tret = !!skip_unnecessary_picks(&oid);\n+\t\tif (!ret && oid)\n+\t\t\tputs(oid);\n+\t\treturn ret;\n+\t}\n \tif (command == REARRANGE_SQUASH && argc == 1)\n \t\treturn !!rearrange_squash();\n \tif (command == ADD_EXEC && argc == 2)\ndiff --git a/sequencer.c b/sequencer.c\nindex 2b6ddc6cf..676ac1320 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -4392,7 +4392,7 @@ static int rewrite_file(const char *path, const char *buf, size_t len)\n }\n \n /* skip picking commits whose parents are unchanged */\n-int skip_unnecessary_picks(void)\n+int skip_unnecessary_picks(const char **output_oid)\n {\n \tconst char *todo_file = rebase_path_todo();\n \tstruct strbuf buf = STRBUF_INIT;\n@@ -4467,7 +4467,7 @@ int skip_unnecessary_picks(void)\n \t}\n \n \ttodo_list_release(&todo_list);\n-\tprintf(\"%s\\n\", oid_to_hex(oid));\n+\t*output_oid = oid_to_hex(oid);\n \n \treturn 0;\n }\ndiff --git a/sequencer.h b/sequencer.h\nindex 11a533461..25b50efe2 100644\n--- a/sequencer.h\n+++ b/sequencer.h\n@@ -88,7 +88,7 @@ int sequencer_add_exec_commands(const char *command);\n int transform_todos(unsigned flags);\n enum missing_commit_check_level get_missing_commit_check_level(void);\n int check_todo_list(void);\n-int skip_unnecessary_picks(void);\n+int skip_unnecessary_picks(const char **output_oid);\n int rearrange_squash(void);\n \n extern const char sign_off_header[];\n-- \n2.18.0\n\n"},{"id":"352098","messageId":"20180710121557.6698-5-alban.gruin@gmail.com","threadId":"48814","inReplyTo":"20180710121557.6698-1-alban.gruin@gmail.com","subject":"[GSoC][PATCH v3 04/13] rebase-interactive: rewrite the edit-todo functionality in C","fromName":"Alban Gruin","fromEmail":"alban.gruin@gmail.com","sentAt":"2018-07-10T12:15:48Z","receivedAt":"2018-07-10T12:18:04Z","isPatch":true,"sender":{"key":"alban.gruin@gmail.com","avatar":"https://avatars.githubusercontent.com/u/6310153?v=4"},"body":"This rewrites the edit-todo functionality from shell to C.\n\nTo achieve that, a new command mode, `edit-todo`, is added, and the\n`write-edit-todo` flag is removed, as the shell script does not need to\nwrite the edit todo help message to the todo list anymore.\n\nThe shell version is then stripped in favour of a call to the helper.\n\nSigned-off-by: Alban Gruin <alban.gruin@gmail.com>\n---\nUnchanged from v2.\n\nbuiltin/rebase--helper.c   | 13 ++++++++-----\n git-rebase--interactive.sh | 11 +----------\n rebase-interactive.c       | 31 +++++++++++++++++++++++++++++++\n rebase-interactive.h       |  1 +\n 4 files changed, 41 insertions(+), 15 deletions(-)\n\ndiff --git a/builtin/rebase--helper.c b/builtin/rebase--helper.c\nindex 05e73e71d..731a64971 100644\n--- a/builtin/rebase--helper.c\n+++ b/builtin/rebase--helper.c\n@@ -13,12 +13,12 @@ static const char * const builtin_rebase_helper_usage[] = {\n int cmd_rebase__helper(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, write_edit_todo = 0;\n+\tunsigned flags = 0, keep_empty = 0, rebase_merges = 0;\n \tint abbreviate_commands = 0, rebase_cousins = -1;\n \tenum {\n \t\tCONTINUE = 1, ABORT, MAKE_SCRIPT, SHORTEN_OIDS, EXPAND_OIDS,\n \t\tCHECK_TODO_LIST, SKIP_UNNECESSARY_PICKS, REARRANGE_SQUASH,\n-\t\tADD_EXEC, APPEND_TODO_HELP\n+\t\tADD_EXEC, APPEND_TODO_HELP, EDIT_TODO\n \t} command = 0;\n \tstruct option options[] = {\n \t\tOPT_BOOL(0, \"ff\", &opts.allow_ff, N_(\"allow fast-forward\")),\n@@ -28,8 +28,6 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\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, \"write-edit-todo\", &write_edit_todo,\n-\t\t\t N_(\"append the edit-todo message to the todo-list\")),\n \t\tOPT_CMDMODE(0, \"continue\", &command, N_(\"continue rebase\"),\n \t\t\t\tCONTINUE),\n \t\tOPT_CMDMODE(0, \"abort\", &command, N_(\"abort rebase\"),\n@@ -50,6 +48,9 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\n \t\t\tN_(\"insert exec commands in todo list\"), ADD_EXEC),\n \t\tOPT_CMDMODE(0, \"append-todo-help\", &command,\n \t\t\t    N_(\"insert the help in the todo list\"), APPEND_TODO_HELP),\n+\t\tOPT_CMDMODE(0, \"edit-todo\", &command,\n+\t\t\t    N_(\"edit the todo list during an interactive rebase\"),\n+\t\t\t    EDIT_TODO),\n \t\tOPT_END()\n \t};\n \n@@ -90,6 +91,8 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\n \tif (command == ADD_EXEC && argc == 2)\n \t\treturn !!sequencer_add_exec_commands(argv[1]);\n \tif (command == APPEND_TODO_HELP && argc == 1)\n-\t\treturn !!append_todo_help(write_edit_todo, keep_empty);\n+\t\treturn !!append_todo_help(0, keep_empty);\n+\tif (command == EDIT_TODO && argc == 1)\n+\t\treturn !!edit_todo_list(flags);\n \tusage_with_options(builtin_rebase_helper_usage, options);\n }\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex 94c23a7af..2defe607f 100644\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -108,16 +108,7 @@ initiate_action () {\n \t\t     --continue\n \t\t;;\n \tedit-todo)\n-\t\tgit stripspace --strip-comments <\"$todo\" >\"$todo\".new\n-\t\tmv -f \"$todo\".new \"$todo\"\n-\t\tcollapse_todo_ids\n-\t\tgit rebase--helper --append-todo-help --write-edit-todo\n-\n-\t\tgit_sequence_editor \"$todo\" ||\n-\t\t\tdie \"$(gettext \"Could not execute editor\")\"\n-\t\texpand_todo_ids\n-\n-\t\texit\n+\t\texec git rebase--helper --edit-todo\n \t\t;;\n \tshow-current-patch)\n \t\texec git show REBASE_HEAD --\ndiff --git a/rebase-interactive.c b/rebase-interactive.c\nindex d7996bc8d..403ecbf3c 100644\n--- a/rebase-interactive.c\n+++ b/rebase-interactive.c\n@@ -66,3 +66,34 @@ int append_todo_help(unsigned edit_todo, unsigned keep_empty)\n \n \treturn ret;\n }\n+\n+int edit_todo_list(unsigned flags)\n+{\n+\tstruct strbuf buf = STRBUF_INIT;\n+\tconst char *todo_file = rebase_path_todo();\n+\tFILE *todo;\n+\n+\tif (strbuf_read_file(&buf, todo_file, 0) < 0)\n+\t\treturn error_errno(_(\"could not read '%s'.\"), todo_file);\n+\n+\tstrbuf_stripspace(&buf, 1);\n+\ttodo = fopen_or_warn(todo_file, \"w\");\n+\tif (!todo) {\n+\t\tstrbuf_release(&buf);\n+\t\treturn 1;\n+\t}\n+\n+\tstrbuf_write(&buf, todo);\n+\tfclose(todo);\n+\tstrbuf_release(&buf);\n+\n+\ttransform_todos(flags | TODO_LIST_SHORTEN_IDS);\n+\tappend_todo_help(1, 0);\n+\n+\tif (launch_sequence_editor(todo_file, NULL, NULL))\n+\t\treturn 1;\n+\n+\ttransform_todos(flags & ~(TODO_LIST_SHORTEN_IDS));\n+\n+\treturn 0;\n+}\ndiff --git a/rebase-interactive.h b/rebase-interactive.h\nindex 47372624e..155219e74 100644\n--- a/rebase-interactive.h\n+++ b/rebase-interactive.h\n@@ -2,5 +2,6 @@\n #define REBASE_INTERACTIVE_H\n \n int append_todo_help(unsigned edit_todo, unsigned keep_empty);\n+int edit_todo_list(unsigned flags);\n \n #endif\n-- \n2.18.0\n\n"},{"id":"352099","messageId":"20180710121557.6698-6-alban.gruin@gmail.com","threadId":"48814","inReplyTo":"20180710121557.6698-1-alban.gruin@gmail.com","subject":"[GSoC][PATCH v3 05/13] sequencer: add a new function to silence a command, except if it fails","fromName":"Alban Gruin","fromEmail":"alban.gruin@gmail.com","sentAt":"2018-07-10T12:15:49Z","receivedAt":"2018-07-10T12:18:04Z","isPatch":true,"sender":{"key":"alban.gruin@gmail.com","avatar":"https://avatars.githubusercontent.com/u/6310153?v=4"},"body":"This adds a new function, run_command_silent_on_success(), to\nredirect the stdout and stderr of a command to a strbuf, and then to run\nthat command. This strbuf is printed only if the command fails. It is\nfunctionnaly similar to output() from git-rebase.sh.\n\nrun_git_commit() is then refactored to use of\nrun_command_silent_on_success().\n\nSigned-off-by: Alban Gruin <alban.gruin@gmail.com>\n---\n sequencer.c | 51 +++++++++++++++++++++++++--------------------------\n 1 file changed, 25 insertions(+), 26 deletions(-)\n\ndiff --git a/sequencer.c b/sequencer.c\nindex 57fd58bc1..1b5d50298 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -768,6 +768,23 @@ N_(\"you have staged changes in your working tree\\n\"\n #define VERIFY_MSG  (1<<4)\n #define CREATE_ROOT_COMMIT (1<<5)\n \n+static int run_command_silent_on_success(struct child_process *cmd)\n+{\n+\tstruct strbuf buf = STRBUF_INIT;\n+\tint rc;\n+\n+\tcmd->stdout_to_stderr = 1;\n+\trc = pipe_command(cmd,\n+\t\t\t  NULL, 0,\n+\t\t\t  NULL, 0,\n+\t\t\t  &buf, 0);\n+\n+\tif (rc)\n+\t\tfputs(buf.buf, stderr);\n+\tstrbuf_release(&buf);\n+\treturn rc;\n+}\n+\n /*\n  * If we are cherry-pick, and if the merge did not result in\n  * hand-editing, we will hit this commit and inherit the original\n@@ -822,18 +839,11 @@ static int run_git_commit(const char *defmsg, struct replay_opts *opts,\n \n \tcmd.git_cmd = 1;\n \n-\tif (is_rebase_i(opts)) {\n-\t\tif (!(flags & EDIT_MSG)) {\n-\t\t\tcmd.stdout_to_stderr = 1;\n-\t\t\tcmd.err = -1;\n-\t\t}\n-\n-\t\tif (read_env_script(&cmd.env_array)) {\n-\t\t\tconst char *gpg_opt = gpg_sign_opt_quoted(opts);\n+\tif (is_rebase_i(opts) && read_env_script(&cmd.env_array)) {\n+\t\tconst char *gpg_opt = gpg_sign_opt_quoted(opts);\n \n-\t\t\treturn error(_(staged_changes_advice),\n-\t\t\t\t     gpg_opt, gpg_opt);\n-\t\t}\n+\t\treturn error(_(staged_changes_advice),\n+\t\t\t     gpg_opt, gpg_opt);\n \t}\n \n \targv_array_push(&cmd.args, \"commit\");\n@@ -863,21 +873,10 @@ static int run_git_commit(const char *defmsg, struct replay_opts *opts,\n \tif (opts->allow_empty_message)\n \t\targv_array_push(&cmd.args, \"--allow-empty-message\");\n \n-\tif (cmd.err == -1) {\n-\t\t/* hide stderr on success */\n-\t\tstruct strbuf buf = STRBUF_INIT;\n-\t\tint rc = pipe_command(&cmd,\n-\t\t\t\t      NULL, 0,\n-\t\t\t\t      /* stdout is already redirected */\n-\t\t\t\t      NULL, 0,\n-\t\t\t\t      &buf, 0);\n-\t\tif (rc)\n-\t\t\tfputs(buf.buf, stderr);\n-\t\tstrbuf_release(&buf);\n-\t\treturn rc;\n-\t}\n-\n-\treturn run_command(&cmd);\n+\tif (is_rebase_i(opts) && !(flags & EDIT_MSG))\n+\t\treturn run_command_silent_on_success(&cmd);\n+\telse\n+\t\treturn run_command(&cmd);\n }\n \n static int rest_is_empty(const struct strbuf *sb, int start)\n-- \n2.18.0\n\n"},{"id":"352100","messageId":"20180710121557.6698-4-alban.gruin@gmail.com","threadId":"48814","inReplyTo":"20180710121557.6698-1-alban.gruin@gmail.com","subject":"[GSoC][PATCH v3 03/13] editor: add a function to launch the sequence editor","fromName":"Alban Gruin","fromEmail":"alban.gruin@gmail.com","sentAt":"2018-07-10T12:15:47Z","receivedAt":"2018-07-10T12:18:21Z","isPatch":true,"sender":{"key":"alban.gruin@gmail.com","avatar":"https://avatars.githubusercontent.com/u/6310153?v=4"},"body":"As part of the rewrite of interactive rebase, the sequencer will need to\nopen the sequence editor to allow the user to edit the todo list.\nInstead of duplicating the existing launch_editor() function, this\nrefactors it to a new function, launch_specified_editor(), which takes\nthe editor as a parameter, in addition to the path, the buffer and the\nenvironment variables.  launch_sequence_editor() is then added to launch\nthe sequence editor.\n\nSigned-off-by: Alban Gruin <alban.gruin@gmail.com>\n---\n cache.h  |  1 +\n editor.c | 27 +++++++++++++++++++++++++--\n strbuf.h |  2 ++\n 3 files changed, 28 insertions(+), 2 deletions(-)\n\ndiff --git a/cache.h b/cache.h\nindex d49092d94..33fa70f55 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -1472,6 +1472,7 @@ extern const char *fmt_name(const char *name, const char *email);\n extern const char *ident_default_name(void);\n extern const char *ident_default_email(void);\n extern const char *git_editor(void);\n+extern const char *git_sequence_editor(void);\n extern const char *git_pager(int stdout_is_tty);\n extern int is_terminal_dumb(void);\n extern int git_ident_config(const char *, const char *, void *);\ndiff --git a/editor.c b/editor.c\nindex 9a9b4e12d..c985eee1f 100644\n--- a/editor.c\n+++ b/editor.c\n@@ -1,4 +1,5 @@\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"strbuf.h\"\n #include \"run-command.h\"\n #include \"sigchain.h\"\n@@ -34,10 +35,21 @@ const char *git_editor(void)\n \treturn editor;\n }\n \n-int launch_editor(const char *path, struct strbuf *buffer, const char *const *env)\n+const char *git_sequence_editor(void)\n {\n-\tconst char *editor = git_editor();\n+\tconst char *editor = getenv(\"GIT_SEQUENCE_EDITOR\");\n+\n+\tif (!editor)\n+\t\tgit_config_get_string_const(\"sequence.editor\", &editor);\n+\tif (!editor)\n+\t\teditor = git_editor();\n \n+\treturn editor;\n+}\n+\n+static int launch_specified_editor(const char *editor, const char *path,\n+\t\t\t\t   struct strbuf *buffer, const char *const *env)\n+{\n \tif (!editor)\n \t\treturn error(\"Terminal is dumb, but EDITOR unset\");\n \n@@ -95,3 +107,14 @@ int launch_editor(const char *path, struct strbuf *buffer, const char *const *en\n \t\treturn error_errno(\"could not read file '%s'\", path);\n \treturn 0;\n }\n+\n+int launch_editor(const char *path, struct strbuf *buffer, const char *const *env)\n+{\n+\treturn launch_specified_editor(git_editor(), path, buffer, env);\n+}\n+\n+int launch_sequence_editor(const char *path, struct strbuf *buffer,\n+\t\t\t   const char *const *env)\n+{\n+\treturn launch_specified_editor(git_sequence_editor(), path, buffer, env);\n+}\ndiff --git a/strbuf.h b/strbuf.h\nindex 60a35aef1..66da9822f 100644\n--- a/strbuf.h\n+++ b/strbuf.h\n@@ -575,6 +575,8 @@ extern void strbuf_add_unique_abbrev(struct strbuf *sb,\n  * file's contents are not read into the buffer upon completion.\n  */\n extern int launch_editor(const char *path, struct strbuf *buffer, const char *const *env);\n+extern int launch_sequence_editor(const char *path, struct strbuf *buffer,\n+\t\t\t\t  const char *const *env);\n \n extern void strbuf_add_lines(struct strbuf *sb, const char *prefix, const char *buf, size_t size);\n \n-- \n2.18.0\n\n"},{"id":"352101","messageId":"20180710121557.6698-7-alban.gruin@gmail.com","threadId":"48814","inReplyTo":"20180710121557.6698-1-alban.gruin@gmail.com","subject":"[GSoC][PATCH v3 06/13] rebase -i: rewrite setup_reflog_action() in C","fromName":"Alban Gruin","fromEmail":"alban.gruin@gmail.com","sentAt":"2018-07-10T12:15:50Z","receivedAt":"2018-07-10T12:18:23Z","isPatch":true,"sender":{"key":"alban.gruin@gmail.com","avatar":"https://avatars.githubusercontent.com/u/6310153?v=4"},"body":"This rewrites (the misnamed) setup_reflog_action() from shell to C. The\nnew version is called prepare_branch_to_be_rebased().\n\nA new command is added to rebase--helper.c, “checkout-base”, as well as\na new flag, “verbose”, to avoid silencing the output of the checkout\noperation called by checkout_base_commit().\n\nThe function `run_git_checkout()` will also be used in the next commit,\ntherefore its code is not part of `checkout_base_commit()`.\n\nThe shell version is then stripped in favour of a call to the helper.\n\nAs $GIT_REFLOG_ACTION is no longer set at the first call of\ncheckout_onto(), a call to comment_for_reflog() is added at the\nbeginning of this function.\n\nSigned-off-by: Alban Gruin <alban.gruin@gmail.com>\n---\n builtin/rebase--helper.c   | 10 ++++++++--\n git-rebase--interactive.sh | 16 ++--------------\n sequencer.c                | 30 ++++++++++++++++++++++++++++++\n sequencer.h                |  2 ++\n 4 files changed, 42 insertions(+), 16 deletions(-)\n\ndiff --git a/builtin/rebase--helper.c b/builtin/rebase--helper.c\nindex 731a64971..76bdc6fdb 100644\n--- a/builtin/rebase--helper.c\n+++ b/builtin/rebase--helper.c\n@@ -13,12 +13,12 @@ static const char * const builtin_rebase_helper_usage[] = {\n int cmd_rebase__helper(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;\n+\tunsigned flags = 0, keep_empty = 0, rebase_merges = 0, verbose = 0;\n \tint abbreviate_commands = 0, rebase_cousins = -1;\n \tenum {\n \t\tCONTINUE = 1, ABORT, MAKE_SCRIPT, SHORTEN_OIDS, EXPAND_OIDS,\n \t\tCHECK_TODO_LIST, SKIP_UNNECESSARY_PICKS, REARRANGE_SQUASH,\n-\t\tADD_EXEC, APPEND_TODO_HELP, EDIT_TODO\n+\t\tADD_EXEC, APPEND_TODO_HELP, EDIT_TODO, PREPARE_BRANCH\n \t} command = 0;\n \tstruct option options[] = {\n \t\tOPT_BOOL(0, \"ff\", &opts.allow_ff, N_(\"allow fast-forward\")),\n@@ -28,6 +28,7 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\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__VERBOSE(&verbose, N_(\"be verbose\")),\n \t\tOPT_CMDMODE(0, \"continue\", &command, N_(\"continue rebase\"),\n \t\t\t\tCONTINUE),\n \t\tOPT_CMDMODE(0, \"abort\", &command, N_(\"abort rebase\"),\n@@ -51,6 +52,8 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\n \t\tOPT_CMDMODE(0, \"edit-todo\", &command,\n \t\t\t    N_(\"edit the todo list during an interactive rebase\"),\n \t\t\t    EDIT_TODO),\n+\t\tOPT_CMDMODE(0, \"prepare-branch\", &command,\n+\t\t\t    N_(\"prepare the branch to be rebased\"), PREPARE_BRANCH),\n \t\tOPT_END()\n \t};\n \n@@ -60,6 +63,7 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\n \topts.action = REPLAY_INTERACTIVE_REBASE;\n \topts.allow_ff = 1;\n \topts.allow_empty = 1;\n+\topts.verbose = verbose;\n \n \targc = parse_options(argc, argv, NULL, options,\n \t\t\tbuiltin_rebase_helper_usage, PARSE_OPT_KEEP_ARGV0);\n@@ -94,5 +98,7 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\n \t\treturn !!append_todo_help(0, keep_empty);\n \tif (command == EDIT_TODO && argc == 1)\n \t\treturn !!edit_todo_list(flags);\n+\tif (command == PREPARE_BRANCH && argc == 2)\n+\t\treturn !!prepare_branch_to_be_rebased(&opts, argv[1]);\n \tusage_with_options(builtin_rebase_helper_usage, options);\n }\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex 2defe607f..77e972bb6 100644\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -72,6 +72,7 @@ collapse_todo_ids() {\n \n # Switch to the branch in $into and notify it in the reflog\n checkout_onto () {\n+\tcomment_for_reflog start\n \tGIT_REFLOG_ACTION=\"$GIT_REFLOG_ACTION: checkout $onto_name\"\n \toutput git checkout $onto || die_abort \"$(gettext \"could not detach HEAD\")\"\n \tgit update-ref ORIG_HEAD $orig_head\n@@ -119,19 +120,6 @@ initiate_action () {\n \tesac\n }\n \n-setup_reflog_action () {\n-\tcomment_for_reflog start\n-\n-\tif test ! -z \"$switch_to\"\n-\tthen\n-\t\tGIT_REFLOG_ACTION=\"$GIT_REFLOG_ACTION: checkout $switch_to\"\n-\t\toutput git checkout \"$switch_to\" -- ||\n-\t\t\tdie \"$(eval_gettext \"Could not checkout \\$switch_to\")\"\n-\n-\t\tcomment_for_reflog start\n-\tfi\n-}\n-\n init_basic_state () {\n \torig_head=$(git rev-parse --verify HEAD) || die \"$(gettext \"No HEAD?\")\"\n \tmkdir -p \"$state_dir\" || die \"$(eval_gettext \"Could not create temporary \\$state_dir\")\"\n@@ -211,7 +199,7 @@ git_rebase__interactive () {\n \t\treturn 0\n \tfi\n \n-\tsetup_reflog_action\n+\tgit rebase--helper --prepare-branch \"$switch_to\" ${verbose:+--verbose}\n \tinit_basic_state\n \n \tinit_revisions_and_shortrevisions\ndiff --git a/sequencer.c b/sequencer.c\nindex 1b5d50298..b5ea35f21 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -3132,6 +3132,36 @@ 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+{\n+\tstruct child_process cmd = CHILD_PROCESS_INIT;\n+\n+\tcmd.git_cmd = 1;\n+\n+\targv_array_push(&cmd.args, \"checkout\");\n+\targv_array_push(&cmd.args, 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+\telse\n+\t\treturn run_command_silent_on_success(&cmd);\n+}\n+\n+int prepare_branch_to_be_rebased(struct replay_opts *opts, 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\t\treturn error(_(\"could not checkout %s\"), commit);\n+\t}\n+\n+\treturn 0;\n+}\n+\n static const char rescheduled_advice[] =\n N_(\"Could not execute the todo command\\n\"\n \"\\n\"\ndiff --git a/sequencer.h b/sequencer.h\nindex ffab798f1..93da713fe 100644\n--- a/sequencer.h\n+++ b/sequencer.h\n@@ -106,6 +106,8 @@ int update_head_with_reflog(const struct commit *old_head,\n void commit_post_rewrite(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+\n #define SUMMARY_INITIAL_COMMIT   (1 << 0)\n #define SUMMARY_SHOW_AUTHOR_DATE (1 << 1)\n void print_commit_summary(const char *prefix, const struct object_id *oid,\n-- \n2.18.0\n\n"},{"id":"352103","messageId":"2d451b5c-a819-7e44-bdc7-9340b5b55992@gmail.com","threadId":"48814","inReplyTo":"20180710121557.6698-3-alban.gruin@gmail.com","subject":"Re: [GSoC][PATCH v3 02/13] rebase--interactive: rewrite append_todo_help() in C","fromName":"Alban Gruin","fromEmail":"alban.gruin@gmail.com","sentAt":"2018-07-10T12:21:28Z","receivedAt":"2018-07-10T12:21:38Z","isPatch":true,"sender":{"key":"alban.gruin@gmail.com","avatar":"https://avatars.githubusercontent.com/u/6310153?v=4"},"body":"Le 10/07/2018 à 14:15, Alban Gruin a écrit :\n> This rewrites append_todo_help() from shell to C. It also incorporates\n> some parts of initiate_action() and complete_action() that also write\n> help texts to the todo file.\n> \n> This also introduces the source file rebase-interactive.c. This file\n> will contain functions necessary for interactive rebase that are too\n> specific for the sequencer, and is part of libgit.a.\n> \n> Two flags are added to rebase--helper.c: one to call\n> append_todo_help() (`--append-todo-help`), and another one to tell\n> append_todo_help() to write the help text suited for the edit-todo\n> mode (`--write-edit-todo`).\n> \n> Finally, append_todo_help() is removed from git-rebase--interactive.sh\n> to use `rebase--helper --append-todo-help` instead.\n> \n> Signed-off-by: Alban Gruin <alban.gruin@gmail.com>\n> ---\n> Unchanged from what have been queued on `pu` (ag/rebase-i-in-c), and\n> from v2.\n\nSorry, this has actually changed since v2.\n\n"},{"id":"352104","messageId":"fc0ac1cf-4bea-f36a-5891-bb571a056241@gmail.com","threadId":"48814","inReplyTo":"20180710121557.6698-4-alban.gruin@gmail.com","subject":"Re: [GSoC][PATCH v3 03/13] editor: add a function to launch the sequence editor","fromName":"Alban Gruin","fromEmail":"alban.gruin@gmail.com","sentAt":"2018-07-10T12:23:28Z","receivedAt":"2018-07-10T12:23:34Z","isPatch":true,"sender":{"key":"alban.gruin@gmail.com","avatar":"https://avatars.githubusercontent.com/u/6310153?v=4"},"body":"Le 10/07/2018 à 14:15, Alban Gruin a écrit :\n> As part of the rewrite of interactive rebase, the sequencer will need to\n> open the sequence editor to allow the user to edit the todo list.\n> Instead of duplicating the existing launch_editor() function, this\n> refactors it to a new function, launch_specified_editor(), which takes\n> the editor as a parameter, in addition to the path, the buffer and the\n> environment variables.  launch_sequence_editor() is then added to launch\n> the sequence editor.\n> \n> Signed-off-by: Alban Gruin <alban.gruin@gmail.com>\n> ---\n\nAnd this has not changed from what have been queued in pu\n(ag/rebase-i-in-c), and from v2.\n\n"},{"id":"352144","messageId":"xmqq7em37zax.fsf@gitster-ct.c.googlers.com","threadId":"48814","inReplyTo":"20180710121557.6698-2-alban.gruin@gmail.com","subject":"Re: [GSoC][PATCH v3 01/13] sequencer: make two functions and an enum from sequencer.c public","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2018-07-10T17:53:10Z","receivedAt":"2018-07-10T18:18:14Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Alban Gruin <alban.gruin@gmail.com> writes:\n\n> This makes rebase_path_todo(), get_missing_commit_check_level() and the\n> enum check_level accessible outside sequencer.c.  check_level is renamed\n> missing_commit_check_level, and its value names are prefixed by\n> MISSING_COMMIT_ to avoid namespace pollution.\n\nIt is not too big a deal, but we prefer to hear our story told in a\nconsistent voice.  We'd phrase often the above as if giving an order\nto the code base to \"become like so\", i.e.\n\n\tMake X, Y, and Z accessible outside sequencer.c; rename A to\n\tB and prefix its values by doing C to avoid namespace\n\tpollusion.\n\n> This function and this enum will eventually be moved to\n> rebase-interactive.c and become static again, so no special attention\n> was given to the naming.\n>\n> This will be needed for the rewrite of append_todo_help() from shell to\n> C, as it will be in a new library source file, rebase-interactive.c.\n>\n> Signed-off-by: Alban Gruin <alban.gruin@gmail.com>\n> ---\n> Unchanged from v2.\n\nYou added an excuse for being sloppy in the naming to the log\nmessage; the log message is an important and integral part of the\npatch, so please do not label an update like this as unchanged.\n\n\"eventually\" is fine, but that means we cannot split the early parts\nof the topic, once they are polished well enough, into a separate\nbit and have that graduate earlier than the remainder of the topic\nuntil that \"moved and become static again\" happens, which may be a\nbit unfortunate.  Let's make sure we can get to that \"eventually\"\nstep soon.\n\n\n"},{"id":"352145","messageId":"xmqqpnzv6jsn.fsf@gitster-ct.c.googlers.com","threadId":"48814","inReplyTo":"20180710121557.6698-6-alban.gruin@gmail.com","subject":"Re: [GSoC][PATCH v3 05/13] sequencer: add a new function to silence a command, except if it fails","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2018-07-10T18:13:28Z","receivedAt":"2018-07-10T18:19:21Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Alban Gruin <alban.gruin@gmail.com> writes:\n\n> This adds a new function, run_command_silent_on_success(), to\n> redirect the stdout and stderr of a command to a strbuf, and then to run\n> that command. This strbuf is printed only if the command fails. It is\n> functionnaly similar to output() from git-rebase.sh.\n>\n> run_git_commit() is then refactored to use of\n> run_command_silent_on_success().\n>\n> Signed-off-by: Alban Gruin <alban.gruin@gmail.com>\n> ---\n>  sequencer.c | 51 +++++++++++++++++++++++++--------------------------\n>  1 file changed, 25 insertions(+), 26 deletions(-)\n\nLooks good to me; it seems to cover the glitches pointed out in the\nprevious round well.\n"},{"id":"352146","messageId":"xmqqy3ej6khs.fsf@gitster-ct.c.googlers.com","threadId":"48814","inReplyTo":"20180710121557.6698-4-alban.gruin@gmail.com","subject":"Re: [GSoC][PATCH v3 03/13] editor: add a function to launch the sequence editor","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2018-07-10T17:58:23Z","receivedAt":"2018-07-10T18:19:34Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"For those reading from sidelines, this is unchanged from the\nprevious round, and looking good.\n\nAlban Gruin <alban.gruin@gmail.com> writes:\n\n> +const char *git_sequence_editor(void)\n>  {\n> -\tconst char *editor = git_editor();\n> +\tconst char *editor = getenv(\"GIT_SEQUENCE_EDITOR\");\n> +\n> +\tif (!editor)\n> +\t\tgit_config_get_string_const(\"sequence.editor\", &editor);\n> +\tif (!editor)\n> +\t\teditor = git_editor();\n>  \n> +\treturn editor;\n> +}\n> +\n> +static int launch_specified_editor(const char *editor, const char *path,\n> +\t\t\t\t   struct strbuf *buffer, const char *const *env)\n> +{\n>  \tif (!editor)\n>  \t\treturn error(\"Terminal is dumb, but EDITOR unset\");\n\nNice code reuse.\n\n\n"},{"id":"352148","messageId":"xmqqlgaj6jhe.fsf@gitster-ct.c.googlers.com","threadId":"48814","inReplyTo":"20180710121557.6698-7-alban.gruin@gmail.com","subject":"Re: [GSoC][PATCH v3 06/13] rebase -i: rewrite setup_reflog_action() in C","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2018-07-10T18:20:13Z","receivedAt":"2018-07-10T18:20:17Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Alban Gruin <alban.gruin@gmail.com> writes:\n\n> This rewrites (the misnamed) setup_reflog_action() from shell to C. The\n> new version is called prepare_branch_to_be_rebased().\n>\n> A new command is added to rebase--helper.c, “checkout-base”, as well as\n> a new flag, “verbose”, to avoid silencing the output of the checkout\n> operation called by checkout_base_commit().\n>\n> The function `run_git_checkout()` will also be used in the next commit,\n> therefore its code is not part of `checkout_base_commit()`.\n>\n> The shell version is then stripped in favour of a call to the helper.\n>\n> As $GIT_REFLOG_ACTION is no longer set at the first call of\n> checkout_onto(), a call to comment_for_reflog() is added at the\n> beginning of this function.\n>\n> Signed-off-by: Alban Gruin <alban.gruin@gmail.com>\n> ---\n>  builtin/rebase--helper.c   | 10 ++++++++--\n>  git-rebase--interactive.sh | 16 ++--------------\n>  sequencer.c                | 30 ++++++++++++++++++++++++++++++\n>  sequencer.h                |  2 ++\n>  4 files changed, 42 insertions(+), 16 deletions(-)\n>\n> diff --git a/builtin/rebase--helper.c b/builtin/rebase--helper.c\n> index 731a64971..76bdc6fdb 100644\n> --- a/builtin/rebase--helper.c\n> +++ b/builtin/rebase--helper.c\n> @@ -13,12 +13,12 @@ static const char * const builtin_rebase_helper_usage[] = {\n>  int cmd_rebase__helper(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;\n> +\tunsigned flags = 0, keep_empty = 0, rebase_merges = 0, verbose = 0;\n...\n>  \tstruct option options[] = {\n>  \t\tOPT_BOOL(0, \"ff\", &opts.allow_ff, N_(\"allow fast-forward\")),\n> @@ -28,6 +28,7 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\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__VERBOSE(&verbose, N_(\"be verbose\")),\n...\n> @@ -60,6 +63,7 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\n>  \topts.action = REPLAY_INTERACTIVE_REBASE;\n>  \topts.allow_ff = 1;\n>  \topts.allow_empty = 1;\n> +\topts.verbose = verbose;\n>  \n>  \targc = parse_options(argc, argv, NULL, options,\n>  \t\t\tbuiltin_rebase_helper_usage, PARSE_OPT_KEEP_ARGV0);\n> @@ -94,5 +98,7 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\n>  \t\treturn !!append_todo_help(0, keep_empty);\n>  \tif (command == EDIT_TODO && argc == 1)\n>  \t\treturn !!edit_todo_list(flags);\n> +\tif (command == PREPARE_BRANCH && argc == 2)\n> +\t\treturn !!prepare_branch_to_be_rebased(&opts, argv[1]);\n\nNot passing verbose as a separate parameter, and using opts.verbose\nthat already exists instead, is a sensible improvement from the\nprevious round.  I wonder if we need a new local variable, though?\nJust like &opts.allow_ff is used directly in options[] array, can't\nwe give &opts.verbose to OPT__VERBOSE(), or would we break something\nif we did so?\n\n\n"},{"id":"352151","messageId":"xmqqh8l76je4.fsf@gitster-ct.c.googlers.com","threadId":"48814","inReplyTo":"20180710121557.6698-8-alban.gruin@gmail.com","subject":"Re: [GSoC][PATCH v3 07/13] rebase -i: rewrite checkout_onto() in C","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2018-07-10T18:22:11Z","receivedAt":"2018-07-10T18:22:15Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Alban Gruin <alban.gruin@gmail.com> writes:\n\n> This rewrites checkout_onto() from shell to C.\n>\n> A new command (“checkout-onto”) is added to rebase--helper.c. The shell\n> version is then stripped.\n>\n> Signed-off-by: Alban Gruin <alban.gruin@gmail.com>\n> ---\n\nThe only change relative to the previous round seems to be that this\nround does not pass verbose flag as a separate parameter, but reuses\nthe opts.verbose field where \"struct replay_opts\" is being passed\naround.\n\nLooks OK from a quick scan so far.\n"},{"id":"352152","messageId":"xmqq36wr7z4x.fsf@gitster-ct.c.googlers.com","threadId":"48814","inReplyTo":"20180710121557.6698-3-alban.gruin@gmail.com","subject":"Re: [GSoC][PATCH v3 02/13] rebase--interactive: rewrite append_todo_help() in C","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2018-07-10T17:56:46Z","receivedAt":"2018-07-10T18:23:05Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Alban Gruin <alban.gruin@gmail.com> writes:\n\n> This rewrites append_todo_help() from shell to C. It also incorporates\n> some parts of initiate_action() and complete_action() that also write\n> help texts to the todo file.\n>\n> This also introduces the source file rebase-interactive.c. This file\n> will contain functions necessary for interactive rebase that are too\n> specific for the sequencer, and is part of libgit.a.\n>\n> Two flags are added to rebase--helper.c: one to call\n> append_todo_help() (`--append-todo-help`), and another one to tell\n> append_todo_help() to write the help text suited for the edit-todo\n> mode (`--write-edit-todo`).\n>\n> Finally, append_todo_help() is removed from git-rebase--interactive.sh\n> to use `rebase--helper --append-todo-help` instead.\n>\n> Signed-off-by: Alban Gruin <alban.gruin@gmail.com>\n> ---\n> Unchanged from what have been queued on `pu` (ag/rebase-i-in-c), and\n> from v2.\n\nWith something like '...except downcasing an error message \"Could\nnot append...\"', a comment like this is very much appreciated as it\nhelps readers who have read the previous round and remember what was\nin there ;-)\n\n> + ...\n> +\tif (get_missing_commit_check_level() == MISSING_COMMIT_CHECK_ERROR)\n> +\t\tmsg = _(\"\\nDo not remove any line. Use 'drop' \"\n> +\t\t\t \"explicitly to remove a commit.\\n\");\n> +\telse\n> +\t\tmsg = _(\"\\nIf you remove a line here \"\n> +\t\t\t \"THAT COMMIT WILL BE LOST.\\n\");\n> +\n> +\tstrbuf_add_commented_lines(&buf, msg, strlen(msg));\n\nNice use of strbuf_add_comment_lines() function ;-).\n\n"},{"id":"352155","messageId":"xmqq8t6j6im8.fsf@gitster-ct.c.googlers.com","threadId":"48814","inReplyTo":"20180710121557.6698-10-alban.gruin@gmail.com","subject":"Re: [GSoC][PATCH v3 09/13] sequencer: change the way skip_unnecessary_picks() returns its result","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2018-07-10T18:38:55Z","receivedAt":"2018-07-10T18:39:01Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Alban Gruin <alban.gruin@gmail.com> writes:\n\n> @@ -4467,7 +4467,7 @@ int skip_unnecessary_picks(void)\n>  \t}\n>  \n>  \ttodo_list_release(&todo_list);\n> -\tprintf(\"%s\\n\", oid_to_hex(oid));\n> +\t*output_oid = oid_to_hex(oid);\n\nThe return value from oid_to_hex() is volatile and does not survive\nacross multiple calls to it.  If this interface is meant to be long\nlived (as opposed to an intermediate step during the conversion that\nwill soon disappear), it probably makes more sense to have the\ncaller supply an output buffer and call oid_to_hex_r() into it, or\nsomething like that.\n\n> diff --git a/sequencer.h b/sequencer.h\n> index 11a533461..25b50efe2 100644\n> --- a/sequencer.h\n> +++ b/sequencer.h\n> @@ -88,7 +88,7 @@ int sequencer_add_exec_commands(const char *command);\n>  int transform_todos(unsigned flags);\n>  enum missing_commit_check_level get_missing_commit_check_level(void);\n>  int check_todo_list(void);\n> -int skip_unnecessary_picks(void);\n> +int skip_unnecessary_picks(const char **output_oid);\n>  int rearrange_squash(void);\n>  \n>  extern const char sign_off_header[];\n"},{"id":"352161","messageId":"xmqqtvp76kdu.fsf@gitster-ct.c.googlers.com","threadId":"48814","inReplyTo":"20180710121557.6698-5-alban.gruin@gmail.com","subject":"Re: [GSoC][PATCH v3 04/13] rebase-interactive: rewrite the edit-todo functionality in C","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2018-07-10T18:00:45Z","receivedAt":"2018-07-10T18:46:46Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Alban Gruin <alban.gruin@gmail.com> writes:\n\n> This rewrites the edit-todo functionality from shell to C.\n>\n> To achieve that, a new command mode, `edit-todo`, is added, and the\n> `write-edit-todo` flag is removed, as the shell script does not need to\n> write the edit todo help message to the todo list anymore.\n>\n> The shell version is then stripped in favour of a call to the helper.\n>\n> Signed-off-by: Alban Gruin <alban.gruin@gmail.com>\n> ---\n> Unchanged from v2.\n\nA quite straight-forward rewrite.  Looks sensible.\n"},{"id":"352162","messageId":"xmqqd0vv6j0z.fsf@gitster-ct.c.googlers.com","threadId":"48814","inReplyTo":"20180710121557.6698-9-alban.gruin@gmail.com","subject":"Re: [GSoC][PATCH v3 08/13] sequencer: refactor append_todo_help() to write its message to a buffer","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2018-07-10T18:30:04Z","receivedAt":"2018-07-10T18:50:22Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Alban Gruin <alban.gruin@gmail.com> writes:\n\n> diff --git a/rebase-interactive.h b/rebase-interactive.h\n> index 155219e74..c0ba83be3 100644\n> --- a/rebase-interactive.h\n> +++ b/rebase-interactive.h\n> @@ -1,7 +1,12 @@\n>  #ifndef REBASE_INTERACTIVE_H\n>  #define REBASE_INTERACTIVE_H\n>  \n> -int append_todo_help(unsigned edit_todo, unsigned keep_empty);\n> +#include <cache.h>\n> +#include <strbuf.h>\n\nEven though arguments can be made that using angle-bracket to refer\nto our own headers like the above is more kosher, such a clean-up is\nnot part of the GSoC topic, so let's refrain from doing a little\ncrusade like this and imitate the way the other existing files\ninclude things.\n\nActually, unless there is a definition of the structure that you\nrequire in your header file to define your own structure, we are\nbetter off not including another header from your own header.\n\nWhoever includes \"rebase-interactive.h\", if it needs to know what\nstrbuf looks like in order to call append_todo_help(), should\ninclude \"strbuf.h\" itself.  Those who only need to call\nappend_todo_help_to_file or edit_todo_list hence do not need to know\nabout strbuf, if such a caller existed, should not be forced to\ninclude \"strbuf.h\".\n\n> +\n> +void append_todo_help(unsigned edit_todo, unsigned keep_empty,\n> +\t\t      struct strbuf *buf);\n> +int append_todo_help_to_file(unsigned edit_todo, unsigned keep_empty);\n>  int edit_todo_list(unsigned flags);\n>  \n>  #endif\n"},{"id":"352163","messageId":"xmqq4lh67wkn.fsf@gitster-ct.c.googlers.com","threadId":"48814","inReplyTo":"20180710121557.6698-10-alban.gruin@gmail.com","subject":"Re: [GSoC][PATCH v3 09/13] sequencer: change the way skip_unnecessary_picks() returns its result","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2018-07-10T18:52:08Z","receivedAt":"2018-07-10T18:52:13Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Alban Gruin <alban.gruin@gmail.com> writes:\n\n> -\tif (command == SKIP_UNNECESSARY_PICKS && argc == 1)\n> -\t\treturn !!skip_unnecessary_picks();\n> +\tif (command == SKIP_UNNECESSARY_PICKS && argc == 1) {\n> +\t\tret = !!skip_unnecessary_picks(&oid);\n> +\t\tif (!ret && oid)\n> +\t\t\tputs(oid);\n\nThink why you wrote !! there; in other words, avoid getting into a\nhabit of blindly copying and pasting existing code without thinking.\n\nThe original is synthesizing an integer value that is to be used as\nthe final exit status from a process, which has to be a non negative\ninteger, out of a helper function, whose error return may be\nnagative [*1*], and it knows that the caller cares only about one\nbit \"did we or did we not have an error?\", so it turns any non-zero\nreturn value into 1.  That is why it uses !!.\n\n\tSide note *1* The normal convention for helper functions is\n        to signal an error with negative return value, and success\n        with 0.  There may be different negative values used to\n        signal different error conditions to the caller, depending\n        on how well the API is designed.\n\nBut realize that !! is an operation that loses information, so in\ngeneral you would want to delay its application til when you need\nit.  In this particular case, you do not care what kind of error\nyou got (or you didn't), so you can just say\n\n\tret = skip_unnecessary_picks(&oid);\n\tif (!ret && oid)\n\t\tputs(oid); /* happy */\n\nwithout applying !! before receiving the return value from the\nhelper in \"ret\".\n\n> +\t\treturn ret;\n\nAnd ensure that you return only 0 or 1 by applying !! here instead.\n\n> diff --git a/sequencer.c b/sequencer.c\n> index 2b6ddc6cf..676ac1320 100644\n> --- a/sequencer.c\n> +++ b/sequencer.c\n> @@ -4392,7 +4392,7 @@ static int rewrite_file(const char *path, const char *buf, size_t len)\n>  }\n>  \n>  /* skip picking commits whose parents are unchanged */\n> -int skip_unnecessary_picks(void)\n> +int skip_unnecessary_picks(const char **output_oid)\n>  {\n>  \tconst char *todo_file = rebase_path_todo();\n>  \tstruct strbuf buf = STRBUF_INIT;\n> @@ -4467,7 +4467,7 @@ int skip_unnecessary_picks(void)\n>  \t}\n>  \n>  \ttodo_list_release(&todo_list);\n> -\tprintf(\"%s\\n\", oid_to_hex(oid));\n> +\t*output_oid = oid_to_hex(oid);\n\nThe return value of oid_to_hex() is not meant to be long-lived.\nConsider writing into caller supplied buffer with oid_to_hex_r()\nor something like that.\n"},{"id":"352189","messageId":"xmqq4lh667qw.fsf@gitster-ct.c.googlers.com","threadId":"48814","inReplyTo":"20180710121557.6698-11-alban.gruin@gmail.com","subject":"Re: [GSoC][PATCH v3 10/13] rebase--interactive: rewrite complete_action() in C","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2018-07-10T22:33:43Z","receivedAt":"2018-07-10T22:33:49Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Alban Gruin <alban.gruin@gmail.com> writes:\n\n> This rewrites complete_action() from shell to C.\n>\n> A new mode is added to rebase--helper (`--complete-action`), as well as\n> a new flag (`--autosquash`).\n>\n> Finally, complete_action() is stripped from git-rebase--interactive.sh.\n>\n> The original complete_action() checked twice that the todo-list had at\n> least one operations (the first check took place after the help message\n> was inserted, the second after the user edited the todo-list).  If there\n> are no actions, complete_action() would return with the code 2.  This is\n> a special case for rebase -i and -p; git-rebase.sh would then apply the\n> autostash, delete the state directory, and die with the message \"nothing\n> to do\".  This rewrite remove the first check (because a noop is added to\n> the todo-list if it is empty).  For the second case, the cleanup is\n> rewritten in C instead of returning 2.\n\nThe description about the first check seems unclear here.  Is it\n\"there was a first check but because the list is never empty due to\na noop, the check was unneeded\"?  or is it \"I decided to add noop to\nforce the list to be never empty, and that made the first check\nunneeded\"?  I'd imagine that the end-user experience would become\ndifferent if it were the latter (we'd see a todo whose sole entry is\nno-op in the editor, instead of getting an error before editor\nopens), and such a change would require a separate justification.\n\n> -complete_action() {\n> -\ttest -s \"$todo\" || echo noop >> \"$todo\"\n> -...\n> -\n> -\thas_action \"$todo\" ||\n> -\t\treturn 2\n\nIt seems that the answer to my question turns out to be #1 after\nsome digging, i.e. the original, when it starteed adding noop at\nff74126c (\"rebase -i: do not fail when there is no commit to\ncherry-pick\", 2008-10-10), should have noticed that the first\n\"Nothing to do\" check has now become ineffective and removed it, and\nyou are fixing this age-old bug while rewriting it to C.\n\nBut you shouldn't force reviewers to figure that out.\n\n\tSide note.  This age-old omission is especially interesting,\n\tas the primary point of that change, which can be read from\n\tits title, was to prevent the command from dying that way.\n\tI wonder why reviewers did not notice it back then.\n\n        ... ah, it seems that it was done during my absense ;-)\n\n> -\tcomplete_action\n> +\texec git rebase--helper --complete-action \"$shortrevisions\" \"$onto_name\" \\\n> +\t\t\"$shortonto\" \"$orig_head\" \"$cmd\" $allow_empty_message \\\n> +\t\t${autosquash:+--autosquash} ${keep_empty:+--keep-empty} \\\n> +\t\t${verbose:+--verbose} ${force_rebase:+--no-ff}\n\nThe $allow_empty_message and later options are all dashed ones.\ngit-rebase.sh gives us either empty or --allow-empty-message in the\nvariable for $allow_empty_message, and if you follow suit to prepare\nall the other variables that way, the ugly ${frotz+=--frotz} dance\nwill all become unnecessary here.\n\n> +int complete_action(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, const char *cmd,\n> +\t\t    unsigned autosquash, unsigned keep_empty)\n> +{\n> +\tconst char *shortonto, *todo_file = rebase_path_todo();\n> +\tstruct todo_list todo_list = TODO_LIST_INIT;\n> +\tstruct strbuf *buf = &(todo_list.buf);\n> +\tstruct object_id oid;\n> +\tstruct stat st;\n> +\n> +\tget_oid(onto, &oid);\n> +\tshortonto = find_unique_abbrev(&oid, DEFAULT_ABBREV);\n> +\n> +\tif (!lstat(todo_file, &st) && st.st_size == 0 &&\n> +\t    write_message(\"noop\\n\", 5, todo_file, 0))\n> +\t\treturn error_errno(_(\"could not write '%s'\"), todo_file);\n\nWait a minute... thinking back to the early \"age-old ommission\"\ntopic, can the todo file be a non-empty file that does not have any\ncommand (e.g. just a single blank line, or full of comments and\nnothing else)?  The original wouldn't have added \"noop\" and then the\nfirst \"do we have anything to do?\" check would still have been\nnecessary, which would mean that ff74126c's not removing the first\ncheck was actually not a bug but was a cautious and sensible thing\nto do, and removal of that exact check by this commit becomes a\nregression.  So,... can the todo file be a non-empty file that does\nnot have any command in it at this point?\n\n> +\tif (autosquash && rearrange_squash())\n> +\t\treturn 0;\n\nThe original, when rearrange-squash failed, exited with failure,\nlike so:\n\n-       test -z \"$autosquash\" || git rebase--helper --rearrange-squash || exit\n\nNow this function returns success when rearrange_squash fails.  \nIs that intended?\n\n> +\tif (cmd && *cmd)\n\nShouldn't it be a BUG (programming error) if cmd == NULL?  I thought\nthe caller of complete_action() in this patch insisted that it got\nargc == 6 or something, so *cmd might be NUL but cmd would never be\nNULL if I understand your code correctly.  IOW, shouldn't the line\nbe more like:\n\n\tif (!cmd)\n\t\tBUG(\"...\");\n\tif (*cmd)\n\n?\n\n> +\t\tsequencer_add_exec_commands(cmd);\n\nThe sequencer_add_exec_commands() function does not take the name of\ntodo file as a parameter, so even though we have one in todo_file\nvariable we cannot use it to call the function, which is a bit sad,\nbut is OK.\n\n> +\tif (strbuf_read_file(buf, todo_file, 0) < 0)\n> +\t\treturn error_errno(_(\"could not read '%s'.\"), todo_file);\n> +\tif (parse_insn_buffer(buf->buf, &todo_list)) {\n\nNice that we have parse* function.  We do not have to work with\nstripspace plus \"wc -l\" ;-).\n\n> +\t\ttodo_list_release(&todo_list);\n> +\t\treturn error(_(\"unusable todo list: '%s'\"), todo_file);\n\nWhen the users see this error message, is it easy for them to\ndiagnose what went wrong (e.g. has parse_insn_buffer() already\nissued some message to help pinpoint which insn in the todo list is\nmisspelt, for example)?\n\n> +\t}\n> +\n> +\tstrbuf_addch(buf, '\\n');\n> +\tstrbuf_commented_addf(buf, Q_(\"Rebase %s onto %s (%d command)\",\n> +\t\t\t\t      \"Rebase %s onto %s (%d commands)\",\n> +\t\t\t\t      todo_list.nr),\n> +\t\t\t      shortrevisions, shortonto, todo_list.nr);\n> +\tappend_todo_help(0, keep_empty, buf);\n> +\n> +\tif (write_message(buf->buf, buf->len, todo_file, 0)) {\n> +\t\ttodo_list_release(&todo_list);\n> +\t\treturn error_errno(_(\"could not write '%s'\"), todo_file);\n> +\t}\n> +\tcopy_file(rebase_path_todo_backup(), todo_file, 0666);\n> +\ttransform_todos(flags | TODO_LIST_SHORTEN_IDS);\n> +\n\nIt is a bit sad that we are mostly working on the byte array\nbuf->buf (or external file touched by various helper functions we\ncall), even though we have a perfectly usable parsed representation\nin todo_list structure in all of the above and the rest of this\nfunction.\n\nIt might be better to grab todo_list.nr into a local simple integer\nvariable immediately after parse_insn_buffer() returns and then call\ntodo_list_release() on todo_list, as the parsed todo-list is only\nused for two purposes (i.e. detecting format error by seeing if\nparser returns success, and seeing how many insns are on the todo\nlist by checking todo_list.nr field) and nothing else.  By releasing\nthe otherwise unused todo_list early, you do not have to sprinkle\nvarious error return codepaths with calls to todo_list_release().\n\nThat incidentally would manage too high expectation from readers of\nthe code as well ;-).\n\n>  struct subject2item_entry {\n>  \tstruct hashmap_entry entry;\n>  \tint i;\n> diff --git a/sequencer.h b/sequencer.h\n> index 25b50efe2..02772b927 100644\n> --- a/sequencer.h\n> +++ b/sequencer.h\n> @@ -89,6 +89,10 @@ int transform_todos(unsigned flags);\n>  enum missing_commit_check_level get_missing_commit_check_level(void);\n>  int check_todo_list(void);\n>  int skip_unnecessary_picks(const char **output_oid);\n> +int complete_action(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, const char *cmd,\n> +\t\t    unsigned autosquash, unsigned keep_empty);\n>  int rearrange_squash(void);\n>  \n>  extern const char sign_off_header[];\n"},{"id":"352190","messageId":"xmqqzhyy4t2f.fsf@gitster-ct.c.googlers.com","threadId":"48814","inReplyTo":"20180710121557.6698-12-alban.gruin@gmail.com","subject":"Re: [GSoC][PATCH v3 11/13] rebase--interactive: remove unused modes and functions","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2018-07-10T22:36:08Z","receivedAt":"2018-07-10T22:36:13Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Alban Gruin <alban.gruin@gmail.com> writes:\n\n> This removes the modes `--skip-unnecessary-picks`, `--append-todo-help`,\n> `--checkout-onto`, `--shorten-ids` and `--expand-ids` from\n> rebase--helper.c, the functions of git-rebase--interactive.sh that were\n> rendered useless by the rewrite of complete_action(), and\n> append_todo_help_to_file() from rebase-interactive.c.\n\nGood.  So far up to this step, I thnk the organization of the series\nlooks good, even if the execution in each individual step we have\nseen previously may still need to be improved.\n\n"},{"id":"352246","messageId":"c7c20d70-3ad0-4298-66fd-a10e5bb4a91d@gmail.com","threadId":"48814","inReplyTo":"xmqq4lh667qw.fsf@gitster-ct.c.googlers.com","subject":"Re: [GSoC][PATCH v3 10/13] rebase--interactive: rewrite complete_action() in C","fromName":"Alban Gruin","fromEmail":"alban.gruin@gmail.com","sentAt":"2018-07-11T14:25:52Z","receivedAt":"2018-07-11T14:26:02Z","isPatch":true,"sender":{"key":"alban.gruin@gmail.com","avatar":"https://avatars.githubusercontent.com/u/6310153?v=4"},"body":"Hi Junio,\n\nLe 11/07/2018 à 00:33, Junio C Hamano a écrit :\n> Alban Gruin <alban.gruin@gmail.com> writes:\n>> -\tcomplete_action\n>> +\texec git rebase--helper --complete-action \"$shortrevisions\" \"$onto_name\" \\\n>> +\t\t\"$shortonto\" \"$orig_head\" \"$cmd\" $allow_empty_message \\\n>> +\t\t${autosquash:+--autosquash} ${keep_empty:+--keep-empty} \\\n>> +\t\t${verbose:+--verbose} ${force_rebase:+--no-ff}\n> \n> The $allow_empty_message and later options are all dashed ones.\n> git-rebase.sh gives us either empty or --allow-empty-message in the\n> variable for $allow_empty_message, and if you follow suit to prepare\n> all the other variables that way, the ugly ${frotz+=--frotz} dance\n> will all become unnecessary here.\n> \n\nGood idea.\n\n>> +int complete_action(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, const char *cmd,\n>> +\t\t    unsigned autosquash, unsigned keep_empty)\n>> +{\n>> +\tconst char *shortonto, *todo_file = rebase_path_todo();\n>> +\tstruct todo_list todo_list = TODO_LIST_INIT;\n>> +\tstruct strbuf *buf = &(todo_list.buf);\n>> +\tstruct object_id oid;\n>> +\tstruct stat st;\n>> +\n>> +\tget_oid(onto, &oid);\n>> +\tshortonto = find_unique_abbrev(&oid, DEFAULT_ABBREV);\n>> +\n>> +\tif (!lstat(todo_file, &st) && st.st_size == 0 &&\n>> +\t    write_message(\"noop\\n\", 5, todo_file, 0))\n>> +\t\treturn error_errno(_(\"could not write '%s'\"), todo_file);\n> \n> Wait a minute... thinking back to the early \"age-old ommission\"\n> topic, can the todo file be a non-empty file that does not have any\n> command (e.g. just a single blank line, or full of comments and\n> nothing else)?  The original wouldn't have added \"noop\" and then the\n> first \"do we have anything to do?\" check would still have been\n> necessary, which would mean that ff74126c's not removing the first\n> check was actually not a bug but was a cautious and sensible thing\n> to do, and removal of that exact check by this commit becomes a\n> regression.  So,... can the todo file be a non-empty file that does\n> not have any command in it at this point?\n> \n\nHum, yes, if the commits are empty, and if rebase was invoked without\nthe `--keep-empty` flag.  In this case, it would die with the message\n“Nothing to do”, instead of dropping the commit altogether.\n\nI will add a test case in the next iteration.\n\n>> +\tif (autosquash && rearrange_squash())\n>> +\t\treturn 0;\n> \n> The original, when rearrange-squash failed, exited with failure,\n> like so:\n> \n> -       test -z \"$autosquash\" || git rebase--helper --rearrange-squash || exit\n> \n> Now this function returns success when rearrange_squash fails.  \n> Is that intended?\n> \n\nYes, it is.  I just saw in the man page that `exit` returns the last\nexit status.\n\n>> +\tif (cmd && *cmd)\n> \n> Shouldn't it be a BUG (programming error) if cmd == NULL?  I thought\n> the caller of complete_action() in this patch insisted that it got\n> argc == 6 or something, so *cmd might be NUL but cmd would never be\n> NULL if I understand your code correctly.  IOW, shouldn't the line\n> be more like:\n> \n> \tif (!cmd)\n> \t\tBUG(\"...\");\n> \tif (*cmd)\n> \n> ?\n> \n\nI don’t know, it’s not really problematic if cmd is NULL.  And I think\nthat when interactive rebase will be a builtin, it will be possible for\ncmd to be NULL.\n\n> \n>> +\tif (strbuf_read_file(buf, todo_file, 0) < 0)\n>> +\t\treturn error_errno(_(\"could not read '%s'.\"), todo_file);\n>> +\tif (parse_insn_buffer(buf->buf, &todo_list)) {\n> \n> Nice that we have parse* function.  We do not have to work with\n> stripspace plus \"wc -l\" ;-).\n> \n>> +\t\ttodo_list_release(&todo_list);\n>> +\t\treturn error(_(\"unusable todo list: '%s'\"), todo_file);\n> \n> When the users see this error message, is it easy for them to\n> diagnose what went wrong (e.g. has parse_insn_buffer() already\n> issued some message to help pinpoint which insn in the todo list is\n> misspelt, for example)?\n> \n\nYes, parse_insn_buffer() will say which line caused the error.  But at\nthis point, the user should not have changed the todo-list, so this\nerror should never appear.\n\nPerhaps this is a good use case of BUG()?\n\n>> +\t}\n>> +\n>> +\tstrbuf_addch(buf, '\\n');\n>> +\tstrbuf_commented_addf(buf, Q_(\"Rebase %s onto %s (%d command)\",\n>> +\t\t\t\t      \"Rebase %s onto %s (%d commands)\",\n>> +\t\t\t\t      todo_list.nr),\n>> +\t\t\t      shortrevisions, shortonto, todo_list.nr);\n>> +\tappend_todo_help(0, keep_empty, buf);\n>> +\n>> +\tif (write_message(buf->buf, buf->len, todo_file, 0)) {\n>> +\t\ttodo_list_release(&todo_list);\n>> +\t\treturn error_errno(_(\"could not write '%s'\"), todo_file);\n>> +\t}\n>> +\tcopy_file(rebase_path_todo_backup(), todo_file, 0666);\n>> +\ttransform_todos(flags | TODO_LIST_SHORTEN_IDS);\n>> +\n> \n> It is a bit sad that we are mostly working on the byte array\n> buf->buf (or external file touched by various helper functions we\n> call), even though we have a perfectly usable parsed representation\n> in todo_list structure in all of the above and the rest of this\n> function.\n> \n> It might be better to grab todo_list.nr into a local simple integer\n> variable immediately after parse_insn_buffer() returns and then call\n> todo_list_release() on todo_list, as the parsed todo-list is only\n> used for two purposes (i.e. detecting format error by seeing if\n> parser returns success, and seeing how many insns are on the todo\n> list by checking todo_list.nr field) and nothing else.  By releasing\n> the otherwise unused todo_list early, you do not have to sprinkle\n> various error return codepaths with calls to todo_list_release().\n> \n> That incidentally would manage too high expectation from readers of\n> the code as well ;-).\n> \n\nUnfortunately, this strbuf is part of the todo_list, and it will be\nfreed if I call todo_list_release().\n\n:/\n\nCheers,\nAlban\n\n"},{"id":"352377","messageId":"xmqqo9fcxquk.fsf@gitster-ct.c.googlers.com","threadId":"48814","inReplyTo":"20180710121557.6698-13-alban.gruin@gmail.com","subject":"Re: [GSoC][PATCH v3 12/13] rebase -i: implement the logic to initialize the variable $revision in C","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2018-07-12T18:15:47Z","receivedAt":"2018-07-12T18:15:53Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Alban Gruin <alban.gruin@gmail.com> writes:\n\n> @@ -50,6 +71,13 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\n>  \t\t\t    N_(\"prepare the branch to be rebased\"), PREPARE_BRANCH),\n>  \t\tOPT_CMDMODE(0, \"complete-action\", &command,\n>  \t\t\t    N_(\"complete the action\"), COMPLETE_ACTION),\n> +\t\tOPT_STRING(0, \"onto\", &onto, N_(\"onto\"), N_(\"onto\")),\n> +\t\tOPT_STRING(0, \"restrict-revision\", &restrict_revisions,\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_END()\n>  \t};\n>  \n> @@ -77,8 +105,30 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\n>  \t\treturn !!sequencer_continue(&opts);\n>  \tif (command == ABORT && argc == 1)\n>  \t\treturn !!sequencer_remove_state(&opts);\n> -\tif (command == MAKE_SCRIPT && argc > 1)\n> -\t\treturn !!sequencer_make_script(stdout, argc, argv, flags);\n> +\tif (command == MAKE_SCRIPT && (argc == 1 || argc == 2)) {\n\nSorry but I am confused.  The call to rebase--helper --make-script\nin git-rebase--interactive.sh we see below has only dashed options\n(like --upstream, --onto, --squash-onto, --restrict-revision) and\nthe option parameters given to these options.\n\nWhat are the remaining 1 or 2 arguments we are processing here?\n\nWell, actually argc==1 means there is nothing else, so I am asking\nabout the case where argc==2.\n\n> +\t\tchar *revisions = NULL;\n> +\t\tstruct argv_array make_script_args = ARGV_ARRAY_INIT;\n> +\n> +\t\tif (!upstream && squash_onto)\n> +\t\t\twrite_file(path_squash_onto(), \"%s\\n\", squash_onto);\n> +\n> +\t\tret = get_revision_ranges(upstream, onto, &head_hash, &revisions);\n> +\t\tif (ret)\n> +\t\t\treturn ret;\n> +\n> +\t\targv_array_pushl(&make_script_args, \"\", revisions, NULL);\n> +\t\tif (argc == 2)\n> +\t\t\targv_array_push(&make_script_args, restrict_revisions);\n> +\n> +\t\tret = !!sequencer_make_script(stdout,\n> +\t\t\t\t\t      make_script_args.argc, make_script_args.argv,\n> +\t\t\t\t\t      flags);\n\nExactly the same comment on !! as an earlier step applies here.\n\n> +\t\tfree(revisions);\n> +\t\targv_array_clear(&make_script_args);\n\nIf I am reading the body of this if() block correctly, I think it\ndoes everything init_revisions_and_shortrevisions shell function\ndoes, i.e. compute $revisions for both cases with or without\nupstream and write squash-onto state if needed, so that we can call\nthe sequencer_make_script() helper with necessary $revisions arg\nwithout being passed from the command line of --make-script helper.\n\nBut the hunk below tells me that you are still calling\ninit_revisions_and_shortrevisions shell function before we are\ncalled.  Why?  IOW, why isn't this step removing that shell function\n*and* the call to it, now its logic is fully implemented in the body\nof this if() block?\n\n> +\t\treturn ret;\n> +\t}\n>  \tif (command == CHECK_TODO_LIST && argc == 1)\n>  \t\treturn !!check_todo_list();\n>  \tif (command == REARRANGE_SQUASH && argc == 1)\n\nThanks.\n\n> diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\n> index 0d66c0f8b..4ca47aed1 100644\n> --- a/git-rebase--interactive.sh\n> +++ b/git-rebase--interactive.sh\n> @@ -92,7 +92,9 @@ git_rebase__interactive () {\n>  \tgit rebase--helper --make-script ${keep_empty:+--keep-empty} \\\n>  \t\t${rebase_merges:+--rebase-merges} \\\n>  \t\t${rebase_cousins:+--rebase-cousins} \\\n> -\t\t$revisions ${restrict_revision+^$restrict_revision} >\"$todo\" ||\n> +\t\t${upstream:+--upstream \"$upstream\"} ${onto:+--onto \"$onto\"} \\\n> +\t\t${squash_onto:+--squash-onto \"$squash_onto\"} \\\n> +\t\t${restrict_revision:+--restrict-revision ^\"$restrict_revision\"} >\"$todo\" ||\n>  \tdie \"$(gettext \"Could not generate todo list\")\"\n>  \n>  \texec git rebase--helper --complete-action \"$shortrevisions\" \"$onto_name\" \\\n"},{"id":"352379","messageId":"xmqqk1q0xqfj.fsf@gitster-ct.c.googlers.com","threadId":"48814","inReplyTo":"xmqqo9fcxquk.fsf@gitster-ct.c.googlers.com","subject":"Re: [GSoC][PATCH v3 12/13] rebase -i: implement the logic to initialize the variable $revision in C","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2018-07-12T18:24:48Z","receivedAt":"2018-07-12T18:24:52Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Junio C Hamano <gitster@pobox.com> writes:\n\n> If I am reading the body of this if() block correctly, I think it\n> does everything init_revisions_and_shortrevisions shell function\n> does, i.e. compute $revisions for both cases with or without\n> upstream and write squash-onto state if needed, so that we can call\n> the sequencer_make_script() helper with necessary $revisions arg\n> without being passed from the command line of --make-script helper.\n>\n> But the hunk below tells me that you are still calling\n> init_revisions_and_shortrevisions shell function before we are\n> called.  Why?  IOW, why isn't this step removing that shell function\n> *and* the call to it, now its logic is fully implemented in the body\n> of this if() block?\n\nYou can ignore this part (but not the rest) of my comments, as 13/13\nanswers it adequately.  After this step, the shell function still\nneeds to be called to set $shortrevisions.\n\nThanks.\n"},{"id":"353470","messageId":"20180724163221.15201-1-alban.gruin@gmail.com","threadId":"48814","inReplyTo":"20180710121557.6698-1-alban.gruin@gmail.com","subject":"[GSoC][PATCH v4 00/20] rebase -i: rewrite in C","fromName":"Alban Gruin","fromEmail":"alban.gruin@gmail.com","sentAt":"2018-07-24T16:32:01Z","receivedAt":"2018-07-24T16:34:13Z","isPatch":true,"sender":{"key":"alban.gruin@gmail.com","avatar":"https://avatars.githubusercontent.com/u/6310153?v=4"},"body":"This patch series rewrite the interactive rebase from shell to C.\n\nIt is based on master (as of 2018-07-24).\n\nChanges since v3:\n\n - The `--verbose` option is stored directly into opts.verbose\n\n - Drop includes in rebase-interactive.h\n\n - skip_unnecessary_picks() now returns an object_id instead of a string\n\n - Add a test case to ensure interactive rebase aborts when the todo\n   list only has commented-out commands\n\n - complete_action() aborts when the todo list only has commented-out\n   commands\n\n - Drop the `keep_empty` parameter of complete_action()\n\n - Don’t remove the modes `--shorten-oids` and `--expand-oids` from\n   git-rebase--helper\n\n - Replace `ret = !!x(); return ret` by `ret = x(); return !!ret`\n\n - Fail if `--make-script` is provided with two arguments instead of\n   one\n\n - Rewrite write_basic_state() and init_basic_state() in C\n\n - Rewrite git-rebase--interactive.sh as a builtin\n\nAlban Gruin (20):\n  sequencer: make two functions and an enum from sequencer.c public\n  rebase -i: rewrite append_todo_help() in C\n  editor: add a function to launch the sequence editor\n  rebase -i: rewrite the edit-todo functionality in C\n  sequencer: add a new function to silence a command, except if it fails\n  rebase -i: rewrite setup_reflog_action() in C\n  rebase -i: rewrite checkout_onto() in C\n  sequencer: refactor append_todo_help() to write its message to a\n    buffer\n  sequencer: change the way skip_unnecessary_picks() returns its result\n  t3404: todo list with commented-out commands only aborts\n  rebase -i: rewrite complete_action() in C\n  rebase -i: remove unused modes and functions\n  rebase -i: implement the logic to initialize $revisions in C\n  rebase -i: rewrite the rest of init_revisions_and_shortrevisions() in\n    C\n  rebase -i: rewrite write_basic_state() in C\n  rebase -i: rewrite init_basic_state() in C\n  rebase -i: implement the main part of interactive rebase as a builtin\n  rebase--interactive2: rewrite the submodes of interactive rebase in C\n  rebase -i: remove git-rebase--interactive.sh\n  rebase -i: move rebase--helper modes to rebase--interactive\n\n .gitignore                     |   1 -\n Makefile                       |   5 +-\n builtin.h                      |   1 +\n builtin/rebase--helper.c       |  88 ----------\n builtin/rebase--interactive.c  | 264 ++++++++++++++++++++++++++++\n cache.h                        |   1 +\n editor.c                       |  27 ++-\n git-rebase--interactive.sh     | 283 ------------------------------\n git-rebase--preserve-merges.sh |  10 +-\n git-rebase.sh                  |  47 ++++-\n git.c                          |   2 +-\n rebase-interactive.c           |  96 ++++++++++\n rebase-interactive.h           |   8 +\n sequencer.c                    | 311 +++++++++++++++++++++++++++------\n sequencer.h                    |  19 +-\n strbuf.h                       |   2 +\n t/t3404-rebase-interactive.sh  |  10 ++\n 17 files changed, 729 insertions(+), 446 deletions(-)\n delete mode 100644 builtin/rebase--helper.c\n create mode 100644 builtin/rebase--interactive.c\n delete mode 100644 git-rebase--interactive.sh\n create mode 100644 rebase-interactive.c\n create mode 100644 rebase-interactive.h\n\n-- \n2.18.0\n\n"},{"id":"353471","messageId":"20180724163221.15201-2-alban.gruin@gmail.com","threadId":"48814","inReplyTo":"20180724163221.15201-1-alban.gruin@gmail.com","subject":"[GSoC][PATCH v4 01/20] sequencer: make two functions and an enum from sequencer.c public","fromName":"Alban Gruin","fromEmail":"alban.gruin@gmail.com","sentAt":"2018-07-24T16:32:02Z","receivedAt":"2018-07-24T16:34:15Z","isPatch":true,"sender":{"key":"alban.gruin@gmail.com","avatar":"https://avatars.githubusercontent.com/u/6310153?v=4"},"body":"This makes rebase_path_todo(), get_missing_commit_check_level() and the\nenum check_level accessible outside sequencer.c, renames check_level to\nmissing_commit_check_level, and prefixes its value names by\nMISSING_COMMIT_ to avoid namespace pollution.\n\nThis function and this enum will eventually be moved to\nrebase-interactive.c and become static again, so no special attention\nwas given to the naming.\n\nThis will be needed for the rewrite of append_todo_help() from shell to\nC, as it will be in a new library source file, rebase-interactive.c.\n\nSigned-off-by: Alban Gruin <alban.gruin@gmail.com>\n---\nNo code changes since v3.\n\n sequencer.c | 22 +++++++++-------------\n sequencer.h |  8 ++++++++\n 2 files changed, 17 insertions(+), 13 deletions(-)\n\ndiff --git a/sequencer.c b/sequencer.c\nindex 03c47405fb..0fc03dfe48 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -52,7 +52,7 @@ static GIT_PATH_FUNC(rebase_path, \"rebase-merge\")\n  * the lines are processed, they are removed from the front of this\n  * file and written to the tail of 'done'.\n  */\n-static GIT_PATH_FUNC(rebase_path_todo, \"rebase-merge/git-rebase-todo\")\n+GIT_PATH_FUNC(rebase_path_todo, \"rebase-merge/git-rebase-todo\")\n /*\n  * The rebase command lines that have already been processed. A line\n  * is moved here when it is first handled, before any associated user\n@@ -4245,24 +4245,20 @@ int transform_todos(unsigned flags)\n \treturn i;\n }\n \n-enum check_level {\n-\tCHECK_IGNORE = 0, CHECK_WARN, CHECK_ERROR\n-};\n-\n-static enum check_level get_missing_commit_check_level(void)\n+enum missing_commit_check_level get_missing_commit_check_level(void)\n {\n \tconst char *value;\n \n \tif (git_config_get_value(\"rebase.missingcommitscheck\", &value) ||\n \t\t\t!strcasecmp(\"ignore\", value))\n-\t\treturn CHECK_IGNORE;\n+\t\treturn MISSING_COMMIT_CHECK_IGNORE;\n \tif (!strcasecmp(\"warn\", value))\n-\t\treturn CHECK_WARN;\n+\t\treturn MISSING_COMMIT_CHECK_WARN;\n \tif (!strcasecmp(\"error\", value))\n-\t\treturn CHECK_ERROR;\n+\t\treturn MISSING_COMMIT_CHECK_ERROR;\n \twarning(_(\"unrecognized setting %s for option \"\n \t\t  \"rebase.missingCommitsCheck. Ignoring.\"), value);\n-\treturn CHECK_IGNORE;\n+\treturn MISSING_COMMIT_CHECK_IGNORE;\n }\n \n define_commit_slab(commit_seen, unsigned char);\n@@ -4274,7 +4270,7 @@ define_commit_slab(commit_seen, unsigned char);\n  */\n int check_todo_list(void)\n {\n-\tenum check_level check_level = get_missing_commit_check_level();\n+\tenum missing_commit_check_level check_level = get_missing_commit_check_level();\n \tstruct strbuf todo_file = STRBUF_INIT;\n \tstruct todo_list todo_list = TODO_LIST_INIT;\n \tstruct strbuf missing = STRBUF_INIT;\n@@ -4291,7 +4287,7 @@ int check_todo_list(void)\n \tadvise_to_edit_todo = res =\n \t\tparse_insn_buffer(todo_list.buf.buf, &todo_list);\n \n-\tif (res || check_level == CHECK_IGNORE)\n+\tif (res || check_level == MISSING_COMMIT_CHECK_IGNORE)\n \t\tgoto leave_check;\n \n \t/* Mark the commits in git-rebase-todo as seen */\n@@ -4326,7 +4322,7 @@ int check_todo_list(void)\n \tif (!missing.len)\n \t\tgoto leave_check;\n \n-\tif (check_level == CHECK_ERROR)\n+\tif (check_level == MISSING_COMMIT_CHECK_ERROR)\n \t\tadvise_to_edit_todo = res = 1;\n \n \tfprintf(stderr,\ndiff --git a/sequencer.h b/sequencer.h\nindex c5787c6b56..ffab798f1e 100644\n--- a/sequencer.h\n+++ b/sequencer.h\n@@ -3,6 +3,7 @@\n \n const char *git_path_commit_editmsg(void);\n const char *git_path_seq_dir(void);\n+const char *rebase_path_todo(void);\n \n #define APPEND_SIGNOFF_DEDUP (1u << 0)\n \n@@ -57,6 +58,12 @@ struct replay_opts {\n };\n #define REPLAY_OPTS_INIT { .action = -1, .current_fixups = STRBUF_INIT }\n \n+enum missing_commit_check_level {\n+\tMISSING_COMMIT_CHECK_IGNORE = 0,\n+\tMISSING_COMMIT_CHECK_WARN,\n+\tMISSING_COMMIT_CHECK_ERROR\n+};\n+\n /* Call this to setup defaults before parsing command line options */\n void sequencer_init_config(struct replay_opts *opts);\n int sequencer_pick_revisions(struct replay_opts *opts);\n@@ -79,6 +86,7 @@ int sequencer_make_script(FILE *out, int argc, const char **argv,\n \n int sequencer_add_exec_commands(const char *command);\n int transform_todos(unsigned flags);\n+enum missing_commit_check_level get_missing_commit_check_level(void);\n int check_todo_list(void);\n int skip_unnecessary_picks(void);\n int rearrange_squash(void);\n-- \n2.18.0\n\n"},{"id":"353472","messageId":"20180724163221.15201-3-alban.gruin@gmail.com","threadId":"48814","inReplyTo":"20180724163221.15201-1-alban.gruin@gmail.com","subject":"[GSoC][PATCH v4 02/20] rebase -i: rewrite append_todo_help() in C","fromName":"Alban Gruin","fromEmail":"alban.gruin@gmail.com","sentAt":"2018-07-24T16:32:03Z","receivedAt":"2018-07-24T16:34:17Z","isPatch":true,"sender":{"key":"alban.gruin@gmail.com","avatar":"https://avatars.githubusercontent.com/u/6310153?v=4"},"body":"This rewrites append_todo_help() from shell to C. It also incorporates\nsome parts of initiate_action() and complete_action() that also write\nhelp texts to the todo file.\n\nThis also introduces the source file rebase-interactive.c. This file\nwill contain functions necessary for interactive rebase that are too\nspecific for the sequencer, and is part of libgit.a.\n\nTwo flags are added to rebase--helper.c: one to call\nappend_todo_help() (`--append-todo-help`), and another one to tell\nappend_todo_help() to write the help text suited for the edit-todo\nmode (`--write-edit-todo`).\n\nFinally, append_todo_help() is removed from git-rebase--interactive.sh\nto use `rebase--helper --append-todo-help` instead.\n\nSigned-off-by: Alban Gruin <alban.gruin@gmail.com>\n---\nNo code changes since v3.\n\n Makefile                   |  1 +\n builtin/rebase--helper.c   | 11 ++++--\n git-rebase--interactive.sh | 52 ++---------------------------\n rebase-interactive.c       | 68 ++++++++++++++++++++++++++++++++++++++\n rebase-interactive.h       |  6 ++++\n 5 files changed, 86 insertions(+), 52 deletions(-)\n create mode 100644 rebase-interactive.c\n create mode 100644 rebase-interactive.h\n\ndiff --git a/Makefile b/Makefile\nindex 08e5c54549..909a687857 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -922,6 +922,7 @@ LIB_OBJS += protocol.o\n LIB_OBJS += quote.o\n LIB_OBJS += reachable.o\n LIB_OBJS += read-cache.o\n+LIB_OBJS += rebase-interactive.o\n LIB_OBJS += reflog-walk.o\n LIB_OBJS += refs.o\n LIB_OBJS += refs/files-backend.o\ndiff --git a/builtin/rebase--helper.c b/builtin/rebase--helper.c\nindex f7c2a5fdc8..05e73e71d4 100644\n--- a/builtin/rebase--helper.c\n+++ b/builtin/rebase--helper.c\n@@ -3,6 +3,7 @@\n #include \"config.h\"\n #include \"parse-options.h\"\n #include \"sequencer.h\"\n+#include \"rebase-interactive.h\"\n \n static const char * const builtin_rebase_helper_usage[] = {\n \tN_(\"git rebase--helper [<options>]\"),\n@@ -12,12 +13,12 @@ static const char * const builtin_rebase_helper_usage[] = {\n int cmd_rebase__helper(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;\n+\tunsigned flags = 0, keep_empty = 0, rebase_merges = 0, write_edit_todo = 0;\n \tint abbreviate_commands = 0, rebase_cousins = -1;\n \tenum {\n \t\tCONTINUE = 1, ABORT, MAKE_SCRIPT, SHORTEN_OIDS, EXPAND_OIDS,\n \t\tCHECK_TODO_LIST, SKIP_UNNECESSARY_PICKS, REARRANGE_SQUASH,\n-\t\tADD_EXEC\n+\t\tADD_EXEC, APPEND_TODO_HELP\n \t} command = 0;\n \tstruct option options[] = {\n \t\tOPT_BOOL(0, \"ff\", &opts.allow_ff, N_(\"allow fast-forward\")),\n@@ -27,6 +28,8 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\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, \"write-edit-todo\", &write_edit_todo,\n+\t\t\t N_(\"append the edit-todo message to the todo-list\")),\n \t\tOPT_CMDMODE(0, \"continue\", &command, N_(\"continue rebase\"),\n \t\t\t\tCONTINUE),\n \t\tOPT_CMDMODE(0, \"abort\", &command, N_(\"abort rebase\"),\n@@ -45,6 +48,8 @@ int cmd_rebase__helper(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_CMDMODE(0, \"append-todo-help\", &command,\n+\t\t\t    N_(\"insert the help in the todo list\"), APPEND_TODO_HELP),\n \t\tOPT_END()\n \t};\n \n@@ -84,5 +89,7 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\n \t\treturn !!rearrange_squash();\n \tif (command == ADD_EXEC && argc == 2)\n \t\treturn !!sequencer_add_exec_commands(argv[1]);\n+\tif (command == APPEND_TODO_HELP && argc == 1)\n+\t\treturn !!append_todo_help(write_edit_todo, keep_empty);\n \tusage_with_options(builtin_rebase_helper_usage, options);\n }\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex 299ded2137..94c23a7af2 100644\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -39,38 +39,6 @@ comment_for_reflog () {\n \tesac\n }\n \n-append_todo_help () {\n-\tgettext \"\n-Commands:\n-p, pick <commit> = use commit\n-r, reword <commit> = use commit, but edit the commit message\n-e, edit <commit> = use commit, but stop for amending\n-s, squash <commit> = use commit, but meld into previous commit\n-f, fixup <commit> = like \\\"squash\\\", but discard this commit's log message\n-x, exec <command> = run command (the rest of the line) using shell\n-d, drop <commit> = remove commit\n-l, label <label> = label current HEAD with a name\n-t, reset <label> = reset HEAD to a label\n-m, merge [-C <commit> | -c <commit>] <label> [# <oneline>]\n-.       create a merge commit using the original merge commit's\n-.       message (or the oneline, if no original merge commit was\n-.       specified). Use -c <commit> to reword the commit message.\n-\n-These lines can be re-ordered; they are executed from top to bottom.\n-\" | git stripspace --comment-lines >>\"$todo\"\n-\n-\tif test $(get_missing_commit_check_level) = error\n-\tthen\n-\t\tgettext \"\n-Do not remove any line. Use 'drop' explicitly to remove a commit.\n-\" | git stripspace --comment-lines >>\"$todo\"\n-\telse\n-\t\tgettext \"\n-If you remove a line here THAT COMMIT WILL BE LOST.\n-\" | git stripspace --comment-lines >>\"$todo\"\n-\tfi\n-}\n-\n die_abort () {\n \tapply_autostash\n \trm -rf \"$state_dir\"\n@@ -143,13 +111,7 @@ initiate_action () {\n \t\tgit stripspace --strip-comments <\"$todo\" >\"$todo\".new\n \t\tmv -f \"$todo\".new \"$todo\"\n \t\tcollapse_todo_ids\n-\t\tappend_todo_help\n-\t\tgettext \"\n-You are editing the todo file of an ongoing interactive rebase.\n-To continue rebase after editing, run:\n-    git rebase --continue\n-\n-\" | git stripspace --comment-lines >>\"$todo\"\n+\t\tgit rebase--helper --append-todo-help --write-edit-todo\n \n \t\tgit_sequence_editor \"$todo\" ||\n \t\t\tdie \"$(gettext \"Could not execute editor\")\"\n@@ -220,17 +182,7 @@ $comment_char $(eval_ngettext \\\n \t\"Rebase \\$shortrevisions onto \\$shortonto (\\$todocount commands)\" \\\n \t\"$todocount\")\n EOF\n-\tappend_todo_help\n-\tgettext \"\n-\tHowever, if you remove everything, the rebase will be aborted.\n-\n-\t\" | git stripspace --comment-lines >>\"$todo\"\n-\n-\tif test -z \"$keep_empty\"\n-\tthen\n-\t\tprintf '%s\\n' \"$comment_char $(gettext \"Note that empty commits are commented out\")\" >>\"$todo\"\n-\tfi\n-\n+\tgit rebase--helper --append-todo-help ${keep_empty:+--keep-empty}\n \n \thas_action \"$todo\" ||\n \t\treturn 2\ndiff --git a/rebase-interactive.c b/rebase-interactive.c\nnew file mode 100644\nindex 0000000000..d7996bc8d9\n--- /dev/null\n+++ b/rebase-interactive.c\n@@ -0,0 +1,68 @@\n+#include \"cache.h\"\n+#include \"commit.h\"\n+#include \"rebase-interactive.h\"\n+#include \"sequencer.h\"\n+#include \"strbuf.h\"\n+\n+int append_todo_help(unsigned edit_todo, unsigned keep_empty)\n+{\n+\tstruct strbuf buf = STRBUF_INIT;\n+\tFILE *todo;\n+\tint ret;\n+\tconst char *msg = _(\"\\nCommands:\\n\"\n+\"p, pick <commit> = use commit\\n\"\n+\"r, reword <commit> = use commit, but edit the commit message\\n\"\n+\"e, edit <commit> = use commit, but stop for amending\\n\"\n+\"s, squash <commit> = use commit, but meld into previous commit\\n\"\n+\"f, fixup <commit> = like \\\"squash\\\", but discard this commit's log message\\n\"\n+\"x, exec <command> = run command (the rest of the line) using shell\\n\"\n+\"d, drop <commit> = remove commit\\n\"\n+\"l, label <label> = label current HEAD with a name\\n\"\n+\"t, reset <label> = reset HEAD to a label\\n\"\n+\"m, merge [-C <commit> | -c <commit>] <label> [# <oneline>]\\n\"\n+\".       create a merge commit using the original merge commit's\\n\"\n+\".       message (or the oneline, if no original merge commit was\\n\"\n+\".       specified). Use -c <commit> to reword the commit message.\\n\"\n+\"\\n\"\n+\"These lines can be re-ordered; they are executed from top to bottom.\\n\");\n+\n+\ttodo = fopen_or_warn(rebase_path_todo(), \"a\");\n+\tif (!todo)\n+\t\treturn 1;\n+\n+\tstrbuf_add_commented_lines(&buf, msg, strlen(msg));\n+\n+\tif (get_missing_commit_check_level() == MISSING_COMMIT_CHECK_ERROR)\n+\t\tmsg = _(\"\\nDo not remove any line. Use 'drop' \"\n+\t\t\t \"explicitly to remove a commit.\\n\");\n+\telse\n+\t\tmsg = _(\"\\nIf you remove a line here \"\n+\t\t\t \"THAT COMMIT WILL BE LOST.\\n\");\n+\n+\tstrbuf_add_commented_lines(&buf, msg, strlen(msg));\n+\n+\tif (edit_todo)\n+\t\tmsg = _(\"\\nYou are editing the todo file \"\n+\t\t\t\"of an ongoing interactive rebase.\\n\"\n+\t\t\t\"To continue rebase after editing, run:\\n\"\n+\t\t\t\"    git rebase --continue\\n\\n\");\n+\telse\n+\t\tmsg = _(\"\\nHowever, if you remove everything, \"\n+\t\t\t\"the rebase will be aborted.\\n\\n\");\n+\n+\tstrbuf_add_commented_lines(&buf, msg, strlen(msg));\n+\n+\tif (!keep_empty) {\n+\t\tmsg = _(\"Note that empty commits are commented out\");\n+\t\tstrbuf_add_commented_lines(&buf, msg, strlen(msg));\n+\t}\n+\n+\tret = fputs(buf.buf, todo);\n+\tif (ret < 0)\n+\t\terror_errno(_(\"could not append help text to '%s'\"), rebase_path_todo());\n+\n+\tfclose(todo);\n+\tstrbuf_release(&buf);\n+\n+\treturn ret;\n+}\ndiff --git a/rebase-interactive.h b/rebase-interactive.h\nnew file mode 100644\nindex 0000000000..47372624e0\n--- /dev/null\n+++ b/rebase-interactive.h\n@@ -0,0 +1,6 @@\n+#ifndef REBASE_INTERACTIVE_H\n+#define REBASE_INTERACTIVE_H\n+\n+int append_todo_help(unsigned edit_todo, unsigned keep_empty);\n+\n+#endif\n-- \n2.18.0\n\n"},{"id":"353473","messageId":"20180724163221.15201-4-alban.gruin@gmail.com","threadId":"48814","inReplyTo":"20180724163221.15201-1-alban.gruin@gmail.com","subject":"[GSoC][PATCH v4 03/20] editor: add a function to launch the sequence editor","fromName":"Alban Gruin","fromEmail":"alban.gruin@gmail.com","sentAt":"2018-07-24T16:32:04Z","receivedAt":"2018-07-24T16:34:18Z","isPatch":true,"sender":{"key":"alban.gruin@gmail.com","avatar":"https://avatars.githubusercontent.com/u/6310153?v=4"},"body":"As part of the rewrite of interactive rebase, the sequencer will need to\nopen the sequence editor to allow the user to edit the todo list.\nInstead of duplicating the existing launch_editor() function, this\nrefactors it to a new function, launch_specified_editor(), which takes\nthe editor as a parameter, in addition to the path, the buffer and the\nenvironment variables.  launch_sequence_editor() is then added to launch\nthe sequence editor.\n\nSigned-off-by: Alban Gruin <alban.gruin@gmail.com>\n---\nNo changes since v3.\n\n cache.h  |  1 +\n editor.c | 27 +++++++++++++++++++++++++--\n strbuf.h |  2 ++\n 3 files changed, 28 insertions(+), 2 deletions(-)\n\ndiff --git a/cache.h b/cache.h\nindex 8b447652a7..d70ae49ca2 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -1409,6 +1409,7 @@ extern const char *fmt_name(const char *name, const char *email);\n extern const char *ident_default_name(void);\n extern const char *ident_default_email(void);\n extern const char *git_editor(void);\n+extern const char *git_sequence_editor(void);\n extern const char *git_pager(int stdout_is_tty);\n extern int is_terminal_dumb(void);\n extern int git_ident_config(const char *, const char *, void *);\ndiff --git a/editor.c b/editor.c\nindex 9a9b4e12d1..c985eee1f9 100644\n--- a/editor.c\n+++ b/editor.c\n@@ -1,4 +1,5 @@\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"strbuf.h\"\n #include \"run-command.h\"\n #include \"sigchain.h\"\n@@ -34,10 +35,21 @@ const char *git_editor(void)\n \treturn editor;\n }\n \n-int launch_editor(const char *path, struct strbuf *buffer, const char *const *env)\n+const char *git_sequence_editor(void)\n {\n-\tconst char *editor = git_editor();\n+\tconst char *editor = getenv(\"GIT_SEQUENCE_EDITOR\");\n+\n+\tif (!editor)\n+\t\tgit_config_get_string_const(\"sequence.editor\", &editor);\n+\tif (!editor)\n+\t\teditor = git_editor();\n \n+\treturn editor;\n+}\n+\n+static int launch_specified_editor(const char *editor, const char *path,\n+\t\t\t\t   struct strbuf *buffer, const char *const *env)\n+{\n \tif (!editor)\n \t\treturn error(\"Terminal is dumb, but EDITOR unset\");\n \n@@ -95,3 +107,14 @@ int launch_editor(const char *path, struct strbuf *buffer, const char *const *en\n \t\treturn error_errno(\"could not read file '%s'\", path);\n \treturn 0;\n }\n+\n+int launch_editor(const char *path, struct strbuf *buffer, const char *const *env)\n+{\n+\treturn launch_specified_editor(git_editor(), path, buffer, env);\n+}\n+\n+int launch_sequence_editor(const char *path, struct strbuf *buffer,\n+\t\t\t   const char *const *env)\n+{\n+\treturn launch_specified_editor(git_sequence_editor(), path, buffer, env);\n+}\ndiff --git a/strbuf.h b/strbuf.h\nindex 60a35aef16..66da9822fd 100644\n--- a/strbuf.h\n+++ b/strbuf.h\n@@ -575,6 +575,8 @@ extern void strbuf_add_unique_abbrev(struct strbuf *sb,\n  * file's contents are not read into the buffer upon completion.\n  */\n extern int launch_editor(const char *path, struct strbuf *buffer, const char *const *env);\n+extern int launch_sequence_editor(const char *path, struct strbuf *buffer,\n+\t\t\t\t  const char *const *env);\n \n extern void strbuf_add_lines(struct strbuf *sb, const char *prefix, const char *buf, size_t size);\n \n-- \n2.18.0\n\n"},{"id":"353474","messageId":"20180724163221.15201-5-alban.gruin@gmail.com","threadId":"48814","inReplyTo":"20180724163221.15201-1-alban.gruin@gmail.com","subject":"[GSoC][PATCH v4 04/20] rebase -i: rewrite the edit-todo functionality in C","fromName":"Alban Gruin","fromEmail":"alban.gruin@gmail.com","sentAt":"2018-07-24T16:32:05Z","receivedAt":"2018-07-24T16:34:19Z","isPatch":true,"sender":{"key":"alban.gruin@gmail.com","avatar":"https://avatars.githubusercontent.com/u/6310153?v=4"},"body":"This rewrites the edit-todo functionality from shell to C.\n\nTo achieve that, a new command mode, `edit-todo`, is added, and the\n`write-edit-todo` flag is removed, as the shell script does not need to\nwrite the edit todo help message to the todo list anymore.\n\nThe shell version is then stripped in favour of a call to the helper.\n\nSigned-off-by: Alban Gruin <alban.gruin@gmail.com>\n---\nNo code changes since v3.\n\n builtin/rebase--helper.c   | 13 ++++++++-----\n git-rebase--interactive.sh | 11 +----------\n rebase-interactive.c       | 31 +++++++++++++++++++++++++++++++\n rebase-interactive.h       |  1 +\n 4 files changed, 41 insertions(+), 15 deletions(-)\n\ndiff --git a/builtin/rebase--helper.c b/builtin/rebase--helper.c\nindex 05e73e71d4..731a64971d 100644\n--- a/builtin/rebase--helper.c\n+++ b/builtin/rebase--helper.c\n@@ -13,12 +13,12 @@ static const char * const builtin_rebase_helper_usage[] = {\n int cmd_rebase__helper(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, write_edit_todo = 0;\n+\tunsigned flags = 0, keep_empty = 0, rebase_merges = 0;\n \tint abbreviate_commands = 0, rebase_cousins = -1;\n \tenum {\n \t\tCONTINUE = 1, ABORT, MAKE_SCRIPT, SHORTEN_OIDS, EXPAND_OIDS,\n \t\tCHECK_TODO_LIST, SKIP_UNNECESSARY_PICKS, REARRANGE_SQUASH,\n-\t\tADD_EXEC, APPEND_TODO_HELP\n+\t\tADD_EXEC, APPEND_TODO_HELP, EDIT_TODO\n \t} command = 0;\n \tstruct option options[] = {\n \t\tOPT_BOOL(0, \"ff\", &opts.allow_ff, N_(\"allow fast-forward\")),\n@@ -28,8 +28,6 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\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, \"write-edit-todo\", &write_edit_todo,\n-\t\t\t N_(\"append the edit-todo message to the todo-list\")),\n \t\tOPT_CMDMODE(0, \"continue\", &command, N_(\"continue rebase\"),\n \t\t\t\tCONTINUE),\n \t\tOPT_CMDMODE(0, \"abort\", &command, N_(\"abort rebase\"),\n@@ -50,6 +48,9 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\n \t\t\tN_(\"insert exec commands in todo list\"), ADD_EXEC),\n \t\tOPT_CMDMODE(0, \"append-todo-help\", &command,\n \t\t\t    N_(\"insert the help in the todo list\"), APPEND_TODO_HELP),\n+\t\tOPT_CMDMODE(0, \"edit-todo\", &command,\n+\t\t\t    N_(\"edit the todo list during an interactive rebase\"),\n+\t\t\t    EDIT_TODO),\n \t\tOPT_END()\n \t};\n \n@@ -90,6 +91,8 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\n \tif (command == ADD_EXEC && argc == 2)\n \t\treturn !!sequencer_add_exec_commands(argv[1]);\n \tif (command == APPEND_TODO_HELP && argc == 1)\n-\t\treturn !!append_todo_help(write_edit_todo, keep_empty);\n+\t\treturn !!append_todo_help(0, keep_empty);\n+\tif (command == EDIT_TODO && argc == 1)\n+\t\treturn !!edit_todo_list(flags);\n \tusage_with_options(builtin_rebase_helper_usage, options);\n }\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex 94c23a7af2..2defe607f4 100644\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -108,16 +108,7 @@ initiate_action () {\n \t\t     --continue\n \t\t;;\n \tedit-todo)\n-\t\tgit stripspace --strip-comments <\"$todo\" >\"$todo\".new\n-\t\tmv -f \"$todo\".new \"$todo\"\n-\t\tcollapse_todo_ids\n-\t\tgit rebase--helper --append-todo-help --write-edit-todo\n-\n-\t\tgit_sequence_editor \"$todo\" ||\n-\t\t\tdie \"$(gettext \"Could not execute editor\")\"\n-\t\texpand_todo_ids\n-\n-\t\texit\n+\t\texec git rebase--helper --edit-todo\n \t\t;;\n \tshow-current-patch)\n \t\texec git show REBASE_HEAD --\ndiff --git a/rebase-interactive.c b/rebase-interactive.c\nindex d7996bc8d9..403ecbf3c9 100644\n--- a/rebase-interactive.c\n+++ b/rebase-interactive.c\n@@ -66,3 +66,34 @@ int append_todo_help(unsigned edit_todo, unsigned keep_empty)\n \n \treturn ret;\n }\n+\n+int edit_todo_list(unsigned flags)\n+{\n+\tstruct strbuf buf = STRBUF_INIT;\n+\tconst char *todo_file = rebase_path_todo();\n+\tFILE *todo;\n+\n+\tif (strbuf_read_file(&buf, todo_file, 0) < 0)\n+\t\treturn error_errno(_(\"could not read '%s'.\"), todo_file);\n+\n+\tstrbuf_stripspace(&buf, 1);\n+\ttodo = fopen_or_warn(todo_file, \"w\");\n+\tif (!todo) {\n+\t\tstrbuf_release(&buf);\n+\t\treturn 1;\n+\t}\n+\n+\tstrbuf_write(&buf, todo);\n+\tfclose(todo);\n+\tstrbuf_release(&buf);\n+\n+\ttransform_todos(flags | TODO_LIST_SHORTEN_IDS);\n+\tappend_todo_help(1, 0);\n+\n+\tif (launch_sequence_editor(todo_file, NULL, NULL))\n+\t\treturn 1;\n+\n+\ttransform_todos(flags & ~(TODO_LIST_SHORTEN_IDS));\n+\n+\treturn 0;\n+}\ndiff --git a/rebase-interactive.h b/rebase-interactive.h\nindex 47372624e0..155219e742 100644\n--- a/rebase-interactive.h\n+++ b/rebase-interactive.h\n@@ -2,5 +2,6 @@\n #define REBASE_INTERACTIVE_H\n \n int append_todo_help(unsigned edit_todo, unsigned keep_empty);\n+int edit_todo_list(unsigned flags);\n \n #endif\n-- \n2.18.0\n\n"},{"id":"353475","messageId":"20180724163221.15201-6-alban.gruin@gmail.com","threadId":"48814","inReplyTo":"20180724163221.15201-1-alban.gruin@gmail.com","subject":"[GSoC][PATCH v4 05/20] sequencer: add a new function to silence a command, except if it fails","fromName":"Alban Gruin","fromEmail":"alban.gruin@gmail.com","sentAt":"2018-07-24T16:32:06Z","receivedAt":"2018-07-24T16:34:21Z","isPatch":true,"sender":{"key":"alban.gruin@gmail.com","avatar":"https://avatars.githubusercontent.com/u/6310153?v=4"},"body":"This adds a new function, run_command_silent_on_success(), to\nredirect the stdout and stderr of a command to a strbuf, and then to run\nthat command. This strbuf is printed only if the command fails. It is\nfunctionnaly similar to output() from git-rebase.sh.\n\nrun_git_commit() is then refactored to use of\nrun_command_silent_on_success().\n\nSigned-off-by: Alban Gruin <alban.gruin@gmail.com>\n---\nNo changes since v3.\n\n sequencer.c | 51 +++++++++++++++++++++++++--------------------------\n 1 file changed, 25 insertions(+), 26 deletions(-)\n\ndiff --git a/sequencer.c b/sequencer.c\nindex 0fc03dfe48..274cddd13f 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -769,6 +769,23 @@ N_(\"you have staged changes in your working tree\\n\"\n #define VERIFY_MSG  (1<<4)\n #define CREATE_ROOT_COMMIT (1<<5)\n \n+static int run_command_silent_on_success(struct child_process *cmd)\n+{\n+\tstruct strbuf buf = STRBUF_INIT;\n+\tint rc;\n+\n+\tcmd->stdout_to_stderr = 1;\n+\trc = pipe_command(cmd,\n+\t\t\t  NULL, 0,\n+\t\t\t  NULL, 0,\n+\t\t\t  &buf, 0);\n+\n+\tif (rc)\n+\t\tfputs(buf.buf, stderr);\n+\tstrbuf_release(&buf);\n+\treturn rc;\n+}\n+\n /*\n  * If we are cherry-pick, and if the merge did not result in\n  * hand-editing, we will hit this commit and inherit the original\n@@ -823,18 +840,11 @@ static int run_git_commit(const char *defmsg, struct replay_opts *opts,\n \n \tcmd.git_cmd = 1;\n \n-\tif (is_rebase_i(opts)) {\n-\t\tif (!(flags & EDIT_MSG)) {\n-\t\t\tcmd.stdout_to_stderr = 1;\n-\t\t\tcmd.err = -1;\n-\t\t}\n-\n-\t\tif (read_env_script(&cmd.env_array)) {\n-\t\t\tconst char *gpg_opt = gpg_sign_opt_quoted(opts);\n+\tif (is_rebase_i(opts) && read_env_script(&cmd.env_array)) {\n+\t\tconst char *gpg_opt = gpg_sign_opt_quoted(opts);\n \n-\t\t\treturn error(_(staged_changes_advice),\n-\t\t\t\t     gpg_opt, gpg_opt);\n-\t\t}\n+\t\treturn error(_(staged_changes_advice),\n+\t\t\t     gpg_opt, gpg_opt);\n \t}\n \n \targv_array_push(&cmd.args, \"commit\");\n@@ -864,21 +874,10 @@ static int run_git_commit(const char *defmsg, struct replay_opts *opts,\n \tif (opts->allow_empty_message)\n \t\targv_array_push(&cmd.args, \"--allow-empty-message\");\n \n-\tif (cmd.err == -1) {\n-\t\t/* hide stderr on success */\n-\t\tstruct strbuf buf = STRBUF_INIT;\n-\t\tint rc = pipe_command(&cmd,\n-\t\t\t\t      NULL, 0,\n-\t\t\t\t      /* stdout is already redirected */\n-\t\t\t\t      NULL, 0,\n-\t\t\t\t      &buf, 0);\n-\t\tif (rc)\n-\t\t\tfputs(buf.buf, stderr);\n-\t\tstrbuf_release(&buf);\n-\t\treturn rc;\n-\t}\n-\n-\treturn run_command(&cmd);\n+\tif (is_rebase_i(opts) && !(flags & EDIT_MSG))\n+\t\treturn run_command_silent_on_success(&cmd);\n+\telse\n+\t\treturn run_command(&cmd);\n }\n \n static int rest_is_empty(const struct strbuf *sb, int start)\n-- \n2.18.0\n\n"},{"id":"353476","messageId":"20180724163221.15201-7-alban.gruin@gmail.com","threadId":"48814","inReplyTo":"20180724163221.15201-1-alban.gruin@gmail.com","subject":"[GSoC][PATCH v4 06/20] rebase -i: rewrite setup_reflog_action() in C","fromName":"Alban Gruin","fromEmail":"alban.gruin@gmail.com","sentAt":"2018-07-24T16:32:07Z","receivedAt":"2018-07-24T16:34:24Z","isPatch":true,"sender":{"key":"alban.gruin@gmail.com","avatar":"https://avatars.githubusercontent.com/u/6310153?v=4"},"body":"This rewrites (the misnamed) setup_reflog_action() from shell to C. The\nnew version is called prepare_branch_to_be_rebased().\n\nA new command is added to rebase--helper.c, “checkout-base”, as well as\na new flag, “verbose”, to avoid silencing the output of the checkout\noperation called by checkout_base_commit().\n\nThe function `run_git_checkout()` will also be used in the next commit,\ntherefore its code is not part of `checkout_base_commit()`.\n\nThe shell version is then stripped in favour of a call to the helper.\n\nAs $GIT_REFLOG_ACTION is no longer set at the first call of\ncheckout_onto(), a call to comment_for_reflog() is added at the\nbeginning of this function.\n\nSigned-off-by: Alban Gruin <alban.gruin@gmail.com>\n---\nDropped the `verbose` variable.\n\n builtin/rebase--helper.c   |  7 ++++++-\n git-rebase--interactive.sh | 16 ++--------------\n sequencer.c                | 30 ++++++++++++++++++++++++++++++\n sequencer.h                |  2 ++\n 4 files changed, 40 insertions(+), 15 deletions(-)\n\ndiff --git a/builtin/rebase--helper.c b/builtin/rebase--helper.c\nindex 731a64971d..0e76dadba6 100644\n--- a/builtin/rebase--helper.c\n+++ b/builtin/rebase--helper.c\n@@ -18,7 +18,7 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\n \tenum {\n \t\tCONTINUE = 1, ABORT, MAKE_SCRIPT, SHORTEN_OIDS, EXPAND_OIDS,\n \t\tCHECK_TODO_LIST, SKIP_UNNECESSARY_PICKS, REARRANGE_SQUASH,\n-\t\tADD_EXEC, APPEND_TODO_HELP, EDIT_TODO\n+\t\tADD_EXEC, APPEND_TODO_HELP, EDIT_TODO, PREPARE_BRANCH\n \t} command = 0;\n \tstruct option options[] = {\n \t\tOPT_BOOL(0, \"ff\", &opts.allow_ff, N_(\"allow fast-forward\")),\n@@ -28,6 +28,7 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\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__VERBOSE(&opts.verbose, N_(\"be verbose\")),\n \t\tOPT_CMDMODE(0, \"continue\", &command, N_(\"continue rebase\"),\n \t\t\t\tCONTINUE),\n \t\tOPT_CMDMODE(0, \"abort\", &command, N_(\"abort rebase\"),\n@@ -51,6 +52,8 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\n \t\tOPT_CMDMODE(0, \"edit-todo\", &command,\n \t\t\t    N_(\"edit the todo list during an interactive rebase\"),\n \t\t\t    EDIT_TODO),\n+\t\tOPT_CMDMODE(0, \"prepare-branch\", &command,\n+\t\t\t    N_(\"prepare the branch to be rebased\"), PREPARE_BRANCH),\n \t\tOPT_END()\n \t};\n \n@@ -94,5 +97,7 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\n \t\treturn !!append_todo_help(0, keep_empty);\n \tif (command == EDIT_TODO && argc == 1)\n \t\treturn !!edit_todo_list(flags);\n+\tif (command == PREPARE_BRANCH && argc == 2)\n+\t\treturn !!prepare_branch_to_be_rebased(&opts, argv[1]);\n \tusage_with_options(builtin_rebase_helper_usage, options);\n }\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex 2defe607f4..77e972bb6c 100644\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -72,6 +72,7 @@ collapse_todo_ids() {\n \n # Switch to the branch in $into and notify it in the reflog\n checkout_onto () {\n+\tcomment_for_reflog start\n \tGIT_REFLOG_ACTION=\"$GIT_REFLOG_ACTION: checkout $onto_name\"\n \toutput git checkout $onto || die_abort \"$(gettext \"could not detach HEAD\")\"\n \tgit update-ref ORIG_HEAD $orig_head\n@@ -119,19 +120,6 @@ initiate_action () {\n \tesac\n }\n \n-setup_reflog_action () {\n-\tcomment_for_reflog start\n-\n-\tif test ! -z \"$switch_to\"\n-\tthen\n-\t\tGIT_REFLOG_ACTION=\"$GIT_REFLOG_ACTION: checkout $switch_to\"\n-\t\toutput git checkout \"$switch_to\" -- ||\n-\t\t\tdie \"$(eval_gettext \"Could not checkout \\$switch_to\")\"\n-\n-\t\tcomment_for_reflog start\n-\tfi\n-}\n-\n init_basic_state () {\n \torig_head=$(git rev-parse --verify HEAD) || die \"$(gettext \"No HEAD?\")\"\n \tmkdir -p \"$state_dir\" || die \"$(eval_gettext \"Could not create temporary \\$state_dir\")\"\n@@ -211,7 +199,7 @@ git_rebase__interactive () {\n \t\treturn 0\n \tfi\n \n-\tsetup_reflog_action\n+\tgit rebase--helper --prepare-branch \"$switch_to\" ${verbose:+--verbose}\n \tinit_basic_state\n \n \tinit_revisions_and_shortrevisions\ndiff --git a/sequencer.c b/sequencer.c\nindex 274cddd13f..0bc53e009e 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -3139,6 +3139,36 @@ 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+{\n+\tstruct child_process cmd = CHILD_PROCESS_INIT;\n+\n+\tcmd.git_cmd = 1;\n+\n+\targv_array_push(&cmd.args, \"checkout\");\n+\targv_array_push(&cmd.args, 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+\telse\n+\t\treturn run_command_silent_on_success(&cmd);\n+}\n+\n+int prepare_branch_to_be_rebased(struct replay_opts *opts, 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\t\treturn error(_(\"could not checkout %s\"), commit);\n+\t}\n+\n+\treturn 0;\n+}\n+\n static const char rescheduled_advice[] =\n N_(\"Could not execute the todo command\\n\"\n \"\\n\"\ndiff --git a/sequencer.h b/sequencer.h\nindex ffab798f1e..93da713fe2 100644\n--- a/sequencer.h\n+++ b/sequencer.h\n@@ -106,6 +106,8 @@ int update_head_with_reflog(const struct commit *old_head,\n void commit_post_rewrite(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+\n #define SUMMARY_INITIAL_COMMIT   (1 << 0)\n #define SUMMARY_SHOW_AUTHOR_DATE (1 << 1)\n void print_commit_summary(const char *prefix, const struct object_id *oid,\n-- \n2.18.0\n\n"},{"id":"353479","messageId":"20180724163221.15201-8-alban.gruin@gmail.com","threadId":"48814","inReplyTo":"20180724163221.15201-1-alban.gruin@gmail.com","subject":"[GSoC][PATCH v4 07/20] rebase -i: rewrite checkout_onto() in C","fromName":"Alban Gruin","fromEmail":"alban.gruin@gmail.com","sentAt":"2018-07-24T16:32:08Z","receivedAt":"2018-07-24T16:34:25Z","isPatch":true,"sender":{"key":"alban.gruin@gmail.com","avatar":"https://avatars.githubusercontent.com/u/6310153?v=4"},"body":"This rewrites checkout_onto() from shell to C.\n\nA new command (“checkout-onto”) is added to rebase--helper.c. The shell\nversion is then stripped.\n\nSigned-off-by: Alban Gruin <alban.gruin@gmail.com>\n---\nNo changes since v3.\n\n builtin/rebase--helper.c   |  7 ++++++-\n git-rebase--interactive.sh | 25 ++++---------------------\n sequencer.c                | 19 +++++++++++++++++++\n sequencer.h                |  3 +++\n 4 files changed, 32 insertions(+), 22 deletions(-)\n\ndiff --git a/builtin/rebase--helper.c b/builtin/rebase--helper.c\nindex 0e76dadba6..7d9426d23c 100644\n--- a/builtin/rebase--helper.c\n+++ b/builtin/rebase--helper.c\n@@ -18,7 +18,8 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\n \tenum {\n \t\tCONTINUE = 1, ABORT, MAKE_SCRIPT, SHORTEN_OIDS, EXPAND_OIDS,\n \t\tCHECK_TODO_LIST, SKIP_UNNECESSARY_PICKS, REARRANGE_SQUASH,\n-\t\tADD_EXEC, APPEND_TODO_HELP, EDIT_TODO, PREPARE_BRANCH\n+\t\tADD_EXEC, APPEND_TODO_HELP, EDIT_TODO, PREPARE_BRANCH,\n+\t\tCHECKOUT_ONTO\n \t} command = 0;\n \tstruct option options[] = {\n \t\tOPT_BOOL(0, \"ff\", &opts.allow_ff, N_(\"allow fast-forward\")),\n@@ -54,6 +55,8 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\n \t\t\t    EDIT_TODO),\n \t\tOPT_CMDMODE(0, \"prepare-branch\", &command,\n \t\t\t    N_(\"prepare the branch to be rebased\"), PREPARE_BRANCH),\n+\t\tOPT_CMDMODE(0, \"checkout-onto\", &command,\n+\t\t\t    N_(\"checkout a commit\"), CHECKOUT_ONTO),\n \t\tOPT_END()\n \t};\n \n@@ -99,5 +102,7 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\n \t\treturn !!edit_todo_list(flags);\n \tif (command == PREPARE_BRANCH && argc == 2)\n \t\treturn !!prepare_branch_to_be_rebased(&opts, argv[1]);\n+\tif (command == CHECKOUT_ONTO && argc == 4)\n+\t\treturn !!checkout_onto(&opts, argv[1], argv[2], argv[3]);\n \tusage_with_options(builtin_rebase_helper_usage, options);\n }\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex 77e972bb6c..b68f108f28 100644\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -28,17 +28,6 @@ case \"$comment_char\" in\n \t;;\n esac\n \n-orig_reflog_action=\"$GIT_REFLOG_ACTION\"\n-\n-comment_for_reflog () {\n-\tcase \"$orig_reflog_action\" in\n-\t''|rebase*)\n-\t\tGIT_REFLOG_ACTION=\"rebase -i ($1)\"\n-\t\texport GIT_REFLOG_ACTION\n-\t\t;;\n-\tesac\n-}\n-\n die_abort () {\n \tapply_autostash\n \trm -rf \"$state_dir\"\n@@ -70,14 +59,6 @@ collapse_todo_ids() {\n \tgit rebase--helper --shorten-ids\n }\n \n-# Switch to the branch in $into and notify it in the reflog\n-checkout_onto () {\n-\tcomment_for_reflog start\n-\tGIT_REFLOG_ACTION=\"$GIT_REFLOG_ACTION: checkout $onto_name\"\n-\toutput git checkout $onto || die_abort \"$(gettext \"could not detach HEAD\")\"\n-\tgit update-ref ORIG_HEAD $orig_head\n-}\n-\n get_missing_commit_check_level () {\n \tcheck_level=$(git config --get rebase.missingCommitsCheck)\n \tcheck_level=${check_level:-ignore}\n@@ -176,7 +157,8 @@ EOF\n \n \tgit rebase--helper --check-todo-list || {\n \t\tret=$?\n-\t\tcheckout_onto\n+\t\tgit rebase--helper --checkout-onto \"$onto_name\" \"$onto\" \\\n+\t\t    \"$orig_head\" ${verbose:+--verbose}\n \t\texit $ret\n \t}\n \n@@ -186,7 +168,8 @@ EOF\n \tonto=\"$(git rebase--helper --skip-unnecessary-picks)\" ||\n \tdie \"Could not skip unnecessary pick commands\"\n \n-\tcheckout_onto\n+\tgit rebase--helper --checkout-onto \"$onto_name\" \"$onto\" \"$orig_head\" \\\n+\t    ${verbose:+--verbose}\n \trequire_clean_work_tree \"rebase\"\n \texec git rebase--helper ${force_rebase:+--no-ff} $allow_empty_message \\\n \t     --continue\ndiff --git a/sequencer.c b/sequencer.c\nindex 0bc53e009e..c7d01d60b3 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -3169,6 +3169,25 @@ int prepare_branch_to_be_rebased(struct replay_opts *opts, const char *commit)\n \treturn 0;\n }\n \n+int checkout_onto(struct replay_opts *opts,\n+\t\t  const char *onto_name, const char *onto,\n+\t\t  const char *orig_head)\n+{\n+\tstruct object_id oid;\n+\tconst char *action = reflog_message(opts, \"start\", \"checkout %s\", onto_name);\n+\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+\t\tapply_autostash(opts);\n+\t\tsequencer_remove_state(opts);\n+\t\treturn error(_(\"could not detach HEAD\"));\n+\t}\n+\n+\treturn update_ref(NULL, \"ORIG_HEAD\", &oid, NULL, 0, UPDATE_REFS_MSG_ON_ERR);\n+}\n+\n static const char rescheduled_advice[] =\n N_(\"Could not execute the todo command\\n\"\n \"\\n\"\ndiff --git a/sequencer.h b/sequencer.h\nindex 93da713fe2..11a5334612 100644\n--- a/sequencer.h\n+++ b/sequencer.h\n@@ -107,6 +107,9 @@ void commit_post_rewrite(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 checkout_onto(struct replay_opts *opts,\n+\t\t  const char *onto_name, const char *onto,\n+\t\t  const char *orig_head);\n \n #define SUMMARY_INITIAL_COMMIT   (1 << 0)\n #define SUMMARY_SHOW_AUTHOR_DATE (1 << 1)\n-- \n2.18.0\n\n"},{"id":"353478","messageId":"20180724163221.15201-9-alban.gruin@gmail.com","threadId":"48814","inReplyTo":"20180724163221.15201-1-alban.gruin@gmail.com","subject":"[GSoC][PATCH v4 08/20] sequencer: refactor append_todo_help() to write its message to a buffer","fromName":"Alban Gruin","fromEmail":"alban.gruin@gmail.com","sentAt":"2018-07-24T16:32:09Z","receivedAt":"2018-07-24T16:34:27Z","isPatch":true,"sender":{"key":"alban.gruin@gmail.com","avatar":"https://avatars.githubusercontent.com/u/6310153?v=4"},"body":"This refactors append_todo_help() to write its message to a buffer\ninstead of the todo-list.  This is needed for the rewrite of\ncomplete_action(), which will come after the next commit.\n\nAs rebase--helper still needs the file manipulation part of\nappend_todo_help(), it is extracted to a temporary function,\nappend_todo_help_to_file().  This function will go away after the\nrewrite of complete_action().\n\nSigned-off-by: Alban Gruin <alban.gruin@gmail.com>\n---\nDropped the `include` in rebase-interactive.h.\n\n builtin/rebase--helper.c |  2 +-\n rebase-interactive.c     | 45 ++++++++++++++++++++++++++++------------\n rebase-interactive.h     |  4 +++-\n 3 files changed, 36 insertions(+), 15 deletions(-)\n\ndiff --git a/builtin/rebase--helper.c b/builtin/rebase--helper.c\nindex 7d9426d23c..313092c465 100644\n--- a/builtin/rebase--helper.c\n+++ b/builtin/rebase--helper.c\n@@ -97,7 +97,7 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\n \tif (command == ADD_EXEC && argc == 2)\n \t\treturn !!sequencer_add_exec_commands(argv[1]);\n \tif (command == APPEND_TODO_HELP && argc == 1)\n-\t\treturn !!append_todo_help(0, keep_empty);\n+\t\treturn !!append_todo_help_to_file(0, keep_empty);\n \tif (command == EDIT_TODO && argc == 1)\n \t\treturn !!edit_todo_list(flags);\n \tif (command == PREPARE_BRANCH && argc == 2)\ndiff --git a/rebase-interactive.c b/rebase-interactive.c\nindex 403ecbf3c9..d8b9465597 100644\n--- a/rebase-interactive.c\n+++ b/rebase-interactive.c\n@@ -4,11 +4,9 @@\n #include \"sequencer.h\"\n #include \"strbuf.h\"\n \n-int append_todo_help(unsigned edit_todo, unsigned keep_empty)\n+void append_todo_help(unsigned edit_todo, unsigned keep_empty,\n+\t\t      struct strbuf *buf)\n {\n-\tstruct strbuf buf = STRBUF_INIT;\n-\tFILE *todo;\n-\tint ret;\n \tconst char *msg = _(\"\\nCommands:\\n\"\n \"p, pick <commit> = use commit\\n\"\n \"r, reword <commit> = use commit, but edit the commit message\\n\"\n@@ -26,11 +24,7 @@ int append_todo_help(unsigned edit_todo, unsigned keep_empty)\n \"\\n\"\n \"These lines can be re-ordered; they are executed from top to bottom.\\n\");\n \n-\ttodo = fopen_or_warn(rebase_path_todo(), \"a\");\n-\tif (!todo)\n-\t\treturn 1;\n-\n-\tstrbuf_add_commented_lines(&buf, msg, strlen(msg));\n+\tstrbuf_add_commented_lines(buf, msg, strlen(msg));\n \n \tif (get_missing_commit_check_level() == MISSING_COMMIT_CHECK_ERROR)\n \t\tmsg = _(\"\\nDo not remove any line. Use 'drop' \"\n@@ -39,7 +33,7 @@ int append_todo_help(unsigned edit_todo, unsigned keep_empty)\n \t\tmsg = _(\"\\nIf you remove a line here \"\n \t\t\t \"THAT COMMIT WILL BE LOST.\\n\");\n \n-\tstrbuf_add_commented_lines(&buf, msg, strlen(msg));\n+\tstrbuf_add_commented_lines(buf, msg, strlen(msg));\n \n \tif (edit_todo)\n \t\tmsg = _(\"\\nYou are editing the todo file \"\n@@ -50,12 +44,25 @@ int append_todo_help(unsigned edit_todo, unsigned keep_empty)\n \t\tmsg = _(\"\\nHowever, if you remove everything, \"\n \t\t\t\"the rebase will be aborted.\\n\\n\");\n \n-\tstrbuf_add_commented_lines(&buf, msg, strlen(msg));\n+\tstrbuf_add_commented_lines(buf, msg, strlen(msg));\n \n \tif (!keep_empty) {\n \t\tmsg = _(\"Note that empty commits are commented out\");\n-\t\tstrbuf_add_commented_lines(&buf, msg, strlen(msg));\n+\t\tstrbuf_add_commented_lines(buf, msg, strlen(msg));\n \t}\n+}\n+\n+int append_todo_help_to_file(unsigned edit_todo, unsigned keep_empty)\n+{\n+\tstruct strbuf buf = STRBUF_INIT;\n+\tFILE *todo;\n+\tint ret;\n+\n+\ttodo = fopen_or_warn(rebase_path_todo(), \"a\");\n+\tif (!todo)\n+\t\treturn 1;\n+\n+\tappend_todo_help(edit_todo, keep_empty, &buf);\n \n \tret = fputs(buf.buf, todo);\n \tif (ret < 0)\n@@ -88,7 +95,19 @@ int edit_todo_list(unsigned flags)\n \tstrbuf_release(&buf);\n \n \ttransform_todos(flags | TODO_LIST_SHORTEN_IDS);\n-\tappend_todo_help(1, 0);\n+\n+\tstrbuf_read_file(&buf, todo_file, 0);\n+\tappend_todo_help(1, 0, &buf);\n+\n+\ttodo = fopen_or_warn(todo_file, \"w\");\n+\tif (!todo) {\n+\t\tstrbuf_release(&buf);\n+\t\treturn 1;\n+\t}\n+\n+\tstrbuf_write(&buf, todo);\n+\tfclose(todo);\n+\tstrbuf_release(&buf);\n \n \tif (launch_sequence_editor(todo_file, NULL, NULL))\n \t\treturn 1;\ndiff --git a/rebase-interactive.h b/rebase-interactive.h\nindex 155219e742..d33f3176b7 100644\n--- a/rebase-interactive.h\n+++ b/rebase-interactive.h\n@@ -1,7 +1,9 @@\n #ifndef REBASE_INTERACTIVE_H\n #define REBASE_INTERACTIVE_H\n \n-int append_todo_help(unsigned edit_todo, unsigned keep_empty);\n+void append_todo_help(unsigned edit_todo, unsigned keep_empty,\n+\t\t      struct strbuf *buf);\n+int append_todo_help_to_file(unsigned edit_todo, unsigned keep_empty);\n int edit_todo_list(unsigned flags);\n \n #endif\n-- \n2.18.0\n\n"},{"id":"353477","messageId":"20180724163221.15201-10-alban.gruin@gmail.com","threadId":"48814","inReplyTo":"20180724163221.15201-1-alban.gruin@gmail.com","subject":"[GSoC][PATCH v4 09/20] sequencer: change the way skip_unnecessary_picks() returns its result","fromName":"Alban Gruin","fromEmail":"alban.gruin@gmail.com","sentAt":"2018-07-24T16:32:10Z","receivedAt":"2018-07-24T16:34:28Z","isPatch":true,"sender":{"key":"alban.gruin@gmail.com","avatar":"https://avatars.githubusercontent.com/u/6310153?v=4"},"body":"Instead of skip_unnecessary_picks() printing its result to stdout, it\nreturns it into a struct object_id, as the rewrite of complete_action()\n(to come in the next commit) will need it.\n\nrebase--helper then is modified to fit this change.\n\nSigned-off-by: Alban Gruin <alban.gruin@gmail.com>\n---\n builtin/rebase--helper.c | 10 ++++++++--\n sequencer.c              | 13 ++++++-------\n sequencer.h              |  2 +-\n 3 files changed, 15 insertions(+), 10 deletions(-)\n\ndiff --git a/builtin/rebase--helper.c b/builtin/rebase--helper.c\nindex 313092c465..bed3dd2b95 100644\n--- a/builtin/rebase--helper.c\n+++ b/builtin/rebase--helper.c\n@@ -90,8 +90,14 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\n \t\treturn !!transform_todos(flags);\n \tif (command == CHECK_TODO_LIST && argc == 1)\n \t\treturn !!check_todo_list();\n-\tif (command == SKIP_UNNECESSARY_PICKS && argc == 1)\n-\t\treturn !!skip_unnecessary_picks();\n+\tif (command == SKIP_UNNECESSARY_PICKS && argc == 1) {\n+\t\tstruct object_id oid;\n+\t\tint ret = skip_unnecessary_picks(&oid);\n+\n+\t\tif (!ret)\n+\t\t\tputs(oid_to_hex(&oid));\n+\t\treturn !!ret;\n+\t}\n \tif (command == REARRANGE_SQUASH && argc == 1)\n \t\treturn !!rearrange_squash();\n \tif (command == ADD_EXEC && argc == 2)\ndiff --git a/sequencer.c b/sequencer.c\nindex c7d01d60b3..238c534049 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -4416,17 +4416,17 @@ static int rewrite_file(const char *path, const char *buf, size_t len)\n }\n \n /* skip picking commits whose parents are unchanged */\n-int skip_unnecessary_picks(void)\n+int skip_unnecessary_picks(struct object_id *output_oid)\n {\n \tconst char *todo_file = rebase_path_todo();\n \tstruct strbuf buf = STRBUF_INIT;\n \tstruct todo_list todo_list = TODO_LIST_INIT;\n-\tstruct object_id onto_oid, *oid = &onto_oid, *parent_oid;\n+\tstruct object_id *parent_oid;\n \tint fd, i;\n \n \tif (!read_oneliner(&buf, rebase_path_onto(), 0))\n \t\treturn error(_(\"could not read 'onto'\"));\n-\tif (get_oid(buf.buf, &onto_oid)) {\n+\tif (get_oid(buf.buf, output_oid)) {\n \t\tstrbuf_release(&buf);\n \t\treturn error(_(\"need a HEAD to fixup\"));\n \t}\n@@ -4456,9 +4456,9 @@ int skip_unnecessary_picks(void)\n \t\tif (item->commit->parents->next)\n \t\t\tbreak; /* merge commit */\n \t\tparent_oid = &item->commit->parents->item->object.oid;\n-\t\tif (hashcmp(parent_oid->hash, oid->hash))\n+\t\tif (hashcmp(parent_oid->hash, output_oid->hash))\n \t\t\tbreak;\n-\t\toid = &item->commit->object.oid;\n+\t\toidcpy(output_oid, &item->commit->object.oid);\n \t}\n \tif (i > 0) {\n \t\tint offset = get_item_line_offset(&todo_list, i);\n@@ -4487,11 +4487,10 @@ int skip_unnecessary_picks(void)\n \n \t\ttodo_list.current = i;\n \t\tif (is_fixup(peek_command(&todo_list, 0)))\n-\t\t\trecord_in_rewritten(oid, peek_command(&todo_list, 0));\n+\t\t\trecord_in_rewritten(output_oid, peek_command(&todo_list, 0));\n \t}\n \n \ttodo_list_release(&todo_list);\n-\tprintf(\"%s\\n\", oid_to_hex(oid));\n \n \treturn 0;\n }\ndiff --git a/sequencer.h b/sequencer.h\nindex 11a5334612..f11dabfd65 100644\n--- a/sequencer.h\n+++ b/sequencer.h\n@@ -88,7 +88,7 @@ int sequencer_add_exec_commands(const char *command);\n int transform_todos(unsigned flags);\n enum missing_commit_check_level get_missing_commit_check_level(void);\n int check_todo_list(void);\n-int skip_unnecessary_picks(void);\n+int skip_unnecessary_picks(struct object_id *output_oid);\n int rearrange_squash(void);\n \n extern const char sign_off_header[];\n-- \n2.18.0\n\n"},{"id":"353480","messageId":"20180724163221.15201-11-alban.gruin@gmail.com","threadId":"48814","inReplyTo":"20180724163221.15201-1-alban.gruin@gmail.com","subject":"[GSoC][PATCH v4 10/20] t3404: todo list with commented-out commands only aborts","fromName":"Alban Gruin","fromEmail":"alban.gruin@gmail.com","sentAt":"2018-07-24T16:32:11Z","receivedAt":"2018-07-24T16:34:29Z","isPatch":true,"sender":{"key":"alban.gruin@gmail.com","avatar":"https://avatars.githubusercontent.com/u/6310153?v=4"},"body":"If the todo list generated by `--make-script` is empty,\ncomplete_action() writes a noop, but if it has only commented-out\ncommands, it will abort with the message \"Nothing to do\", and does not\nlaunch the editor.  This adds a new test to ensure that\ncomplete_action() behaves this way.\n\nSigned-off-by: Alban Gruin <alban.gruin@gmail.com>\n---\nNew patch.\n\n t/t3404-rebase-interactive.sh | 10 ++++++++++\n 1 file changed, 10 insertions(+)\n\ndiff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh\nindex d392160ba9..7755b68092 100755\n--- a/t/t3404-rebase-interactive.sh\n+++ b/t/t3404-rebase-interactive.sh\n@@ -75,6 +75,16 @@ test_expect_success 'rebase --keep-empty' '\n \ttest_line_count = 6 actual\n '\n \n+cat > expect <<EOF\n+Nothing to do\n+EOF\n+\n+test_expect_success 'rebase -i with empty HEAD' '\n+\tset_fake_editor &&\n+\ttest_must_fail env FAKE_LINES=\"1 exec_true\" git rebase -i HEAD^ >actual 2>&1 &&\n+\ttest_i18ncmp expect actual\n+'\n+\n test_expect_success 'rebase -i with the exec command' '\n \tgit checkout master &&\n \t(\n-- \n2.18.0\n\n"},{"id":"353481","messageId":"20180724163221.15201-12-alban.gruin@gmail.com","threadId":"48814","inReplyTo":"20180724163221.15201-1-alban.gruin@gmail.com","subject":"[GSoC][PATCH v4 11/20] rebase -i: rewrite complete_action() in C","fromName":"Alban Gruin","fromEmail":"alban.gruin@gmail.com","sentAt":"2018-07-24T16:32:12Z","receivedAt":"2018-07-24T16:34:32Z","isPatch":true,"sender":{"key":"alban.gruin@gmail.com","avatar":"https://avatars.githubusercontent.com/u/6310153?v=4"},"body":"This rewrites complete_action() from shell to C.\n\nA new mode is added to rebase--helper (`--complete-action`), as well as\na new flag (`--autosquash`).\n\nFinally, complete_action() is stripped from git-rebase--interactive.sh.\n\nThe original complete_action() would return the code 2 when the todo\nlist contained no actions.  This was a special case for rebase -i and\n-p; git-rebase.sh would then apply the autostash, delete the state\ndirectory, and die with the message \"Nothing to do\".  This cleanup is\nrewritten in C instead of returning 2.  As rebase -i no longer returns\n2, the comment describing this behaviour in git-rebase.sh is updated to\nreflect this change.\n\nThe first check might seem useless as we write \"noop\" to the todo list\nif it is empty.  Actually, the todo list might contain commented\ncommands (ie. empty commits).  In this case, complete_action() won’t\nwrite \"noop\", and will abort without starting the editor.\n\nSigned-off-by: Alban Gruin <alban.gruin@gmail.com>\n---\n builtin/rebase--helper.c   | 12 ++++-\n git-rebase--interactive.sh | 53 ++------------------\n git-rebase.sh              |  2 +-\n sequencer.c                | 99 ++++++++++++++++++++++++++++++++++++++\n sequencer.h                |  4 ++\n 5 files changed, 118 insertions(+), 52 deletions(-)\n\ndiff --git a/builtin/rebase--helper.c b/builtin/rebase--helper.c\nindex bed3dd2b95..d7fa5a5062 100644\n--- a/builtin/rebase--helper.c\n+++ b/builtin/rebase--helper.c\n@@ -13,13 +13,13 @@ static const char * const builtin_rebase_helper_usage[] = {\n int cmd_rebase__helper(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;\n+\tunsigned flags = 0, keep_empty = 0, rebase_merges = 0, autosquash = 0;\n \tint abbreviate_commands = 0, rebase_cousins = -1;\n \tenum {\n \t\tCONTINUE = 1, ABORT, MAKE_SCRIPT, SHORTEN_OIDS, EXPAND_OIDS,\n \t\tCHECK_TODO_LIST, SKIP_UNNECESSARY_PICKS, REARRANGE_SQUASH,\n \t\tADD_EXEC, APPEND_TODO_HELP, EDIT_TODO, PREPARE_BRANCH,\n-\t\tCHECKOUT_ONTO\n+\t\tCHECKOUT_ONTO, COMPLETE_ACTION\n \t} command = 0;\n \tstruct option options[] = {\n \t\tOPT_BOOL(0, \"ff\", &opts.allow_ff, N_(\"allow fast-forward\")),\n@@ -29,6 +29,8 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\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 thas begin with squash!/fixup!\")),\n \t\tOPT__VERBOSE(&opts.verbose, N_(\"be verbose\")),\n \t\tOPT_CMDMODE(0, \"continue\", &command, N_(\"continue rebase\"),\n \t\t\t\tCONTINUE),\n@@ -57,6 +59,8 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\n \t\t\t    N_(\"prepare the branch to be rebased\"), PREPARE_BRANCH),\n \t\tOPT_CMDMODE(0, \"checkout-onto\", &command,\n \t\t\t    N_(\"checkout a commit\"), CHECKOUT_ONTO),\n+\t\tOPT_CMDMODE(0, \"complete-action\", &command,\n+\t\t\t    N_(\"complete the action\"), COMPLETE_ACTION),\n \t\tOPT_END()\n \t};\n \n@@ -110,5 +114,9 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\n \t\treturn !!prepare_branch_to_be_rebased(&opts, argv[1]);\n \tif (command == CHECKOUT_ONTO && argc == 4)\n \t\treturn !!checkout_onto(&opts, argv[1], argv[2], argv[3]);\n+\tif (command == COMPLETE_ACTION && argc == 6)\n+\t\treturn !!complete_action(&opts, flags, argv[1], argv[2], argv[3],\n+\t\t\t\t\t argv[4], argv[5], autosquash);\n+\n \tusage_with_options(builtin_rebase_helper_usage, options);\n }\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex b68f108f28..59dc4888a6 100644\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -127,54 +127,6 @@ init_revisions_and_shortrevisions () {\n \tfi\n }\n \n-complete_action() {\n-\ttest -s \"$todo\" || echo noop >> \"$todo\"\n-\ttest -z \"$autosquash\" || git rebase--helper --rearrange-squash || exit\n-\ttest -n \"$cmd\" && git rebase--helper --add-exec-commands \"$cmd\"\n-\n-\ttodocount=$(git stripspace --strip-comments <\"$todo\" | wc -l)\n-\ttodocount=${todocount##* }\n-\n-cat >>\"$todo\" <<EOF\n-\n-$comment_char $(eval_ngettext \\\n-\t\"Rebase \\$shortrevisions onto \\$shortonto (\\$todocount command)\" \\\n-\t\"Rebase \\$shortrevisions onto \\$shortonto (\\$todocount commands)\" \\\n-\t\"$todocount\")\n-EOF\n-\tgit rebase--helper --append-todo-help ${keep_empty:+--keep-empty}\n-\n-\thas_action \"$todo\" ||\n-\t\treturn 2\n-\n-\tcp \"$todo\" \"$todo\".backup\n-\tcollapse_todo_ids\n-\tgit_sequence_editor \"$todo\" ||\n-\t\tdie_abort \"$(gettext \"Could not execute editor\")\"\n-\n-\thas_action \"$todo\" ||\n-\t\treturn 2\n-\n-\tgit rebase--helper --check-todo-list || {\n-\t\tret=$?\n-\t\tgit rebase--helper --checkout-onto \"$onto_name\" \"$onto\" \\\n-\t\t    \"$orig_head\" ${verbose:+--verbose}\n-\t\texit $ret\n-\t}\n-\n-\texpand_todo_ids\n-\n-\ttest -n \"$force_rebase\" ||\n-\tonto=\"$(git rebase--helper --skip-unnecessary-picks)\" ||\n-\tdie \"Could not skip unnecessary pick commands\"\n-\n-\tgit rebase--helper --checkout-onto \"$onto_name\" \"$onto\" \"$orig_head\" \\\n-\t    ${verbose:+--verbose}\n-\trequire_clean_work_tree \"rebase\"\n-\texec git rebase--helper ${force_rebase:+--no-ff} $allow_empty_message \\\n-\t     --continue\n-}\n-\n git_rebase__interactive () {\n \tinitiate_action \"$action\"\n \tret=$?\n@@ -193,5 +145,8 @@ git_rebase__interactive () {\n \t\t$revisions ${restrict_revision+^$restrict_revision} >\"$todo\" ||\n \tdie \"$(gettext \"Could not generate todo list\")\"\n \n-\tcomplete_action\n+\texec git rebase--helper --complete-action \"$shortrevisions\" \"$onto_name\" \\\n+\t\t\"$shortonto\" \"$orig_head\" \"$cmd\" $allow_empty_message \\\n+\t\t${autosquash:+--autosquash} ${keep_empty:+--keep-empty} \\\n+\t\t${verbose:+--verbose} ${force_rebase:+--no-ff}\n }\ndiff --git a/git-rebase.sh b/git-rebase.sh\nindex f3b10c7f62..86da3816be 100755\n--- a/git-rebase.sh\n+++ b/git-rebase.sh\n@@ -219,7 +219,7 @@ run_specific_rebase () {\n \tif test $ret -eq 0\n \tthen\n \t\tfinish_rebase\n-\telif test $ret -eq 2 # special exit status for rebase -i\n+\telif test $ret -eq 2 # special exit status for rebase -p\n \tthen\n \t\tapply_autostash &&\n \t\trm -rf \"$state_dir\" &&\ndiff --git a/sequencer.c b/sequencer.c\nindex 238c534049..28082fe13e 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -30,6 +30,7 @@\n #include \"oidset.h\"\n #include \"commit-slab.h\"\n #include \"alias.h\"\n+#include \"rebase-interactive.h\"\n \n #define GIT_REFLOG_ACTION \"GIT_REFLOG_ACTION\"\n \n@@ -53,6 +54,9 @@ static GIT_PATH_FUNC(rebase_path, \"rebase-merge\")\n  * file and written to the tail of 'done'.\n  */\n GIT_PATH_FUNC(rebase_path_todo, \"rebase-merge/git-rebase-todo\")\n+static GIT_PATH_FUNC(rebase_path_todo_backup,\n+\t\t     \"rebase-merge/git-rebase-todo.backup\")\n+\n /*\n  * The rebase command lines that have already been processed. A line\n  * is moved here when it is first handled, before any associated user\n@@ -4495,6 +4499,101 @@ int skip_unnecessary_picks(struct object_id *output_oid)\n \treturn 0;\n }\n \n+int complete_action(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, const char *cmd,\n+\t\t    unsigned autosquash)\n+{\n+\tconst char *shortonto, *todo_file = rebase_path_todo();\n+\tstruct todo_list todo_list = TODO_LIST_INIT;\n+\tstruct strbuf *buf = &(todo_list.buf);\n+\tstruct object_id oid;\n+\tstruct stat st;\n+\n+\tget_oid(onto, &oid);\n+\tshortonto = find_unique_abbrev(&oid, DEFAULT_ABBREV);\n+\n+\tif (!lstat(todo_file, &st) && st.st_size == 0 &&\n+\t    write_message(\"noop\\n\", 5, todo_file, 0))\n+\t\treturn error_errno(_(\"could not write '%s'\"), todo_file);\n+\n+\tif (autosquash && rearrange_squash())\n+\t\treturn 1;\n+\n+\tif (cmd && *cmd)\n+\t\tsequencer_add_exec_commands(cmd);\n+\n+\tif (strbuf_read_file(buf, todo_file, 0) < 0)\n+\t\treturn error_errno(_(\"could not read '%s'.\"), todo_file);\n+\n+\tif (parse_insn_buffer(buf->buf, &todo_list)) {\n+\t\ttodo_list_release(&todo_list);\n+\t\treturn error(_(\"unusable todo list: '%s'\"), todo_file);\n+\t}\n+\n+\tif (count_commands(&todo_list) == 0) {\n+\t\tapply_autostash(opts);\n+\t\tsequencer_remove_state(opts);\n+\t\ttodo_list_release(&todo_list);\n+\n+\t\tfputs(\"Nothing to do\\n\", stderr);\n+\t\treturn 1;\n+\t}\n+\n+\tstrbuf_addch(buf, '\\n');\n+\tstrbuf_commented_addf(buf, Q_(\"Rebase %s onto %s (%d command)\",\n+\t\t\t\t      \"Rebase %s onto %s (%d commands)\",\n+\t\t\t\t      count_commands(&todo_list)),\n+\t\t\t      shortrevisions, shortonto, count_commands(&todo_list));\n+\tappend_todo_help(0, flags & TODO_LIST_KEEP_EMPTY, buf);\n+\n+\tif (write_message(buf->buf, buf->len, todo_file, 0)) {\n+\t\ttodo_list_release(&todo_list);\n+\t\treturn error_errno(_(\"could not write '%s'\"), todo_file);\n+\t}\n+\n+\tcopy_file(rebase_path_todo_backup(), todo_file, 0666);\n+\ttransform_todos(flags | TODO_LIST_SHORTEN_IDS);\n+\n+\tstrbuf_reset(buf);\n+\n+\tif (launch_sequence_editor(todo_file, buf, NULL)) {\n+\t\tapply_autostash(opts);\n+\t\tsequencer_remove_state(opts);\n+\t\ttodo_list_release(&todo_list);\n+\n+\t\treturn error(_(\"could not execute editor\"));\n+\t}\n+\n+\tstrbuf_stripspace(buf, 1);\n+\tif (buf->len == 0) {\n+\t\tapply_autostash(opts);\n+\t\tsequencer_remove_state(opts);\n+\t\ttodo_list_release(&todo_list);\n+\n+\t\tfputs(\"Nothing to do\\n\", stderr);\n+\t\treturn 1;\n+\t}\n+\n+\ttodo_list_release(&todo_list);\n+\n+\tif (check_todo_list()) {\n+\t\tcheckout_onto(opts, onto_name, onto, orig_head);\n+\t\treturn 1;\n+\t}\n+\n+\ttransform_todos(flags & ~(TODO_LIST_SHORTEN_IDS));\n+\n+\tif (opts->allow_ff && skip_unnecessary_picks(&oid))\n+\t\treturn error(_(\"could not skip unnecessary pick commands\"));\n+\n+\tcheckout_onto(opts, onto_name, oid_to_hex(&oid), orig_head);\n+\tif (require_clean_work_tree(\"rebase\", \"\", 1, 1))\n+\t\treturn 1;\n+\n+\treturn sequencer_continue(opts);\n+}\n+\n struct subject2item_entry {\n \tstruct hashmap_entry entry;\n \tint i;\ndiff --git a/sequencer.h b/sequencer.h\nindex f11dabfd65..3ab3791c8a 100644\n--- a/sequencer.h\n+++ b/sequencer.h\n@@ -89,6 +89,10 @@ int transform_todos(unsigned flags);\n enum missing_commit_check_level get_missing_commit_check_level(void);\n int check_todo_list(void);\n int skip_unnecessary_picks(struct object_id *output_oid);\n+int complete_action(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, const char *cmd,\n+\t\t    unsigned autosquash);\n int rearrange_squash(void);\n \n extern const char sign_off_header[];\n-- \n2.18.0\n\n"},{"id":"353482","messageId":"20180724163221.15201-13-alban.gruin@gmail.com","threadId":"48814","inReplyTo":"20180724163221.15201-1-alban.gruin@gmail.com","subject":"[GSoC][PATCH v4 12/20] rebase -i: remove unused modes and functions","fromName":"Alban Gruin","fromEmail":"alban.gruin@gmail.com","sentAt":"2018-07-24T16:32:13Z","receivedAt":"2018-07-24T16:34:33Z","isPatch":true,"sender":{"key":"alban.gruin@gmail.com","avatar":"https://avatars.githubusercontent.com/u/6310153?v=4"},"body":"This removes the modes `--skip-unnecessary-picks`, `--append-todo-help`,\nand `--checkout-onto` from rebase--helper.c, the functions of\ngit-rebase--interactive.sh that were rendered useless by the rewrite of\ncomplete_action(), and append_todo_help_to_file() from\nrebase-interactive.c.\n\nskip_unnecessary_picks() and checkout_onto() becomes static, as they are\nonly used inside of the sequencer.\n\nSigned-off-by: Alban Gruin <alban.gruin@gmail.com>\n---\n builtin/rebase--helper.c   | 23 ++----------------\n git-rebase--interactive.sh | 50 --------------------------------------\n rebase-interactive.c       | 22 -----------------\n rebase-interactive.h       |  1 -\n sequencer.c                |  8 +++---\n sequencer.h                |  4 ---\n 6 files changed, 6 insertions(+), 102 deletions(-)\n\ndiff --git a/builtin/rebase--helper.c b/builtin/rebase--helper.c\nindex d7fa5a5062..6085527b2b 100644\n--- a/builtin/rebase--helper.c\n+++ b/builtin/rebase--helper.c\n@@ -17,9 +17,8 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\n \tint abbreviate_commands = 0, rebase_cousins = -1;\n \tenum {\n \t\tCONTINUE = 1, ABORT, MAKE_SCRIPT, SHORTEN_OIDS, EXPAND_OIDS,\n-\t\tCHECK_TODO_LIST, SKIP_UNNECESSARY_PICKS, REARRANGE_SQUASH,\n-\t\tADD_EXEC, APPEND_TODO_HELP, EDIT_TODO, PREPARE_BRANCH,\n-\t\tCHECKOUT_ONTO, COMPLETE_ACTION\n+\t\tCHECK_TODO_LIST, REARRANGE_SQUASH, ADD_EXEC, EDIT_TODO, PREPARE_BRANCH,\n+\t\tCOMPLETE_ACTION\n \t} command = 0;\n \tstruct option options[] = {\n \t\tOPT_BOOL(0, \"ff\", &opts.allow_ff, N_(\"allow fast-forward\")),\n@@ -44,21 +43,15 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\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, \"skip-unnecessary-picks\", &command,\n-\t\t\tN_(\"skip unnecessary picks\"), SKIP_UNNECESSARY_PICKS),\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_CMDMODE(0, \"append-todo-help\", &command,\n-\t\t\t    N_(\"insert the help in the todo list\"), APPEND_TODO_HELP),\n \t\tOPT_CMDMODE(0, \"edit-todo\", &command,\n \t\t\t    N_(\"edit the todo list during an interactive rebase\"),\n \t\t\t    EDIT_TODO),\n \t\tOPT_CMDMODE(0, \"prepare-branch\", &command,\n \t\t\t    N_(\"prepare the branch to be rebased\"), PREPARE_BRANCH),\n-\t\tOPT_CMDMODE(0, \"checkout-onto\", &command,\n-\t\t\t    N_(\"checkout a commit\"), CHECKOUT_ONTO),\n \t\tOPT_CMDMODE(0, \"complete-action\", &command,\n \t\t\t    N_(\"complete the action\"), COMPLETE_ACTION),\n \t\tOPT_END()\n@@ -94,26 +87,14 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\n \t\treturn !!transform_todos(flags);\n \tif (command == CHECK_TODO_LIST && argc == 1)\n \t\treturn !!check_todo_list();\n-\tif (command == SKIP_UNNECESSARY_PICKS && argc == 1) {\n-\t\tstruct object_id oid;\n-\t\tint ret = skip_unnecessary_picks(&oid);\n-\n-\t\tif (!ret)\n-\t\t\tputs(oid_to_hex(&oid));\n-\t\treturn !!ret;\n-\t}\n \tif (command == REARRANGE_SQUASH && argc == 1)\n \t\treturn !!rearrange_squash();\n \tif (command == ADD_EXEC && argc == 2)\n \t\treturn !!sequencer_add_exec_commands(argv[1]);\n-\tif (command == APPEND_TODO_HELP && argc == 1)\n-\t\treturn !!append_todo_help_to_file(0, keep_empty);\n \tif (command == EDIT_TODO && argc == 1)\n \t\treturn !!edit_todo_list(flags);\n \tif (command == PREPARE_BRANCH && argc == 2)\n \t\treturn !!prepare_branch_to_be_rebased(&opts, argv[1]);\n-\tif (command == CHECKOUT_ONTO && argc == 4)\n-\t\treturn !!checkout_onto(&opts, argv[1], argv[2], argv[3]);\n \tif (command == COMPLETE_ACTION && argc == 6)\n \t\treturn !!complete_action(&opts, flags, argv[1], argv[2], argv[3],\n \t\t\t\t\t argv[4], argv[5], autosquash);\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex 59dc4888a6..0d66c0f8b8 100644\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -16,56 +16,6 @@ todo=\"$state_dir\"/git-rebase-todo\n GIT_CHERRY_PICK_HELP=\"$resolvemsg\"\n export GIT_CHERRY_PICK_HELP\n \n-comment_char=$(git config --get core.commentchar 2>/dev/null)\n-case \"$comment_char\" in\n-'' | auto)\n-\tcomment_char=\"#\"\n-\t;;\n-?)\n-\t;;\n-*)\n-\tcomment_char=$(echo \"$comment_char\" | cut -c1)\n-\t;;\n-esac\n-\n-die_abort () {\n-\tapply_autostash\n-\trm -rf \"$state_dir\"\n-\tdie \"$1\"\n-}\n-\n-has_action () {\n-\ttest -n \"$(git stripspace --strip-comments <\"$1\")\"\n-}\n-\n-git_sequence_editor () {\n-\tif test -z \"$GIT_SEQUENCE_EDITOR\"\n-\tthen\n-\t\tGIT_SEQUENCE_EDITOR=\"$(git config sequence.editor)\"\n-\t\tif [ -z \"$GIT_SEQUENCE_EDITOR\" ]\n-\t\tthen\n-\t\t\tGIT_SEQUENCE_EDITOR=\"$(git var GIT_EDITOR)\" || return $?\n-\t\tfi\n-\tfi\n-\n-\teval \"$GIT_SEQUENCE_EDITOR\" '\"$@\"'\n-}\n-\n-expand_todo_ids() {\n-\tgit rebase--helper --expand-ids\n-}\n-\n-collapse_todo_ids() {\n-\tgit rebase--helper --shorten-ids\n-}\n-\n-get_missing_commit_check_level () {\n-\tcheck_level=$(git config --get rebase.missingCommitsCheck)\n-\tcheck_level=${check_level:-ignore}\n-\t# Don't be case sensitive\n-\tprintf '%s' \"$check_level\" | tr 'A-Z' 'a-z'\n-}\n-\n # Initiate an action. If the cannot be any\n # further action it  may exec a command\n # or exit and not return.\ndiff --git a/rebase-interactive.c b/rebase-interactive.c\nindex d8b9465597..f99e596d28 100644\n--- a/rebase-interactive.c\n+++ b/rebase-interactive.c\n@@ -52,28 +52,6 @@ void append_todo_help(unsigned edit_todo, unsigned keep_empty,\n \t}\n }\n \n-int append_todo_help_to_file(unsigned edit_todo, unsigned keep_empty)\n-{\n-\tstruct strbuf buf = STRBUF_INIT;\n-\tFILE *todo;\n-\tint ret;\n-\n-\ttodo = fopen_or_warn(rebase_path_todo(), \"a\");\n-\tif (!todo)\n-\t\treturn 1;\n-\n-\tappend_todo_help(edit_todo, keep_empty, &buf);\n-\n-\tret = fputs(buf.buf, todo);\n-\tif (ret < 0)\n-\t\terror_errno(_(\"could not append help text to '%s'\"), rebase_path_todo());\n-\n-\tfclose(todo);\n-\tstrbuf_release(&buf);\n-\n-\treturn ret;\n-}\n-\n int edit_todo_list(unsigned flags)\n {\n \tstruct strbuf buf = STRBUF_INIT;\ndiff --git a/rebase-interactive.h b/rebase-interactive.h\nindex d33f3176b7..971da03776 100644\n--- a/rebase-interactive.h\n+++ b/rebase-interactive.h\n@@ -3,7 +3,6 @@\n \n void append_todo_help(unsigned edit_todo, unsigned keep_empty,\n \t\t      struct strbuf *buf);\n-int append_todo_help_to_file(unsigned edit_todo, unsigned keep_empty);\n int edit_todo_list(unsigned flags);\n \n #endif\ndiff --git a/sequencer.c b/sequencer.c\nindex 28082fe13e..1c035ceec7 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -3173,9 +3173,9 @@ int prepare_branch_to_be_rebased(struct replay_opts *opts, const char *commit)\n \treturn 0;\n }\n \n-int checkout_onto(struct replay_opts *opts,\n-\t\t  const char *onto_name, const char *onto,\n-\t\t  const char *orig_head)\n+static int checkout_onto(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 \tstruct object_id oid;\n \tconst char *action = reflog_message(opts, \"start\", \"checkout %s\", onto_name);\n@@ -4420,7 +4420,7 @@ static int rewrite_file(const char *path, const char *buf, size_t len)\n }\n \n /* skip picking commits whose parents are unchanged */\n-int skip_unnecessary_picks(struct object_id *output_oid)\n+static int skip_unnecessary_picks(struct object_id *output_oid)\n {\n \tconst char *todo_file = rebase_path_todo();\n \tstruct strbuf buf = STRBUF_INIT;\ndiff --git a/sequencer.h b/sequencer.h\nindex 3ab3791c8a..de9d4cf430 100644\n--- a/sequencer.h\n+++ b/sequencer.h\n@@ -88,7 +88,6 @@ int sequencer_add_exec_commands(const char *command);\n int transform_todos(unsigned flags);\n enum missing_commit_check_level get_missing_commit_check_level(void);\n int check_todo_list(void);\n-int skip_unnecessary_picks(struct object_id *output_oid);\n int complete_action(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, const char *cmd,\n@@ -111,9 +110,6 @@ void commit_post_rewrite(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 checkout_onto(struct replay_opts *opts,\n-\t\t  const char *onto_name, const char *onto,\n-\t\t  const char *orig_head);\n \n #define SUMMARY_INITIAL_COMMIT   (1 << 0)\n #define SUMMARY_SHOW_AUTHOR_DATE (1 << 1)\n-- \n2.18.0\n\n"},{"id":"353483","messageId":"20180724163221.15201-14-alban.gruin@gmail.com","threadId":"48814","inReplyTo":"20180724163221.15201-1-alban.gruin@gmail.com","subject":"[GSoC][PATCH v4 13/20] rebase -i: implement the logic to initialize $revisions in C","fromName":"Alban Gruin","fromEmail":"alban.gruin@gmail.com","sentAt":"2018-07-24T16:32:14Z","receivedAt":"2018-07-24T16:34:34Z","isPatch":true,"sender":{"key":"alban.gruin@gmail.com","avatar":"https://avatars.githubusercontent.com/u/6310153?v=4"},"body":"This rewrites the part of init_revisions_and_shortrevisions() needed by\n`--make-script` from shell to C.  The new version is called\nget_revision_ranges(), and is a static function inside of\nrebase--helper.c.  As this does not initialize $shortrevision, the\noriginal shell version is not yet stripped.\n\nUnlike init_revisions_and_shortrevisions(), get_revision_ranges()\ndoesn’t write $squash_onto to the state directory, it’s done by the\nhandler of `--make-script` instead.\n\nFinally, this drops the $revision argument passed to `--make-script` in\ngit-rebase--interactive.sh, and rebase--helper is changed accordingly.\n\nSigned-off-by: Alban Gruin <alban.gruin@gmail.com>\n---\n builtin/rebase--helper.c   | 56 ++++++++++++++++++++++++++++++++++++--\n git-rebase--interactive.sh |  4 ++-\n 2 files changed, 56 insertions(+), 4 deletions(-)\n\ndiff --git a/builtin/rebase--helper.c b/builtin/rebase--helper.c\nindex 6085527b2b..15fa556f65 100644\n--- a/builtin/rebase--helper.c\n+++ b/builtin/rebase--helper.c\n@@ -4,6 +4,25 @@\n #include \"parse-options.h\"\n #include \"sequencer.h\"\n #include \"rebase-interactive.h\"\n+#include \"argv-array.h\"\n+\n+static GIT_PATH_FUNC(path_squash_onto, \"rebase-merge/squash-onto\")\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)\n+{\n+\tconst char *base_rev = upstream ? upstream : onto;\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+\treturn 0;\n+}\n \n static const char * const builtin_rebase_helper_usage[] = {\n \tN_(\"git rebase--helper [<options>]\"),\n@@ -14,7 +33,9 @@ int cmd_rebase__helper(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;\n+\tint abbreviate_commands = 0, rebase_cousins = -1, ret;\n+\tconst char *head_hash = NULL, *onto = NULL, *restrict_revision = NULL,\n+\t\t*squash_onto = NULL, *upstream = NULL;\n \tenum {\n \t\tCONTINUE = 1, ABORT, MAKE_SCRIPT, SHORTEN_OIDS, EXPAND_OIDS,\n \t\tCHECK_TODO_LIST, REARRANGE_SQUASH, ADD_EXEC, EDIT_TODO, PREPARE_BRANCH,\n@@ -54,6 +75,13 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\n \t\t\t    N_(\"prepare the branch to be rebased\"), PREPARE_BRANCH),\n \t\tOPT_CMDMODE(0, \"complete-action\", &command,\n \t\t\t    N_(\"complete the action\"), COMPLETE_ACTION),\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_END()\n \t};\n \n@@ -81,8 +109,30 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\n \t\treturn !!sequencer_continue(&opts);\n \tif (command == ABORT && argc == 1)\n \t\treturn !!sequencer_remove_state(&opts);\n-\tif (command == MAKE_SCRIPT && argc > 1)\n-\t\treturn !!sequencer_make_script(stdout, argc, argv, flags);\n+\tif (command == MAKE_SCRIPT && argc == 1) {\n+\t\tchar *revisions = NULL;\n+\t\tstruct argv_array make_script_args = ARGV_ARRAY_INIT;\n+\n+\t\tif (!upstream && squash_onto)\n+\t\t\twrite_file(path_squash_onto(), \"%s\\n\", squash_onto);\n+\n+\t\tret = get_revision_ranges(upstream, onto, &head_hash, &revisions);\n+\t\tif (ret)\n+\t\t\treturn ret;\n+\n+\t\targv_array_pushl(&make_script_args, \"\", revisions, NULL);\n+\t\tif (restrict_revision)\n+\t\t\targv_array_push(&make_script_args, restrict_revision);\n+\n+\t\tret = sequencer_make_script(stdout,\n+\t\t\t\t\t    make_script_args.argc, make_script_args.argv,\n+\t\t\t\t\t    flags);\n+\n+\t\tfree(revisions);\n+\t\targv_array_clear(&make_script_args);\n+\n+\t\treturn !!ret;\n+\t}\n \tif ((command == SHORTEN_OIDS || command == EXPAND_OIDS) && argc == 1)\n \t\treturn !!transform_todos(flags);\n \tif (command == CHECK_TODO_LIST && argc == 1)\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex 0d66c0f8b8..4ca47aed1e 100644\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -92,7 +92,9 @@ git_rebase__interactive () {\n \tgit rebase--helper --make-script ${keep_empty:+--keep-empty} \\\n \t\t${rebase_merges:+--rebase-merges} \\\n \t\t${rebase_cousins:+--rebase-cousins} \\\n-\t\t$revisions ${restrict_revision+^$restrict_revision} >\"$todo\" ||\n+\t\t${upstream:+--upstream \"$upstream\"} ${onto:+--onto \"$onto\"} \\\n+\t\t${squash_onto:+--squash-onto \"$squash_onto\"} \\\n+\t\t${restrict_revision:+--restrict-revision ^\"$restrict_revision\"} >\"$todo\" ||\n \tdie \"$(gettext \"Could not generate todo list\")\"\n \n \texec git rebase--helper --complete-action \"$shortrevisions\" \"$onto_name\" \\\n-- \n2.18.0\n\n"},{"id":"353484","messageId":"20180724163221.15201-15-alban.gruin@gmail.com","threadId":"48814","inReplyTo":"20180724163221.15201-1-alban.gruin@gmail.com","subject":"[GSoC][PATCH v4 14/20] rebase -i: rewrite the rest of init_revisions_and_shortrevisions() in C","fromName":"Alban Gruin","fromEmail":"alban.gruin@gmail.com","sentAt":"2018-07-24T16:32:15Z","receivedAt":"2018-07-24T16:34:37Z","isPatch":true,"sender":{"key":"alban.gruin@gmail.com","avatar":"https://avatars.githubusercontent.com/u/6310153?v=4"},"body":"This rewrites the part of init_revisions_and_shortrevisions() needed by\n`--complete-action` (which initialize $shortrevisions) from shell to C.\n\nWhen `upstream` is empty, it means that the user launched a `rebase\n--root`, and `onto` contains the ID of an empty commit.  As a range\nbetween an empty commit and `head` is not really meaningful, `onto` is\nnot used to initialize `shortrevisions` in this case.\n\nThe corresponding arguments passed to `--complete-action` are then\ndropped, and init_revisions_and_shortrevisions() is stripped from\ngit-rebase--interactive.sh\n\nSigned-off-by: Alban Gruin <alban.gruin@gmail.com>\n---\n builtin/rebase--helper.c   | 40 ++++++++++++++++++++++++++++++++------\n git-rebase--interactive.sh | 27 ++++---------------------\n 2 files changed, 38 insertions(+), 29 deletions(-)\n\ndiff --git a/builtin/rebase--helper.c b/builtin/rebase--helper.c\nindex 15fa556f65..c4a4c5cfbb 100644\n--- a/builtin/rebase--helper.c\n+++ b/builtin/rebase--helper.c\n@@ -10,7 +10,7 @@ static GIT_PATH_FUNC(path_squash_onto, \"rebase-merge/squash-onto\")\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)\n+\t\t\t       char **revisions, char **shortrevisions)\n {\n \tconst char *base_rev = upstream ? upstream : onto;\n \tstruct object_id orig_head;\n@@ -19,7 +19,25 @@ static int get_revision_ranges(const char *upstream, const char *onto,\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+\tif (revisions)\n+\t\t*revisions = xstrfmt(\"%s...%s\", base_rev, *head_hash);\n+\tif (shortrevisions) {\n+\t\tconst char *shorthead;\n+\n+\t\tshorthead = find_unique_abbrev(&orig_head, DEFAULT_ABBREV);\n+\n+\t\tif (upstream) {\n+\t\t\tconst char *shortrev;\n+\t\t\tstruct object_id rev_oid;\n+\n+\t\t\tget_oid(base_rev, &rev_oid);\n+\t\t\tshortrev = find_unique_abbrev(&rev_oid, DEFAULT_ABBREV);\n+\n+\t\t\t*shortrevisions = xstrfmt(\"%s..%s\", shortrev, shorthead);\n+\t\t} else\n+\t\t\t*shortrevisions = xstrdup(shorthead);\n+\t}\n \n \treturn 0;\n }\n@@ -116,7 +134,7 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\n \t\tif (!upstream && squash_onto)\n \t\t\twrite_file(path_squash_onto(), \"%s\\n\", squash_onto);\n \n-\t\tret = get_revision_ranges(upstream, onto, &head_hash, &revisions);\n+\t\tret = get_revision_ranges(upstream, onto, &head_hash, &revisions, NULL);\n \t\tif (ret)\n \t\t\treturn ret;\n \n@@ -145,9 +163,19 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\n \t\treturn !!edit_todo_list(flags);\n \tif (command == PREPARE_BRANCH && argc == 2)\n \t\treturn !!prepare_branch_to_be_rebased(&opts, argv[1]);\n-\tif (command == COMPLETE_ACTION && argc == 6)\n-\t\treturn !!complete_action(&opts, flags, argv[1], argv[2], argv[3],\n-\t\t\t\t\t argv[4], argv[5], autosquash);\n+\tif (command == COMPLETE_ACTION && argc == 3) {\n+\t\tchar *shortrevisions = NULL;\n+\n+\t\tret = get_revision_ranges(upstream, onto, &head_hash, NULL, &shortrevisions);\n+\t\tif (ret)\n+\t\t\treturn ret;\n+\n+\t\tret = complete_action(&opts, flags, shortrevisions, argv[1], onto,\n+\t\t\t\t      head_hash, argv[2], autosquash);\n+\n+\t\tfree(shortrevisions);\n+\t\treturn !!ret;\n+\t}\n \n \tusage_with_options(builtin_rebase_helper_usage, options);\n }\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex 4ca47aed1e..08e9a21c2f 100644\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -60,23 +60,6 @@ init_basic_state () {\n \twrite_basic_state\n }\n \n-init_revisions_and_shortrevisions () {\n-\tshorthead=$(git rev-parse --short $orig_head)\n-\tshortonto=$(git rev-parse --short $onto)\n-\tif test -z \"$rebase_root\"\n-\t\t# this is now equivalent to ! -z \"$upstream\"\n-\tthen\n-\t\tshortupstream=$(git rev-parse --short $upstream)\n-\t\trevisions=$upstream...$orig_head\n-\t\tshortrevisions=$shortupstream..$shorthead\n-\telse\n-\t\trevisions=$onto...$orig_head\n-\t\tshortrevisions=$shorthead\n-\t\ttest -z \"$squash_onto\" ||\n-\t\techo \"$squash_onto\" >\"$state_dir\"/squash-onto\n-\tfi\n-}\n-\n git_rebase__interactive () {\n \tinitiate_action \"$action\"\n \tret=$?\n@@ -87,8 +70,6 @@ git_rebase__interactive () {\n \tgit rebase--helper --prepare-branch \"$switch_to\" ${verbose:+--verbose}\n \tinit_basic_state\n \n-\tinit_revisions_and_shortrevisions\n-\n \tgit rebase--helper --make-script ${keep_empty:+--keep-empty} \\\n \t\t${rebase_merges:+--rebase-merges} \\\n \t\t${rebase_cousins:+--rebase-cousins} \\\n@@ -97,8 +78,8 @@ git_rebase__interactive () {\n \t\t${restrict_revision:+--restrict-revision ^\"$restrict_revision\"} >\"$todo\" ||\n \tdie \"$(gettext \"Could not generate todo list\")\"\n \n-\texec git rebase--helper --complete-action \"$shortrevisions\" \"$onto_name\" \\\n-\t\t\"$shortonto\" \"$orig_head\" \"$cmd\" $allow_empty_message \\\n-\t\t${autosquash:+--autosquash} ${keep_empty:+--keep-empty} \\\n-\t\t${verbose:+--verbose} ${force_rebase:+--no-ff}\n+\texec git rebase--helper --complete-action \"$onto_name\" \"$cmd\" \\\n+\t\t$allow_empty_message ${autosquash:+--autosquash} ${verbose:+--verbose} \\\n+\t\t${keep_empty:+--keep-empty} ${force_rebase:+--no-ff} \\\n+\t\t${upstream:+--upstream \"$upstream\"} ${onto:+--onto \"$onto\"}\n }\n-- \n2.18.0\n\n"},{"id":"353485","messageId":"20180724163221.15201-16-alban.gruin@gmail.com","threadId":"48814","inReplyTo":"20180724163221.15201-1-alban.gruin@gmail.com","subject":"[GSoC][PATCH v4 15/20] rebase -i: rewrite write_basic_state() in C","fromName":"Alban Gruin","fromEmail":"alban.gruin@gmail.com","sentAt":"2018-07-24T16:32:16Z","receivedAt":"2018-07-24T16:34:38Z","isPatch":true,"sender":{"key":"alban.gruin@gmail.com","avatar":"https://avatars.githubusercontent.com/u/6310153?v=4"},"body":"This rewrites write_basic_state() from git-rebase.sh in C.  This is the\nfirst step in the conversion of init_basic_state(), hence the mode in\nrebase--helper.c is called INIT_BASIC_STATE.  init_basic_state() will be\nconverted in the next commit.\n\nThe part of read_strategy_opts() that parses the stategy options is\nmoved to a new function to allow its use in rebase--helper.c.\n\nFinally, the call to write_basic_state() is removed from\ngit-rebase--interactive.sh, replaced by a call to `--init-basic-state`.\n\nSigned-off-by: Alban Gruin <alban.gruin@gmail.com>\n---\nAll patches from this one are new.\n\n builtin/rebase--helper.c   | 28 +++++++++++++-\n git-rebase--interactive.sh |  7 +++-\n sequencer.c                | 77 ++++++++++++++++++++++++++++++++------\n sequencer.h                |  4 ++\n 4 files changed, 102 insertions(+), 14 deletions(-)\n\ndiff --git a/builtin/rebase--helper.c b/builtin/rebase--helper.c\nindex c4a4c5cfbb..06fe3c018b 100644\n--- a/builtin/rebase--helper.c\n+++ b/builtin/rebase--helper.c\n@@ -5,6 +5,8 @@\n #include \"sequencer.h\"\n #include \"rebase-interactive.h\"\n #include \"argv-array.h\"\n+#include \"rerere.h\"\n+#include \"alias.h\"\n \n static GIT_PATH_FUNC(path_squash_onto, \"rebase-merge/squash-onto\")\n \n@@ -53,11 +55,12 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\n \tunsigned flags = 0, keep_empty = 0, rebase_merges = 0, autosquash = 0;\n \tint abbreviate_commands = 0, rebase_cousins = -1, ret;\n \tconst char *head_hash = NULL, *onto = NULL, *restrict_revision = NULL,\n-\t\t*squash_onto = NULL, *upstream = NULL;\n+\t\t*squash_onto = NULL, *upstream = NULL, *head_name = NULL;\n+\tchar *raw_strategies = NULL;\n \tenum {\n \t\tCONTINUE = 1, ABORT, MAKE_SCRIPT, SHORTEN_OIDS, EXPAND_OIDS,\n \t\tCHECK_TODO_LIST, REARRANGE_SQUASH, ADD_EXEC, EDIT_TODO, PREPARE_BRANCH,\n-\t\tCOMPLETE_ACTION\n+\t\tCOMPLETE_ACTION, INIT_BASIC_STATE\n \t} command = 0;\n \tstruct option options[] = {\n \t\tOPT_BOOL(0, \"ff\", &opts.allow_ff, N_(\"allow fast-forward\")),\n@@ -69,6 +72,7 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\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 thas 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\tCONTINUE),\n@@ -93,6 +97,8 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\n \t\t\t    N_(\"prepare the branch to be rebased\"), PREPARE_BRANCH),\n \t\tOPT_CMDMODE(0, \"complete-action\", &command,\n \t\t\t    N_(\"complete the action\"), COMPLETE_ACTION),\n+\t\tOPT_CMDMODE(0, \"init-basic-state\", &command,\n+\t\t\t    N_(\"initialise the rebase state\"), INIT_BASIC_STATE),\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@@ -100,6 +106,14 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\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\tOPT_STRING('S', \"gpg-sign\", &opts.gpg_sign, N_(\"gpg-sign\"),\n+\t\t\t   N_(\"GPG-sign commits\")),\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_RERERE_AUTOUPDATE(&opts.allow_rerere_auto),\n \t\tOPT_END()\n \t};\n \n@@ -176,6 +190,16 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\n \t\tfree(shortrevisions);\n \t\treturn !!ret;\n \t}\n+\tif (command == INIT_BASIC_STATE) {\n+\t\tif (raw_strategies)\n+\t\t\tparse_strategy_opts(&opts, raw_strategies);\n+\n+\t\tret = get_revision_ranges(upstream, onto, &head_hash, NULL, NULL);\n+\t\tif (ret)\n+\t\t\treturn ret;\n+\n+\t\treturn !!write_basic_state(&opts, head_name, onto, head_hash);\n+\t}\n \n \tusage_with_options(builtin_rebase_helper_usage, options);\n }\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex 08e9a21c2f..6367da66e2 100644\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -57,7 +57,6 @@ init_basic_state () {\n \trm -f \"$(git rev-parse --git-path REBASE_HEAD)\"\n \n \t: > \"$state_dir\"/interactive || die \"$(gettext \"Could not mark as interactive\")\"\n-\twrite_basic_state\n }\n \n git_rebase__interactive () {\n@@ -70,6 +69,12 @@ git_rebase__interactive () {\n \tgit rebase--helper --prepare-branch \"$switch_to\" ${verbose:+--verbose}\n \tinit_basic_state\n \n+\tgit rebase--helper --init-basic-state ${upstream:+--upstream \"$upstream\"} \\\n+\t\t${onto:+--onto \"$onto\"} ${head_name:+--head-name \"$head_name\"} \\\n+\t\t${verbose:+--verbose} ${strategy:+--strategy \"$strategy\"} \\\n+\t\t${strategy_opts:+--strategy-opts=\"$strategy_opts\"} \\\n+\t\t\"$allow_rerere_autoupdate\" \"$gpg_sign_opt\" \"$signoff\" || exit\n+\n \tgit rebase--helper --make-script ${keep_empty:+--keep-empty} \\\n \t\t${rebase_merges:+--rebase-merges} \\\n \t\t${rebase_cousins:+--rebase-cousins} \\\ndiff --git a/sequencer.c b/sequencer.c\nindex 1c035ceec7..d257903db0 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -144,7 +144,7 @@ static GIT_PATH_FUNC(rebase_path_refs_to_delete, \"rebase-merge/refs-to-delete\")\n \n /*\n  * The following files are written by git-rebase just after parsing the\n- * command-line (and are only consumed, not modified, by the sequencer).\n+ * command-line.\n  */\n static GIT_PATH_FUNC(rebase_path_gpg_sign_opt, \"rebase-merge/gpg_sign_opt\")\n static GIT_PATH_FUNC(rebase_path_orig_head, \"rebase-merge/orig-head\")\n@@ -156,6 +156,7 @@ static GIT_PATH_FUNC(rebase_path_autostash, \"rebase-merge/autostash\")\n static GIT_PATH_FUNC(rebase_path_strategy, \"rebase-merge/strategy\")\n static GIT_PATH_FUNC(rebase_path_strategy_opts, \"rebase-merge/strategy_opts\")\n static GIT_PATH_FUNC(rebase_path_allow_rerere_autoupdate, \"rebase-merge/allow_rerere_autoupdate\")\n+static GIT_PATH_FUNC(rebase_path_quiet, \"rebase-merge/quiet\")\n \n static int git_sequencer_config(const char *k, const char *v, void *cb)\n {\n@@ -2207,21 +2208,14 @@ static int populate_opts_cb(const char *key, const char *value, void *data)\n \treturn 0;\n }\n \n-static void read_strategy_opts(struct replay_opts *opts, struct strbuf *buf)\n+void parse_strategy_opts(struct replay_opts *opts, char *raw_opts)\n {\n \tint i;\n-\tchar *strategy_opts_string;\n+\tchar *strategy_opts_string = raw_opts;\n \n-\tstrbuf_reset(buf);\n-\tif (!read_oneliner(buf, rebase_path_strategy(), 0))\n-\t\treturn;\n-\topts->strategy = strbuf_detach(buf, NULL);\n-\tif (!read_oneliner(buf, rebase_path_strategy_opts(), 0))\n-\t\treturn;\n-\n-\tstrategy_opts_string = buf->buf;\n \tif (*strategy_opts_string == ' ')\n \t\tstrategy_opts_string++;\n+\n \topts->xopts_nr = split_cmdline(strategy_opts_string,\n \t\t\t\t       (const char ***)&opts->xopts);\n \tfor (i = 0; i < opts->xopts_nr; i++) {\n@@ -2232,6 +2226,18 @@ static void read_strategy_opts(struct replay_opts *opts, struct strbuf *buf)\n \t}\n }\n \n+static void read_strategy_opts(struct replay_opts *opts, struct strbuf *buf)\n+{\n+\tstrbuf_reset(buf);\n+\tif (!read_oneliner(buf, rebase_path_strategy(), 0))\n+\t\treturn;\n+\topts->strategy = strbuf_detach(buf, NULL);\n+\tif (!read_oneliner(buf, rebase_path_strategy_opts(), 0))\n+\t\treturn;\n+\n+\tparse_strategy_opts(opts, buf->buf);\n+}\n+\n static int read_populate_opts(struct replay_opts *opts)\n {\n \tif (is_rebase_i(opts)) {\n@@ -2299,6 +2305,55 @@ static int read_populate_opts(struct replay_opts *opts)\n \treturn 0;\n }\n \n+static void write_strategy_opts(struct replay_opts *opts)\n+{\n+\tint i;\n+\tstruct strbuf buf = STRBUF_INIT;\n+\n+\tfor (i = 0; i < opts->xopts_nr; ++i)\n+\t\tstrbuf_addf(&buf, \" --%s\", opts->xopts[i]);\n+\n+\twrite_file(rebase_path_strategy_opts(), \"%s\\n\", buf.buf);\n+\tstrbuf_release(&buf);\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+{\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+\tif (orig_head)\n+\t\twrite_file(rebase_path_orig_head(), \"%s\\n\", orig_head);\n+\n+\tif (quiet)\n+\t\twrite_file(rebase_path_quiet(), \"%s\\n\", quiet);\n+\telse\n+\t\twrite_file(rebase_path_quiet(), \"\");\n+\n+\tif (opts->verbose)\n+\t\twrite_file(rebase_path_verbose(), \"\");\n+\tif (opts->strategy)\n+\t\twrite_file(rebase_path_strategy(), \"%s\\n\", opts->strategy);\n+\tif (opts->xopts_nr > 0)\n+\t\twrite_strategy_opts(opts);\n+\n+\tif (opts->allow_rerere_auto == RERERE_AUTOUPDATE)\n+\t\twrite_file(rebase_path_allow_rerere_autoupdate(), \"--rerere-autoupdate\\n\");\n+\telse if (opts->allow_rerere_auto == RERERE_NOAUTOUPDATE)\n+\t\twrite_file(rebase_path_allow_rerere_autoupdate(), \"--no-rerere-autoupdate\\n\");\n+\n+\tif (opts->gpg_sign)\n+\t\twrite_file(rebase_path_gpg_sign_opt(), \"-S%s\\n\", opts->gpg_sign);\n+\tif (opts->signoff)\n+\t\twrite_file(rebase_path_signoff(), \"--signoff\\n\");\n+\n+\treturn 0;\n+}\n+\n static int walk_revs_populate_todo(struct todo_list *todo_list,\n \t\t\t\tstruct replay_opts *opts)\n {\ndiff --git a/sequencer.h b/sequencer.h\nindex de9d4cf430..62045131ae 100644\n--- a/sequencer.h\n+++ b/sequencer.h\n@@ -116,3 +116,7 @@ int prepare_branch_to_be_rebased(struct replay_opts *opts, const char *commit);\n void print_commit_summary(const char *prefix, const struct object_id *oid,\n \t\t\t  unsigned int flags);\n #endif\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-- \n2.18.0\n\n"},{"id":"353486","messageId":"20180724163221.15201-17-alban.gruin@gmail.com","threadId":"48814","inReplyTo":"20180724163221.15201-1-alban.gruin@gmail.com","subject":"[GSoC][PATCH v4 16/20] rebase -i: rewrite init_basic_state() in C","fromName":"Alban Gruin","fromEmail":"alban.gruin@gmail.com","sentAt":"2018-07-24T16:32:17Z","receivedAt":"2018-07-24T16:34:39Z","isPatch":true,"sender":{"key":"alban.gruin@gmail.com","avatar":"https://avatars.githubusercontent.com/u/6310153?v=4"},"body":"This rewrites init_basic_state() from shell to C.  The call to\nwrite_basic_state() in cmd_rebase__helper() is replaced by a call to the\nnew function.\n\nThe shell version is then stripped from git-rebase--interactive.sh.\n\nSigned-off-by: Alban Gruin <alban.gruin@gmail.com>\n---\n builtin/rebase--helper.c   | 23 ++++++++++++++++++++++-\n git-rebase--interactive.sh |  9 ---------\n 2 files changed, 22 insertions(+), 10 deletions(-)\n\ndiff --git a/builtin/rebase--helper.c b/builtin/rebase--helper.c\nindex 06fe3c018b..ac21e8e06e 100644\n--- a/builtin/rebase--helper.c\n+++ b/builtin/rebase--helper.c\n@@ -5,10 +5,13 @@\n #include \"sequencer.h\"\n #include \"rebase-interactive.h\"\n #include \"argv-array.h\"\n+#include \"refs.h\"\n #include \"rerere.h\"\n #include \"alias.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 get_revision_ranges(const char *upstream, const char *onto,\n \t\t\t       const char **head_hash,\n@@ -44,6 +47,24 @@ static int get_revision_ranges(const char *upstream, const char *onto,\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 const char * const builtin_rebase_helper_usage[] = {\n \tN_(\"git rebase--helper [<options>]\"),\n \tNULL\n@@ -198,7 +219,7 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\n \t\tif (ret)\n \t\t\treturn ret;\n \n-\t\treturn !!write_basic_state(&opts, head_name, onto, head_hash);\n+\t\treturn !!init_basic_state(&opts, head_name, onto, head_hash);\n \t}\n \n \tusage_with_options(builtin_rebase_helper_usage, options);\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex 6367da66e2..761be95ed1 100644\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -51,14 +51,6 @@ initiate_action () {\n \tesac\n }\n \n-init_basic_state () {\n-\torig_head=$(git rev-parse --verify HEAD) || die \"$(gettext \"No HEAD?\")\"\n-\tmkdir -p \"$state_dir\" || die \"$(eval_gettext \"Could not create temporary \\$state_dir\")\"\n-\trm -f \"$(git rev-parse --git-path REBASE_HEAD)\"\n-\n-\t: > \"$state_dir\"/interactive || die \"$(gettext \"Could not mark as interactive\")\"\n-}\n-\n git_rebase__interactive () {\n \tinitiate_action \"$action\"\n \tret=$?\n@@ -67,7 +59,6 @@ git_rebase__interactive () {\n \tfi\n \n \tgit rebase--helper --prepare-branch \"$switch_to\" ${verbose:+--verbose}\n-\tinit_basic_state\n \n \tgit rebase--helper --init-basic-state ${upstream:+--upstream \"$upstream\"} \\\n \t\t${onto:+--onto \"$onto\"} ${head_name:+--head-name \"$head_name\"} \\\n-- \n2.18.0\n\n"},{"id":"353487","messageId":"20180724163221.15201-18-alban.gruin@gmail.com","threadId":"48814","inReplyTo":"20180724163221.15201-1-alban.gruin@gmail.com","subject":"[GSoC][PATCH v4 17/20] rebase -i: implement the main part of interactive rebase as a builtin","fromName":"Alban Gruin","fromEmail":"alban.gruin@gmail.com","sentAt":"2018-07-24T16:32:18Z","receivedAt":"2018-07-24T16:34:42Z","isPatch":true,"sender":{"key":"alban.gruin@gmail.com","avatar":"https://avatars.githubusercontent.com/u/6310153?v=4"},"body":"This rewrites the part of interactive rebase which initializes the\nbasic state, make the script and complete the action, as a buitin, named\ngit-rebase--interactive2 for now.  Others modes (`--continue`,\n`--edit-todo`, etc.) will be rewritten in the next commit.\n\ngit-rebase--interactive.sh is modified to call git-rebase--interactive2\ninstead of git-rebase--helper.\n\nSigned-off-by: Alban Gruin <alban.gruin@gmail.com>\n---\n .gitignore                     |   1 +\n Makefile                       |   1 +\n builtin.h                      |   1 +\n builtin/rebase--interactive2.c | 200 +++++++++++++++++++++++++++++++++\n git-rebase--interactive.sh     |  41 +++----\n git.c                          |   1 +\n 6 files changed, 226 insertions(+), 19 deletions(-)\n create mode 100644 builtin/rebase--interactive2.c\n\ndiff --git a/.gitignore b/.gitignore\nindex 3284a1e9b1..404c9a8472 100644\n--- a/.gitignore\n+++ b/.gitignore\n@@ -118,6 +118,7 @@\n /git-rebase--am\n /git-rebase--helper\n /git-rebase--interactive\n+/git-rebase--interactive2\n /git-rebase--merge\n /git-rebase--preserve-merges\n /git-receive-pack\ndiff --git a/Makefile b/Makefile\nindex 909a687857..71f8f45fe5 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -1060,6 +1060,7 @@ BUILTIN_OBJS += builtin/prune.o\n BUILTIN_OBJS += builtin/pull.o\n BUILTIN_OBJS += builtin/push.o\n BUILTIN_OBJS += builtin/read-tree.o\n+BUILTIN_OBJS += builtin/rebase--interactive2.o\n BUILTIN_OBJS += builtin/rebase--helper.o\n BUILTIN_OBJS += builtin/receive-pack.o\n BUILTIN_OBJS += builtin/reflog.o\ndiff --git a/builtin.h b/builtin.h\nindex 0362f1ce25..ed89b4f495 100644\n--- a/builtin.h\n+++ b/builtin.h\n@@ -202,6 +202,7 @@ extern int cmd_prune_packed(int argc, const char **argv, const char *prefix);\n extern int cmd_pull(int argc, const char **argv, const char *prefix);\n extern int cmd_push(int argc, const char **argv, const char *prefix);\n extern int cmd_read_tree(int argc, const char **argv, const char *prefix);\n+extern int cmd_rebase__interactive(int argc, const char **argv, const char *prefix);\n extern int cmd_rebase__helper(int argc, const char **argv, const char *prefix);\n extern int cmd_receive_pack(int argc, const char **argv, const char *prefix);\n extern int cmd_reflog(int argc, const char **argv, const char *prefix);\ndiff --git a/builtin/rebase--interactive2.c b/builtin/rebase--interactive2.c\nnew file mode 100644\nindex 0000000000..e89ef71499\n--- /dev/null\n+++ b/builtin/rebase--interactive2.c\n@@ -0,0 +1,200 @@\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 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 const char *cmd, 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+\tFILE *todo_list;\n+\n+\tif (prepare_branch_to_be_rebased(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+\ttodo_list = fopen(rebase_path_todo(), \"w\");\n+\tif (!todo_list) {\n+\t\tfree(revisions);\n+\t\tfree(shortrevisions);\n+\n+\t\treturn error_errno(_(\"could not open %s\"), rebase_path_todo());\n+\t}\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(todo_list,\n+\t\t\t\t    make_script_args.argc, make_script_args.argv,\n+\t\t\t\t    flags);\n+\tfclose(todo_list);\n+\n+\tif (ret)\n+\t\terror(_(\"could not generate todo list\"));\n+\telse {\n+\t\tdiscard_cache();\n+\t\tret = complete_action(opts, flags, shortrevisions, onto_name, onto,\n+\t\t\t\t      head_hash, cmd, autosquash);\n+\t}\n+\n+\tfree(revisions);\n+\tfree(shortrevisions);\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;\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+\tchar *raw_strategies = NULL;\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_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\tOPT_STRING('S', \"gpg-sign\", &opts.gpg_sign, N_(\"gpg-sign\"),\n+\t\t\t   N_(\"GPG-sign commits\")),\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_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+\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+\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+\treturn !!do_interactive_rebase(&opts, flags, switch_to, upstream, onto,\n+\t\t\t\t       onto_name, squash_onto, head_name, restrict_revision,\n+\t\t\t\t       raw_strategies, cmd, autosquash);\n+}\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex 761be95ed1..e87d708a4d 100644\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -58,24 +58,27 @@ git_rebase__interactive () {\n \t\treturn 0\n \tfi\n \n-\tgit rebase--helper --prepare-branch \"$switch_to\" ${verbose:+--verbose}\n+\ttest -n \"$keep_empty\" && keep_empty=\"--keep-empty\"\n+\ttest -n \"$rebase_merges\" && rebase_merges=\"--rebase-merges\"\n+\ttest -n \"$rebase_cousins\" && rebase_cousins=\"--rebase-cousins\"\n+\ttest -n \"$autosquash\" && autosquash=\"--autosquash\"\n+\ttest -n \"$verbose\" && verbose=\"--verbose\"\n+\ttest -n \"$force_rebase\" && force_rebase=\"--no-ff\"\n+\ttest -n \"$restrict_revisions\" && restrict_revisions=\"--restrict-revisions=^$restrict_revisions\"\n+\ttest -n \"$upstream\" && upstream=\"--upstream=$upstream\"\n+\ttest -n \"$onto\" && onto=\"--onto=$onto\"\n+\ttest -n \"$squash_onto\" && squash_onto=\"--squash-onto=$squash_onto\"\n+\ttest -n \"$onto_name\" && onto_name=\"--onto-name=$onto_name\"\n+\ttest -n \"$head_name\" && head_name=\"--head-name=$head_name\"\n+\ttest -n \"$strategy\" && strategy=\"--strategy=$strategy\"\n+\ttest -n \"$strategy_opts\" && strategy_opts=\"--strategy-opts=$strategy_opts\"\n+\ttest -n \"$switch_to\" && switch_to=\"--switch-to=$switch_to\"\n+\ttest -n \"$cmd\" && cmd=\"--cmd=$cmd\"\n \n-\tgit rebase--helper --init-basic-state ${upstream:+--upstream \"$upstream\"} \\\n-\t\t${onto:+--onto \"$onto\"} ${head_name:+--head-name \"$head_name\"} \\\n-\t\t${verbose:+--verbose} ${strategy:+--strategy \"$strategy\"} \\\n-\t\t${strategy_opts:+--strategy-opts=\"$strategy_opts\"} \\\n-\t\t\"$allow_rerere_autoupdate\" \"$gpg_sign_opt\" \"$signoff\" || exit\n-\n-\tgit rebase--helper --make-script ${keep_empty:+--keep-empty} \\\n-\t\t${rebase_merges:+--rebase-merges} \\\n-\t\t${rebase_cousins:+--rebase-cousins} \\\n-\t\t${upstream:+--upstream \"$upstream\"} ${onto:+--onto \"$onto\"} \\\n-\t\t${squash_onto:+--squash-onto \"$squash_onto\"} \\\n-\t\t${restrict_revision:+--restrict-revision ^\"$restrict_revision\"} >\"$todo\" ||\n-\tdie \"$(gettext \"Could not generate todo list\")\"\n-\n-\texec git rebase--helper --complete-action \"$onto_name\" \"$cmd\" \\\n-\t\t$allow_empty_message ${autosquash:+--autosquash} ${verbose:+--verbose} \\\n-\t\t${keep_empty:+--keep-empty} ${force_rebase:+--no-ff} \\\n-\t\t${upstream:+--upstream \"$upstream\"} ${onto:+--onto \"$onto\"}\n+\texec git rebase--interactive2 \"$keep_empty\" \"$rebase_merges\" \"$rebase_cousins\" \\\n+\t\t\"$upstream\" \"$onto\" \"$squash_onto\" \"$restrict_revision\" \\\n+\t\t\"$allow_empty_message\" \"$autosquash\" \"$verbose\" \\\n+\t\t\"$force_rebase\" \"$onto_name\" \"$head_name\" \"$strategy\" \\\n+\t\t\"$strategy_opts\" \"$cmd\" \"$switch_to\" \\\n+\t\t\"$allow_rerere_autoupdate\" \"$gpg_sign_opt\" \"$signoff\"\n }\ndiff --git a/git.c b/git.c\nindex 3fded74519..8309fb24a6 100644\n--- a/git.c\n+++ b/git.c\n@@ -518,6 +518,7 @@ static struct cmd_struct commands[] = {\n \t{ \"pull\", cmd_pull, RUN_SETUP | NEED_WORK_TREE },\n \t{ \"push\", cmd_push, RUN_SETUP },\n \t{ \"read-tree\", cmd_read_tree, RUN_SETUP | SUPPORT_SUPER_PREFIX},\n+\t{ \"rebase--interactive2\", cmd_rebase__interactive, RUN_SETUP | NEED_WORK_TREE },\n \t{ \"rebase--helper\", cmd_rebase__helper, RUN_SETUP | NEED_WORK_TREE },\n \t{ \"receive-pack\", cmd_receive_pack },\n \t{ \"reflog\", cmd_reflog, RUN_SETUP },\n-- \n2.18.0\n\n"},{"id":"353488","messageId":"20180724163221.15201-19-alban.gruin@gmail.com","threadId":"48814","inReplyTo":"20180724163221.15201-1-alban.gruin@gmail.com","subject":"[GSoC][PATCH v4 18/20] rebase--interactive2: rewrite the submodes of interactive rebase in C","fromName":"Alban Gruin","fromEmail":"alban.gruin@gmail.com","sentAt":"2018-07-24T16:32:19Z","receivedAt":"2018-07-24T16:34:45Z","isPatch":true,"sender":{"key":"alban.gruin@gmail.com","avatar":"https://avatars.githubusercontent.com/u/6310153?v=4"},"body":"This rewrites the submodes of interactive rebase (`--continue`,\n`--skip`, `--edit-todo`, and `--show-current-patch`) in C.\n\ngit-rebase.sh is then modified to call directly git-rebase--interactive2\ninstead of git-rebase--interactive.sh.\n\nSigned-off-by: Alban Gruin <alban.gruin@gmail.com>\n---\n builtin/rebase--interactive2.c | 47 +++++++++++++++++++++++++++++++---\n git-rebase.sh                  | 45 +++++++++++++++++++++++++++++---\n 2 files changed, 84 insertions(+), 8 deletions(-)\n\ndiff --git a/builtin/rebase--interactive2.c b/builtin/rebase--interactive2.c\nindex e89ef71499..53b4f7483d 100644\n--- a/builtin/rebase--interactive2.c\n+++ b/builtin/rebase--interactive2.c\n@@ -134,11 +134,14 @@ 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;\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 \tchar *raw_strategies = NULL;\n+\tenum {\n+\t\tNONE = 0, CONTINUE, SKIP, EDIT_TODO, SHOW_CURRENT_PATCH\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@@ -151,6 +154,13 @@ int cmd_rebase__interactive(int argc, const char **argv, const char *prefix)\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_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@@ -194,7 +204,36 @@ 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-\treturn !!do_interactive_rebase(&opts, flags, switch_to, upstream, onto,\n-\t\t\t\t       onto_name, squash_onto, head_name, restrict_revision,\n-\t\t\t\t       raw_strategies, cmd, autosquash);\n+\tswitch (command) {\n+\tcase NONE:\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, cmd, autosquash);\n+\t\tbreak;\n+\tcase SKIP: {\n+\t\tstruct string_list merge_rr = STRING_LIST_INIT_DUP;\n+\n+\t\trerere_clear(&merge_rr);\n+\t\t/* fallthrough */\n+\tcase CONTINUE:\n+\t\tret = sequencer_continue(&opts);\n+\t\tbreak;\n+\t}\n+\tcase EDIT_TODO:\n+\t\tret = edit_todo_list(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+\tdefault:\n+\t\tBUG(\"invalid command '%d'\", command);\n+\t}\n+\n+\treturn !!ret;\n }\ndiff --git a/git-rebase.sh b/git-rebase.sh\nindex 86da3816be..65e909d7bd 100755\n--- a/git-rebase.sh\n+++ b/git-rebase.sh\n@@ -200,19 +200,56 @@ finish_rebase () {\n \trm -rf \"$state_dir\"\n }\n \n+run_interactive () {\n+\tGIT_CHERRY_PICK_HELP=\"$resolvemsg\"\n+\texport GIT_CHERRY_PICK_HELP\n+\n+\ttest -n \"$keep_empty\" && keep_empty=\"--keep-empty\"\n+\ttest -n \"$rebase_merges\" && rebase_merges=\"--rebase-merges\"\n+\ttest -n \"$rebase_cousins\" && rebase_cousins=\"--rebase-cousins\"\n+\ttest -n \"$autosquash\" && autosquash=\"--autosquash\"\n+\ttest -n \"$verbose\" && verbose=\"--verbose\"\n+\ttest -n \"$force_rebase\" && force_rebase=\"--no-ff\"\n+\ttest -n \"$restrict_revisions\" && \\\n+\t\trestrict_revisions=\"--restrict-revisions=^$restrict_revisions\"\n+\ttest -n \"$upstream\" && upstream=\"--upstream=$upstream\"\n+\ttest -n \"$onto\" && onto=\"--onto=$onto\"\n+\ttest -n \"$squash_onto\" && squash_onto=\"--squash-onto=$squash_onto\"\n+\ttest -n \"$onto_name\" && onto_name=\"--onto-name=$onto_name\"\n+\ttest -n \"$head_name\" && head_name=\"--head-name=$head_name\"\n+\ttest -n \"$strategy\" && strategy=\"--strategy=$strategy\"\n+\ttest -n \"$strategy_opts\" && strategy_opts=\"--strategy-opts=$strategy_opts\"\n+\ttest -n \"$switch_to\" && switch_to=\"--switch-to=$switch_to\"\n+\ttest -n \"$cmd\" && cmd=\"--cmd=$cmd\"\n+\ttest -n \"$action\" && action=\"--$action\"\n+\n+\texec git rebase--interactive2 \"$action\" \"$keep_empty\" \"$rebase_merges\" \"$rebase_cousins\" \\\n+\t\t\"$upstream\" \"$onto\" \"$squash_onto\" \"$restrict_revision\" \\\n+\t\t\"$allow_empty_message\" \"$autosquash\" \"$verbose\" \\\n+\t\t\"$force_rebase\" \"$onto_name\" \"$head_name\" \"$strategy\" \\\n+\t\t\"$strategy_opts\" \"$cmd\" \"$switch_to\" \\\n+\t\t\"$allow_rerere_autoupdate\" \"$gpg_sign_opt\" \"$signoff\"\n+}\n+\n run_specific_rebase () {\n \tif [ \"$interactive_rebase\" = implied ]; then\n \t\tGIT_EDITOR=:\n \t\texport GIT_EDITOR\n \t\tautosquash=\n \tfi\n-\t. git-rebase--$type\n \n-\tif test -z \"$preserve_merges\"\n+\tif test -n \"$interactive_rebase\" -a -z \"$preserve_merges\"\n \tthen\n-\t\tgit_rebase__$type\n+\t\trun_interactive\n \telse\n-\t\tgit_rebase__preserve_merges\n+\t\t. git-rebase--$type\n+\n+\t\tif test -z \"$preserve_merges\"\n+\t\tthen\n+\t\t\tgit_rebase__$type\n+\t\telse\n+\t\t\tgit_rebase__preserve_merges\n+\t\tfi\n \tfi\n \n \tret=$?\n-- \n2.18.0\n\n"},{"id":"353489","messageId":"20180724163221.15201-20-alban.gruin@gmail.com","threadId":"48814","inReplyTo":"20180724163221.15201-1-alban.gruin@gmail.com","subject":"[GSoC][PATCH v4 19/20] rebase -i: remove git-rebase--interactive.sh","fromName":"Alban Gruin","fromEmail":"alban.gruin@gmail.com","sentAt":"2018-07-24T16:32:20Z","receivedAt":"2018-07-24T16:34:47Z","isPatch":true,"sender":{"key":"alban.gruin@gmail.com","avatar":"https://avatars.githubusercontent.com/u/6310153?v=4"},"body":"This removes git-rebase--interactive.sh, as its functionnality has been\nreplaced by git-rebase--interactive2.\n\ngit-rebase--interactive2.c is then renamed to git-rebase--interactive.c.\n\nSigned-off-by: Alban Gruin <alban.gruin@gmail.com>\n---\n .gitignore                                    |  1 -\n Makefile                                      |  4 +-\n ...--interactive2.c => rebase--interactive.c} |  0\n git-rebase--interactive.sh                    | 84 -------------------\n git-rebase.sh                                 |  2 +-\n git.c                                         |  2 +-\n 6 files changed, 3 insertions(+), 90 deletions(-)\n rename builtin/{rebase--interactive2.c => rebase--interactive.c} (100%)\n delete mode 100644 git-rebase--interactive.sh\n\ndiff --git a/.gitignore b/.gitignore\nindex 404c9a8472..3284a1e9b1 100644\n--- a/.gitignore\n+++ b/.gitignore\n@@ -118,7 +118,6 @@\n /git-rebase--am\n /git-rebase--helper\n /git-rebase--interactive\n-/git-rebase--interactive2\n /git-rebase--merge\n /git-rebase--preserve-merges\n /git-receive-pack\ndiff --git a/Makefile b/Makefile\nindex 71f8f45fe5..584834726d 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -619,7 +619,6 @@ SCRIPT_SH += git-web--browse.sh\n SCRIPT_LIB += git-mergetool--lib\n SCRIPT_LIB += git-parse-remote\n SCRIPT_LIB += git-rebase--am\n-SCRIPT_LIB += git-rebase--interactive\n SCRIPT_LIB += git-rebase--preserve-merges\n SCRIPT_LIB += git-rebase--merge\n SCRIPT_LIB += git-sh-setup\n@@ -1060,8 +1059,8 @@ BUILTIN_OBJS += builtin/prune.o\n BUILTIN_OBJS += builtin/pull.o\n BUILTIN_OBJS += builtin/push.o\n BUILTIN_OBJS += builtin/read-tree.o\n-BUILTIN_OBJS += builtin/rebase--interactive2.o\n BUILTIN_OBJS += builtin/rebase--helper.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\n@@ -2400,7 +2399,6 @@ XGETTEXT_FLAGS_PERL = $(XGETTEXT_FLAGS) --language=Perl \\\n LOCALIZED_C = $(C_OBJ:o=c) $(LIB_H) $(GENERATED_H)\n LOCALIZED_SH = $(SCRIPT_SH)\n LOCALIZED_SH += git-parse-remote.sh\n-LOCALIZED_SH += git-rebase--interactive.sh\n LOCALIZED_SH += git-rebase--preserve-merges.sh\n LOCALIZED_SH += git-sh-setup.sh\n LOCALIZED_PERL = $(SCRIPT_PERL)\ndiff --git a/builtin/rebase--interactive2.c b/builtin/rebase--interactive.c\nsimilarity index 100%\nrename from builtin/rebase--interactive2.c\nrename to builtin/rebase--interactive.c\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\ndeleted file mode 100644\nindex e87d708a4d..0000000000\n--- a/git-rebase--interactive.sh\n+++ /dev/null\n@@ -1,84 +0,0 @@\n-# This shell script fragment is sourced by git-rebase to implement\n-# its interactive mode.  \"git rebase --interactive\" makes it easy\n-# to fix up commits in the middle of a series and rearrange commits.\n-#\n-# Copyright (c) 2006 Johannes E. Schindelin\n-#\n-# The original idea comes from Eric W. Biederman, in\n-# https://public-inbox.org/git/m1odwkyuf5.fsf_-_@ebiederm.dsl.xmission.com/\n-#\n-# The file containing rebase commands, comments, and empty lines.\n-# This file is created by \"git rebase -i\" then edited by the user.  As\n-# the lines are processed, they are removed from the front of this\n-# file and written to the tail of $done.\n-todo=\"$state_dir\"/git-rebase-todo\n-\n-GIT_CHERRY_PICK_HELP=\"$resolvemsg\"\n-export GIT_CHERRY_PICK_HELP\n-\n-# Initiate an action. If the cannot be any\n-# further action it  may exec a command\n-# or exit and not return.\n-#\n-# TODO: Consider a cleaner return model so it\n-# never exits and always return 0 if process\n-# is complete.\n-#\n-# Parameter 1 is the action to initiate.\n-#\n-# Returns 0 if the action was able to complete\n-# and if 1 if further processing is required.\n-initiate_action () {\n-\tcase \"$1\" in\n-\tcontinue)\n-\t\texec git rebase--helper ${force_rebase:+--no-ff} $allow_empty_message \\\n-\t\t     --continue\n-\t\t;;\n-\tskip)\n-\t\tgit rerere clear\n-\t\texec git rebase--helper ${force_rebase:+--no-ff} $allow_empty_message \\\n-\t\t     --continue\n-\t\t;;\n-\tedit-todo)\n-\t\texec git rebase--helper --edit-todo\n-\t\t;;\n-\tshow-current-patch)\n-\t\texec git show REBASE_HEAD --\n-\t\t;;\n-\t*)\n-\t\treturn 1 # continue\n-\t\t;;\n-\tesac\n-}\n-\n-git_rebase__interactive () {\n-\tinitiate_action \"$action\"\n-\tret=$?\n-\tif test $ret = 0; then\n-\t\treturn 0\n-\tfi\n-\n-\ttest -n \"$keep_empty\" && keep_empty=\"--keep-empty\"\n-\ttest -n \"$rebase_merges\" && rebase_merges=\"--rebase-merges\"\n-\ttest -n \"$rebase_cousins\" && rebase_cousins=\"--rebase-cousins\"\n-\ttest -n \"$autosquash\" && autosquash=\"--autosquash\"\n-\ttest -n \"$verbose\" && verbose=\"--verbose\"\n-\ttest -n \"$force_rebase\" && force_rebase=\"--no-ff\"\n-\ttest -n \"$restrict_revisions\" && restrict_revisions=\"--restrict-revisions=^$restrict_revisions\"\n-\ttest -n \"$upstream\" && upstream=\"--upstream=$upstream\"\n-\ttest -n \"$onto\" && onto=\"--onto=$onto\"\n-\ttest -n \"$squash_onto\" && squash_onto=\"--squash-onto=$squash_onto\"\n-\ttest -n \"$onto_name\" && onto_name=\"--onto-name=$onto_name\"\n-\ttest -n \"$head_name\" && head_name=\"--head-name=$head_name\"\n-\ttest -n \"$strategy\" && strategy=\"--strategy=$strategy\"\n-\ttest -n \"$strategy_opts\" && strategy_opts=\"--strategy-opts=$strategy_opts\"\n-\ttest -n \"$switch_to\" && switch_to=\"--switch-to=$switch_to\"\n-\ttest -n \"$cmd\" && cmd=\"--cmd=$cmd\"\n-\n-\texec git rebase--interactive2 \"$keep_empty\" \"$rebase_merges\" \"$rebase_cousins\" \\\n-\t\t\"$upstream\" \"$onto\" \"$squash_onto\" \"$restrict_revision\" \\\n-\t\t\"$allow_empty_message\" \"$autosquash\" \"$verbose\" \\\n-\t\t\"$force_rebase\" \"$onto_name\" \"$head_name\" \"$strategy\" \\\n-\t\t\"$strategy_opts\" \"$cmd\" \"$switch_to\" \\\n-\t\t\"$allow_rerere_autoupdate\" \"$gpg_sign_opt\" \"$signoff\"\n-}\ndiff --git a/git-rebase.sh b/git-rebase.sh\nindex 65e909d7bd..46b8b0f2f0 100755\n--- a/git-rebase.sh\n+++ b/git-rebase.sh\n@@ -223,7 +223,7 @@ run_interactive () {\n \ttest -n \"$cmd\" && cmd=\"--cmd=$cmd\"\n \ttest -n \"$action\" && action=\"--$action\"\n \n-\texec git rebase--interactive2 \"$action\" \"$keep_empty\" \"$rebase_merges\" \"$rebase_cousins\" \\\n+\texec git rebase--interactive \"$action\" \"$keep_empty\" \"$rebase_merges\" \"$rebase_cousins\" \\\n \t\t\"$upstream\" \"$onto\" \"$squash_onto\" \"$restrict_revision\" \\\n \t\t\"$allow_empty_message\" \"$autosquash\" \"$verbose\" \\\n \t\t\"$force_rebase\" \"$onto_name\" \"$head_name\" \"$strategy\" \\\ndiff --git a/git.c b/git.c\nindex 8309fb24a6..19d0b6e3b8 100644\n--- a/git.c\n+++ b/git.c\n@@ -518,7 +518,7 @@ static struct cmd_struct commands[] = {\n \t{ \"pull\", cmd_pull, RUN_SETUP | NEED_WORK_TREE },\n \t{ \"push\", cmd_push, RUN_SETUP },\n \t{ \"read-tree\", cmd_read_tree, RUN_SETUP | SUPPORT_SUPER_PREFIX},\n-\t{ \"rebase--interactive2\", cmd_rebase__interactive, RUN_SETUP | NEED_WORK_TREE },\n+\t{ \"rebase--interactive\", cmd_rebase__interactive, RUN_SETUP | NEED_WORK_TREE },\n \t{ \"rebase--helper\", cmd_rebase__helper, RUN_SETUP | NEED_WORK_TREE },\n \t{ \"receive-pack\", cmd_receive_pack },\n \t{ \"reflog\", cmd_reflog, RUN_SETUP },\n-- \n2.18.0\n\n"},{"id":"353490","messageId":"20180724163221.15201-21-alban.gruin@gmail.com","threadId":"48814","inReplyTo":"20180724163221.15201-1-alban.gruin@gmail.com","subject":"[GSoC][PATCH v4 20/20] rebase -i: move rebase--helper modes to rebase--interactive","fromName":"Alban Gruin","fromEmail":"alban.gruin@gmail.com","sentAt":"2018-07-24T16:32:21Z","receivedAt":"2018-07-24T16:34:49Z","isPatch":true,"sender":{"key":"alban.gruin@gmail.com","avatar":"https://avatars.githubusercontent.com/u/6310153?v=4"},"body":"This moves the rebase--helper modes still used by\ngit-rebase--preserve-merges.sh (`--shorten-ids`, `--expand-ids`,\n`--check-todo-list`, `--rearrange-squash` and `--add-exec-commands`) to\nrebase--interactive.c.\n\ngit-rebase--preserve-merges.sh is modified accordingly, and\nrebase--helper.c is removed as it is useless now.\n\nSigned-off-by: Alban Gruin <alban.gruin@gmail.com>\n---\n .gitignore                     |   1 -\n Makefile                       |   1 -\n builtin/rebase--helper.c       | 226 ---------------------------------\n builtin/rebase--interactive.c  |  27 +++-\n git-rebase--preserve-merges.sh |  10 +-\n git.c                          |   1 -\n 6 files changed, 31 insertions(+), 235 deletions(-)\n delete mode 100644 builtin/rebase--helper.c\n\ndiff --git a/.gitignore b/.gitignore\nindex 3284a1e9b1..406f26d050 100644\n--- a/.gitignore\n+++ b/.gitignore\n@@ -116,7 +116,6 @@\n /git-read-tree\n /git-rebase\n /git-rebase--am\n-/git-rebase--helper\n /git-rebase--interactive\n /git-rebase--merge\n /git-rebase--preserve-merges\ndiff --git a/Makefile b/Makefile\nindex 584834726d..ca3a0888dd 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -1059,7 +1059,6 @@ BUILTIN_OBJS += builtin/prune.o\n BUILTIN_OBJS += builtin/pull.o\n BUILTIN_OBJS += builtin/push.o\n BUILTIN_OBJS += builtin/read-tree.o\n-BUILTIN_OBJS += builtin/rebase--helper.o\n BUILTIN_OBJS += builtin/rebase--interactive.o\n BUILTIN_OBJS += builtin/receive-pack.o\n BUILTIN_OBJS += builtin/reflog.o\ndiff --git a/builtin/rebase--helper.c b/builtin/rebase--helper.c\ndeleted file mode 100644\nindex ac21e8e06e..0000000000\n--- a/builtin/rebase--helper.c\n+++ /dev/null\n@@ -1,226 +0,0 @@\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 \"alias.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 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;\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-\n-\tif (revisions)\n-\t\t*revisions = xstrfmt(\"%s...%s\", base_rev, *head_hash);\n-\tif (shortrevisions) {\n-\t\tconst char *shorthead;\n-\n-\t\tshorthead = find_unique_abbrev(&orig_head, DEFAULT_ABBREV);\n-\n-\t\tif (upstream) {\n-\t\t\tconst char *shortrev;\n-\t\t\tstruct object_id rev_oid;\n-\n-\t\t\tget_oid(base_rev, &rev_oid);\n-\t\t\tshortrev = find_unique_abbrev(&rev_oid, DEFAULT_ABBREV);\n-\n-\t\t\t*shortrevisions = xstrfmt(\"%s..%s\", shortrev, shorthead);\n-\t\t} else\n-\t\t\t*shortrevisions = xstrdup(shorthead);\n-\t}\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 const char * const builtin_rebase_helper_usage[] = {\n-\tN_(\"git rebase--helper [<options>]\"),\n-\tNULL\n-};\n-\n-int cmd_rebase__helper(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;\n-\tconst char *head_hash = NULL, *onto = NULL, *restrict_revision = NULL,\n-\t\t*squash_onto = NULL, *upstream = NULL, *head_name = NULL;\n-\tchar *raw_strategies = NULL;\n-\tenum {\n-\t\tCONTINUE = 1, ABORT, MAKE_SCRIPT, SHORTEN_OIDS, EXPAND_OIDS,\n-\t\tCHECK_TODO_LIST, REARRANGE_SQUASH, ADD_EXEC, EDIT_TODO, PREPARE_BRANCH,\n-\t\tCOMPLETE_ACTION, INIT_BASIC_STATE\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\tN_(\"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 thas 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\tCONTINUE),\n-\t\tOPT_CMDMODE(0, \"abort\", &command, N_(\"abort rebase\"),\n-\t\t\t\tABORT),\n-\t\tOPT_CMDMODE(0, \"make-script\", &command,\n-\t\t\tN_(\"make rebase script\"), MAKE_SCRIPT),\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_CMDMODE(0, \"edit-todo\", &command,\n-\t\t\t    N_(\"edit the todo list during an interactive rebase\"),\n-\t\t\t    EDIT_TODO),\n-\t\tOPT_CMDMODE(0, \"prepare-branch\", &command,\n-\t\t\t    N_(\"prepare the branch to be rebased\"), PREPARE_BRANCH),\n-\t\tOPT_CMDMODE(0, \"complete-action\", &command,\n-\t\t\t    N_(\"complete the action\"), COMPLETE_ACTION),\n-\t\tOPT_CMDMODE(0, \"init-basic-state\", &command,\n-\t\t\t    N_(\"initialise the rebase state\"), INIT_BASIC_STATE),\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\tOPT_STRING('S', \"gpg-sign\", &opts.gpg_sign, N_(\"gpg-sign\"),\n-\t\t\t   N_(\"GPG-sign commits\")),\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_RERERE_AUTOUPDATE(&opts.allow_rerere_auto),\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-\targc = parse_options(argc, argv, NULL, options,\n-\t\t\tbuiltin_rebase_helper_usage, PARSE_OPT_KEEP_ARGV0);\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 (command == CONTINUE && argc == 1)\n-\t\treturn !!sequencer_continue(&opts);\n-\tif (command == ABORT && argc == 1)\n-\t\treturn !!sequencer_remove_state(&opts);\n-\tif (command == MAKE_SCRIPT && argc == 1) {\n-\t\tchar *revisions = NULL;\n-\t\tstruct argv_array make_script_args = ARGV_ARRAY_INIT;\n-\n-\t\tif (!upstream && squash_onto)\n-\t\t\twrite_file(path_squash_onto(), \"%s\\n\", squash_onto);\n-\n-\t\tret = get_revision_ranges(upstream, onto, &head_hash, &revisions, NULL);\n-\t\tif (ret)\n-\t\t\treturn ret;\n-\n-\t\targv_array_pushl(&make_script_args, \"\", revisions, NULL);\n-\t\tif (restrict_revision)\n-\t\t\targv_array_push(&make_script_args, restrict_revision);\n-\n-\t\tret = sequencer_make_script(stdout,\n-\t\t\t\t\t    make_script_args.argc, make_script_args.argv,\n-\t\t\t\t\t    flags);\n-\n-\t\tfree(revisions);\n-\t\targv_array_clear(&make_script_args);\n-\n-\t\treturn !!ret;\n-\t}\n-\tif ((command == SHORTEN_OIDS || command == EXPAND_OIDS) && argc == 1)\n-\t\treturn !!transform_todos(flags);\n-\tif (command == CHECK_TODO_LIST && argc == 1)\n-\t\treturn !!check_todo_list();\n-\tif (command == REARRANGE_SQUASH && argc == 1)\n-\t\treturn !!rearrange_squash();\n-\tif (command == ADD_EXEC && argc == 2)\n-\t\treturn !!sequencer_add_exec_commands(argv[1]);\n-\tif (command == EDIT_TODO && argc == 1)\n-\t\treturn !!edit_todo_list(flags);\n-\tif (command == PREPARE_BRANCH && argc == 2)\n-\t\treturn !!prepare_branch_to_be_rebased(&opts, argv[1]);\n-\tif (command == COMPLETE_ACTION && argc == 3) {\n-\t\tchar *shortrevisions = NULL;\n-\n-\t\tret = get_revision_ranges(upstream, onto, &head_hash, NULL, &shortrevisions);\n-\t\tif (ret)\n-\t\t\treturn ret;\n-\n-\t\tret = complete_action(&opts, flags, shortrevisions, argv[1], onto,\n-\t\t\t\t      head_hash, argv[2], autosquash);\n-\n-\t\tfree(shortrevisions);\n-\t\treturn !!ret;\n-\t}\n-\tif (command == INIT_BASIC_STATE) {\n-\t\tif (raw_strategies)\n-\t\t\tparse_strategy_opts(&opts, raw_strategies);\n-\n-\t\tret = get_revision_ranges(upstream, onto, &head_hash, NULL, NULL);\n-\t\tif (ret)\n-\t\t\treturn ret;\n-\n-\t\treturn !!init_basic_state(&opts, head_name, onto, head_hash);\n-\t}\n-\n-\tusage_with_options(builtin_rebase_helper_usage, options);\n-}\ndiff --git a/builtin/rebase--interactive.c b/builtin/rebase--interactive.c\nindex 53b4f7483d..1e1756f1e8 100644\n--- a/builtin/rebase--interactive.c\n+++ b/builtin/rebase--interactive.c\n@@ -140,7 +140,8 @@ int cmd_rebase__interactive(int argc, const char **argv, const char *prefix)\n \t\t*switch_to = NULL, *cmd = NULL;\n \tchar *raw_strategies = NULL;\n \tenum {\n-\t\tNONE = 0, CONTINUE, SKIP, EDIT_TODO, SHOW_CURRENT_PATCH\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@@ -161,6 +162,16 @@ int cmd_rebase__interactive(int argc, const char **argv, const char *prefix)\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@@ -199,6 +210,7 @@ int cmd_rebase__interactive(int argc, const char **argv, const char *prefix)\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@@ -231,6 +243,19 @@ 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+\t\tret = transform_todos(flags);\n+\t\tbreak;\n+\tcase CHECK_TODO_LIST:\n+\t\tret = check_todo_list();\n+\t\tbreak;\n+\tcase REARRANGE_SQUASH:\n+\t\tret = rearrange_squash();\n+\t\tbreak;\n+\tcase ADD_EXEC:\n+\t\tret = sequencer_add_exec_commands(cmd);\n+\t\tbreak;\n \tdefault:\n \t\tBUG(\"invalid command '%d'\", command);\n \t}\ndiff --git a/git-rebase--preserve-merges.sh b/git-rebase--preserve-merges.sh\nindex c51c7828e7..d43b4b582e 100644\n--- a/git-rebase--preserve-merges.sh\n+++ b/git-rebase--preserve-merges.sh\n@@ -711,11 +711,11 @@ do_rest () {\n }\n \n expand_todo_ids() {\n-\tgit rebase--helper --expand-ids\n+\tgit rebase--interactive --expand-ids\n }\n \n collapse_todo_ids() {\n-\tgit rebase--helper --shorten-ids\n+\tgit rebase--interactive --shorten-ids\n }\n \n # Switch to the branch in $into and notify it in the reflog\n@@ -876,8 +876,8 @@ init_revisions_and_shortrevisions () {\n \n complete_action() {\n \ttest -s \"$todo\" || echo noop >> \"$todo\"\n-\ttest -z \"$autosquash\" || git rebase--helper --rearrange-squash || exit\n-\ttest -n \"$cmd\" && git rebase--helper --add-exec-commands \"$cmd\"\n+\ttest -z \"$autosquash\" || git rebase--interactive --rearrange-squash || exit\n+\ttest -n \"$cmd\" && git rebase--interactive --add-exec-commands --cmd \"$cmd\"\n \n \ttodocount=$(git stripspace --strip-comments <\"$todo\" | wc -l)\n \ttodocount=${todocount##* }\n@@ -912,7 +912,7 @@ EOF\n \thas_action \"$todo\" ||\n \t\treturn 2\n \n-\tgit rebase--helper --check-todo-list || {\n+\tgit rebase--interactive --check-todo-list || {\n \t\tret=$?\n \t\tcheckout_onto\n \t\texit $ret\ndiff --git a/git.c b/git.c\nindex 19d0b6e3b8..81aabd1423 100644\n--- a/git.c\n+++ b/git.c\n@@ -519,7 +519,6 @@ static struct cmd_struct commands[] = {\n \t{ \"push\", cmd_push, RUN_SETUP },\n \t{ \"read-tree\", cmd_read_tree, RUN_SETUP | SUPPORT_SUPER_PREFIX},\n \t{ \"rebase--interactive\", cmd_rebase__interactive, RUN_SETUP | NEED_WORK_TREE },\n-\t{ \"rebase--helper\", cmd_rebase__helper, RUN_SETUP | NEED_WORK_TREE },\n \t{ \"receive-pack\", cmd_receive_pack },\n \t{ \"reflog\", cmd_reflog, RUN_SETUP },\n \t{ \"remote\", cmd_remote, RUN_SETUP },\n-- \n2.18.0\n\n"},{"id":"353584","messageId":"CAGZ79kbjy5aXbtThLU7odd15Gf5WZ3c3RGDgxfpcBEh7UnJqoA@mail.gmail.com","threadId":"48814","inReplyTo":"20180724163221.15201-1-alban.gruin@gmail.com","subject":"Re: [GSoC][PATCH v4 00/20] rebase -i: rewrite in C","fromName":"Stefan Beller","fromEmail":"sbeller@google.com","sentAt":"2018-07-25T18:45:28Z","receivedAt":"2018-07-25T18:45:41Z","isPatch":true,"sender":{"key":"stefanbeller@gmail.com","avatar":"https://avatars.githubusercontent.com/u/455868?v=4"},"body":"On Tue, Jul 24, 2018 at 9:34 AM Alban Gruin <alban.gruin@gmail.com> wrote:\n>\n> This patch series rewrite the interactive rebase from shell to C.\n>\n> It is based on master (as of 2018-07-24).\n>\n> Changes since v3:\n>\n>  - The `--verbose` option is stored directly into opts.verbose\n>\n>  - Drop includes in rebase-interactive.h\n>\n>  - skip_unnecessary_picks() now returns an object_id instead of a string\n>\n>  - Add a test case to ensure interactive rebase aborts when the todo\n>    list only has commented-out commands\n>\n>  - complete_action() aborts when the todo list only has commented-out\n>    commands\n>\n>  - Drop the `keep_empty` parameter of complete_action()\n>\n>  - Don’t remove the modes `--shorten-oids` and `--expand-oids` from\n>    git-rebase--helper\n>\n>  - Replace `ret = !!x(); return ret` by `ret = x(); return !!ret`\n>\n>  - Fail if `--make-script` is provided with two arguments instead of\n>    one\n>\n>  - Rewrite write_basic_state() and init_basic_state() in C\n>\n>  - Rewrite git-rebase--interactive.sh as a builtin\n>\n\nI gave that series a read and I think it looks good.\n\nThanks,\nStefan\n"},{"id":"353598","messageId":"xmqq8t5zszqd.fsf@gitster-ct.c.googlers.com","threadId":"48814","inReplyTo":"20180724163221.15201-1-alban.gruin@gmail.com","subject":"Re: [GSoC][PATCH v4 00/20] rebase -i: rewrite in C","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2018-07-25T22:43:38Z","receivedAt":"2018-07-25T22:43:44Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Alban Gruin <alban.gruin@gmail.com> writes:\n\n> This patch series rewrite the interactive rebase from shell to C.\n>\n> It is based on master (as of 2018-07-24).\n\nWith fewer number of bytes than \"as of ....\", you can express it in\na more useful way, even when you and others live in different\ntimezones and when the 'master' branch is updated more than once in\nthe 24-hour period.\n\nI think you based it on b7bd9486 (\"Third batch for 2.19 cycle\",\n2018-07-18), so you can say so\n\n\tIt is based on b7bd9486 (\"Third batch for 2.19 cycle\",\n\t2018-07-18).\n\nwith a bit more bytes for the subject and be more informative.\n\nWhen you rebase your series, please explain why you needed to do so\nin your cover letter.  \"I just wanted to catch up with the latest\n'master'\" is not a good enough reason.  \"I wanted to make sure my\nseries works well with X and Y that the base of my previous attempt\ndid not have.\" is a very good reason.\n\nI think the rebase this round is warranted, if it was done to take\nadvantage of the fix made by Elijah to the code that handles the\n\"strategy\" option in 0060041d (\"Fix use of strategy options with\ninteractive rebases\", 2018-06-27), in other words, you wanted to\nstart from the version of read_strategy_opts() Elijah fixed when\nyou split parse_strategy_opts() out of it in step [15/20].\n\nI'll send comments on individual patches separately.  \n\nThanks.\n\n"},{"id":"353927","messageId":"20180730182516.32644-1-szeder.dev@gmail.com","threadId":"48814","inReplyTo":"20180724163221.15201-16-alban.gruin@gmail.com","subject":"Re: [GSoC][PATCH v4 15/20] rebase -i: rewrite write_basic_state() in C","fromName":"SZEDER Gábor","fromEmail":"szeder.dev@gmail.com","sentAt":"2018-07-30T18:25:16Z","receivedAt":"2018-07-30T18:25:29Z","isPatch":true,"sender":{"key":"szeder.dev@gmail.com","avatar":"https://avatars.githubusercontent.com/u/116324?v=4"},"body":"> diff --git a/sequencer.c b/sequencer.c\n> index 1c035ceec7..d257903db0 100644\n> --- a/sequencer.c\n> +++ b/sequencer.c\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> +{\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> +\tif (orig_head)\n> +\t\twrite_file(rebase_path_orig_head(), \"%s\\n\", orig_head);\n> +\n> +\tif (quiet)\n> +\t\twrite_file(rebase_path_quiet(), \"%s\\n\", quiet);\n> +\telse\n> +\t\twrite_file(rebase_path_quiet(), \"\");\n\nThis is not a faithful conversion of the original.  git-rebase.sh writes\nthis 'quiet' file with:\n\n  echo \"$GIT_QUIET\" > \"$state_dir\"/quiet\n\nwhich means that a single newline character was written even when\n$GIT_QUIET was unset/empty.\n\nI seem to recall a case in the past, when a shell-to-C conversion\naccidentally dropped a newline from a similar state-file, which then\ncaused some issues later on.  But I don't remember the specifics and a\nquick search didn't turn up anything relevant either...\n\n> +\n> +\tif (opts->verbose)\n> +\t\twrite_file(rebase_path_verbose(), \"\");\n> +\tif (opts->strategy)\n> +\t\twrite_file(rebase_path_strategy(), \"%s\\n\", opts->strategy);\n> +\tif (opts->xopts_nr > 0)\n> +\t\twrite_strategy_opts(opts);\n> +\n> +\tif (opts->allow_rerere_auto == RERERE_AUTOUPDATE)\n> +\t\twrite_file(rebase_path_allow_rerere_autoupdate(), \"--rerere-autoupdate\\n\");\n> +\telse if (opts->allow_rerere_auto == RERERE_NOAUTOUPDATE)\n> +\t\twrite_file(rebase_path_allow_rerere_autoupdate(), \"--no-rerere-autoupdate\\n\");\n> +\n> +\tif (opts->gpg_sign)\n> +\t\twrite_file(rebase_path_gpg_sign_opt(), \"-S%s\\n\", opts->gpg_sign);\n> +\tif (opts->signoff)\n> +\t\twrite_file(rebase_path_signoff(), \"--signoff\\n\");\n> +\n> +\treturn 0;\n> +}\n> +\n>  static int walk_revs_populate_todo(struct todo_list *todo_list,\n>  \t\t\t\tstruct replay_opts *opts)\n>  {\n"},{"id":"353967","messageId":"615c2b9d-7a1b-7678-4173-7eb3db193296@gmail.com","threadId":"48814","inReplyTo":"20180730182516.32644-1-szeder.dev@gmail.com","subject":"Re: [GSoC][PATCH v4 15/20] rebase -i: rewrite write_basic_state() in C","fromName":"Alban Gruin","fromEmail":"alban.gruin@gmail.com","sentAt":"2018-07-30T22:11:52Z","receivedAt":"2018-07-30T22:12:04Z","isPatch":true,"sender":{"key":"alban.gruin@gmail.com","avatar":"https://avatars.githubusercontent.com/u/6310153?v=4"},"body":"Hi,\n\nLe 30/07/2018 à 20:25, SZEDER Gábor a écrit :\n>> diff --git a/sequencer.c b/sequencer.c\n>> index 1c035ceec7..d257903db0 100644\n>> --- a/sequencer.c\n>> +++ b/sequencer.c\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>> +{\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>> +\tif (orig_head)\n>> +\t\twrite_file(rebase_path_orig_head(), \"%s\\n\", orig_head);\n>> +\n>> +\tif (quiet)\n>> +\t\twrite_file(rebase_path_quiet(), \"%s\\n\", quiet);\n>> +\telse\n>> +\t\twrite_file(rebase_path_quiet(), \"\");\n> \n> This is not a faithful conversion of the original.  git-rebase.sh writes\n> this 'quiet' file with:\n> \n>   echo \"$GIT_QUIET\" > \"$state_dir\"/quiet\n> \n> which means that a single newline character was written even when\n> $GIT_QUIET was unset/empty.\n> \n> I seem to recall a case in the past, when a shell-to-C conversion\n> accidentally dropped a newline from a similar state-file, which then\n> caused some issues later on.  But I don't remember the specifics and a\n> quick search didn't turn up anything relevant either...\n> \n\nI don’t think it’s a problem here, but we’re better safe than sorry.\nI’ll send a fix soon.\n\nCheers,\nAlban\n\n"},{"id":"354019","messageId":"20180731121115.12296-1-alban.gruin@gmail.com","threadId":"48814","inReplyTo":"20180730182516.32644-1-szeder.dev@gmail.com","subject":"[GSoC][PATCH v4] fixup! rebase -i: rewrite write_basic_state() in C","fromName":"Alban Gruin","fromEmail":"alban.gruin@gmail.com","sentAt":"2018-07-31T12:11:15Z","receivedAt":"2018-07-31T12:11:29Z","isPatch":true,"sender":{"key":"alban.gruin@gmail.com","avatar":"https://avatars.githubusercontent.com/u/6310153?v=4"},"body":"As pointed out by SZEDER Gábor, git-rebase.sh wrote to to 'quiet' with\nan `echo`:\n\n    echo \"$GIT_QUIET\" > \"$state_dir/quiet\"\n\nThis mean that even if $GIT_QUIET is empty, a newline is written to\nquiet.  The rewrite of write_basic_state() changed this behaviour, which\ncould lead to problems.  This patch changes the rewritten version to\nbehave like the shell version.\n\nSigned-off-by: Alban Gruin <alban.gruin@gmail.com>\n---\nHi Junio, could you apply this patch on top of ag/rebase-i-in-c, please?\n\n sequencer.c | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)\n\ndiff --git a/sequencer.c b/sequencer.c\nindex d257903db0..0d41e82953 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -2332,7 +2332,7 @@ int write_basic_state(struct replay_opts *opts, const char *head_name,\n \tif (quiet)\n \t\twrite_file(rebase_path_quiet(), \"%s\\n\", quiet);\n \telse\n-\t\twrite_file(rebase_path_quiet(), \"\");\n+\t\twrite_file(rebase_path_quiet(), \"\\n\");\n \n \tif (opts->verbose)\n \t\twrite_file(rebase_path_verbose(), \"\");\n-- \n2.18.0\n\n"},{"id":"354044","messageId":"xmqqy3drctu4.fsf@gitster-ct.c.googlers.com","threadId":"48814","inReplyTo":"20180731121115.12296-1-alban.gruin@gmail.com","subject":"Re: [GSoC][PATCH v4] fixup! rebase -i: rewrite write_basic_state() in C","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2018-07-31T15:23:31Z","receivedAt":"2018-07-31T15:23:36Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Alban Gruin <alban.gruin@gmail.com> writes:\n\n> As pointed out by SZEDER Gábor, git-rebase.sh wrote to to 'quiet' with\n> an `echo`:\n>\n>     echo \"$GIT_QUIET\" > \"$state_dir/quiet\"\n>\n> This mean that even if $GIT_QUIET is empty, a newline is written to\n> quiet.  The rewrite of write_basic_state() changed this behaviour, which\n> could lead to problems.  This patch changes the rewritten version to\n> behave like the shell version.\n>\n> Signed-off-by: Alban Gruin <alban.gruin@gmail.com>\n> ---\n> Hi Junio, could you apply this patch on top of ag/rebase-i-in-c, please?\n\nHmph, from reading your other message\n\n  https://public-inbox.org/git/dce8c99b-51e9-4ed1-8ae4-28049cb6e7ec@gmail.com/\n\nI got an impression that a rerolled version is coming anyway.  Is\nthis fix so urgent that it needs tobe squashed in in the meantime\nand cannot wait?\n\n>\n>  sequencer.c | 2 +-\n>  1 file changed, 1 insertion(+), 1 deletion(-)\n>\n> diff --git a/sequencer.c b/sequencer.c\n> index d257903db0..0d41e82953 100644\n> --- a/sequencer.c\n> +++ b/sequencer.c\n> @@ -2332,7 +2332,7 @@ int write_basic_state(struct replay_opts *opts, const char *head_name,\n>  \tif (quiet)\n>  \t\twrite_file(rebase_path_quiet(), \"%s\\n\", quiet);\n>  \telse\n> -\t\twrite_file(rebase_path_quiet(), \"\");\n> +\t\twrite_file(rebase_path_quiet(), \"\\n\");\n>  \n>  \tif (opts->verbose)\n>  \t\twrite_file(rebase_path_verbose(), \"\");\n"},{"id":"354049","messageId":"ad8fe398-6e7b-b50f-df96-35ac06049020@gmail.com","threadId":"48814","inReplyTo":"xmqqy3drctu4.fsf@gitster-ct.c.googlers.com","subject":"Re: [GSoC][PATCH v4] fixup! rebase -i: rewrite write_basic_state() in C","fromName":"Alban Gruin","fromEmail":"alban.gruin@gmail.com","sentAt":"2018-07-31T15:59:49Z","receivedAt":"2018-07-31T16:00:09Z","isPatch":true,"sender":{"key":"alban.gruin@gmail.com","avatar":"https://avatars.githubusercontent.com/u/6310153?v=4"},"body":"Hi Junio,\n\nLe 31/07/2018 à 17:23, Junio C Hamano a écrit :\n> Alban Gruin <alban.gruin@gmail.com> writes:\n> \n>> As pointed out by SZEDER Gábor, git-rebase.sh wrote to to 'quiet' with\n>> an `echo`:\n>>\n>>     echo \"$GIT_QUIET\" > \"$state_dir/quiet\"\n>>\n>> This mean that even if $GIT_QUIET is empty, a newline is written to\n>> quiet.  The rewrite of write_basic_state() changed this behaviour, which\n>> could lead to problems.  This patch changes the rewritten version to\n>> behave like the shell version.\n>>\n>> Signed-off-by: Alban Gruin <alban.gruin@gmail.com>\n>> ---\n>> Hi Junio, could you apply this patch on top of ag/rebase-i-in-c, please?\n> \n> Hmph, from reading your other message\n> \n>   https://public-inbox.org/git/dce8c99b-51e9-4ed1-8ae4-28049cb6e7ec@gmail.com/\n> \n> I got an impression that a rerolled version is coming anyway.  Is\n> this fix so urgent that it needs tobe squashed in in the meantime\n> and cannot wait?\n> \n\nI wanted to reroll it first, but the only changes would have been this\nfix and Ramsay’s patch.  I was advised to send a fixup! patch instead.\n\nI can send a reroll if you want, but it won’t have any more changes.\n\nCheers,\nAlban\n\n\n>>\n>>  sequencer.c | 2 +-\n>>  1 file changed, 1 insertion(+), 1 deletion(-)\n>>\n>> diff --git a/sequencer.c b/sequencer.c\n>> index d257903db0..0d41e82953 100644\n>> --- a/sequencer.c\n>> +++ b/sequencer.c\n>> @@ -2332,7 +2332,7 @@ int write_basic_state(struct replay_opts *opts, const char *head_name,\n>>  \tif (quiet)\n>>  \t\twrite_file(rebase_path_quiet(), \"%s\\n\", quiet);\n>>  \telse\n>> -\t\twrite_file(rebase_path_quiet(), \"\");\n>> +\t\twrite_file(rebase_path_quiet(), \"\\n\");\n>>  \n>>  \tif (opts->verbose)\n>>  \t\twrite_file(rebase_path_verbose(), \"\");\n\n"},{"id":"354051","messageId":"xmqqpnz3cry6.fsf@gitster-ct.c.googlers.com","threadId":"48814","inReplyTo":"ad8fe398-6e7b-b50f-df96-35ac06049020@gmail.com","subject":"Re: [GSoC][PATCH v4] fixup! rebase -i: rewrite write_basic_state() in C","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2018-07-31T16:04:17Z","receivedAt":"2018-07-31T16:04:22Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Alban Gruin <alban.gruin@gmail.com> writes:\n\n>> Hmph, from reading your other message\n>> \n>>   https://public-inbox.org/git/dce8c99b-51e9-4ed1-8ae4-28049cb6e7ec@gmail.com/\n>> \n>> I got an impression that a rerolled version is coming anyway.  Is\n>> this fix so urgent that it needs tobe squashed in in the meantime\n>> and cannot wait?\n>> \n>\n> I wanted to reroll it first, but the only changes would have been this\n> fix and Ramsay’s patch.  I was advised to send a fixup! patch instead.\n>\n> I can send a reroll if you want, but it won’t have any more changes.\n\nThen please do send an updated one with v$n incremented.\n\nAs the number of his or her own topics each contributor needs to\nkeep track of by definition is the number of all topics I need to\ntake care of, I do not want to have to keep track of things myself\nmore than necessary, which would result in missed fixups and delayed\nupdates.\n\n\n"},{"id":"354067","messageId":"xmqqd0v3co6c.fsf@gitster-ct.c.googlers.com","threadId":"48814","inReplyTo":"xmqqpnz3cry6.fsf@gitster-ct.c.googlers.com","subject":"Re: [GSoC][PATCH v4] fixup! rebase -i: rewrite write_basic_state() in C","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2018-07-31T17:25:47Z","receivedAt":"2018-07-31T17:25:51Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Junio C Hamano <gitster@pobox.com> writes:\n\n> As the number of his or her own topics each contributor needs to\n> keep track of by definition is the number of all topics I need to\n\ns/is the/is smaller than the/;\n\nSorry for the noise X-<.\n\n> take care of, I do not want to have to keep track of things myself\n> more than necessary, which would result in missed fixups and delayed\n> updates.\n"},{"id":"354075","messageId":"20180731180003.5421-1-alban.gruin@gmail.com","threadId":"48814","inReplyTo":"20180724163221.15201-1-alban.gruin@gmail.com","subject":"[GSoC][PATCH v5 00/20] rebase -i: rewrite in C","fromName":"Alban Gruin","fromEmail":"alban.gruin@gmail.com","sentAt":"2018-07-31T17:59:43Z","receivedAt":"2018-07-31T18:00:21Z","isPatch":true,"sender":{"key":"alban.gruin@gmail.com","avatar":"https://avatars.githubusercontent.com/u/6310153?v=4"},"body":"This patch series rewrite the interactive rebase from shell to C.\n\nIt is based on ffc6fa0e39 (\"Fourth batch for 2.19 cycle\", 2018-07-24).\nThe v4 was based on b7bd9486 (\"Third batch for 2.19 cycle\", 2018-07-18).\nI wanted to make sure my series works well with 'bb/pedantic',\n'jk/empty-pick-fix', and 'as/sequencer-customizable-comment-char', as\nthey modified sequencer.c.\n\nChanges since v4:\n\n - [15/20] Add a newline char to $state_dir/quiet in write_basic_state(), even\n   if $GIT_QUIET is not set\n\n - [20/20] Remove the declaration of cmd_rebase__helper() in builtin.h\n\nAlban Gruin (20):\n  sequencer: make two functions and an enum from sequencer.c public\n  rebase -i: rewrite append_todo_help() in C\n  editor: add a function to launch the sequence editor\n  rebase -i: rewrite the edit-todo functionality in C\n  sequencer: add a new function to silence a command, except if it fails\n  rebase -i: rewrite setup_reflog_action() in C\n  rebase -i: rewrite checkout_onto() in C\n  sequencer: refactor append_todo_help() to write its message to a\n    buffer\n  sequencer: change the way skip_unnecessary_picks() returns its result\n  t3404: todo list with commented-out commands only aborts\n  rebase -i: rewrite complete_action() in C\n  rebase -i: remove unused modes and functions\n  rebase -i: implement the logic to initialize $revisions in C\n  rebase -i: rewrite the rest of init_revisions_and_shortrevisions() in\n    C\n  rebase -i: rewrite write_basic_state() in C\n  rebase -i: rewrite init_basic_state() in C\n  rebase -i: implement the main part of interactive rebase as a builtin\n  rebase--interactive2: rewrite the submodes of interactive rebase in C\n  rebase -i: remove git-rebase--interactive.sh\n  rebase -i: move rebase--helper modes to rebase--interactive\n\n .gitignore                     |   1 -\n Makefile                       |   5 +-\n builtin.h                      |   2 +-\n builtin/rebase--helper.c       |  88 ----------\n builtin/rebase--interactive.c  | 264 ++++++++++++++++++++++++++++\n cache.h                        |   1 +\n editor.c                       |  27 ++-\n git-rebase--interactive.sh     | 283 ------------------------------\n git-rebase--preserve-merges.sh |  10 +-\n git-rebase.sh                  |  47 ++++-\n git.c                          |   2 +-\n rebase-interactive.c           |  96 ++++++++++\n rebase-interactive.h           |   8 +\n sequencer.c                    | 311 +++++++++++++++++++++++++++------\n sequencer.h                    |  19 +-\n strbuf.h                       |   2 +\n t/t3404-rebase-interactive.sh  |  10 ++\n 17 files changed, 729 insertions(+), 447 deletions(-)\n delete mode 100644 builtin/rebase--helper.c\n create mode 100644 builtin/rebase--interactive.c\n delete mode 100644 git-rebase--interactive.sh\n create mode 100644 rebase-interactive.c\n create mode 100644 rebase-interactive.h\n\n-- \n2.18.0\n\n"},{"id":"354076","messageId":"20180731180003.5421-2-alban.gruin@gmail.com","threadId":"48814","inReplyTo":"20180731180003.5421-1-alban.gruin@gmail.com","subject":"[GSoC][PATCH v5 01/20] sequencer: make two functions and an enum from sequencer.c public","fromName":"Alban Gruin","fromEmail":"alban.gruin@gmail.com","sentAt":"2018-07-31T17:59:44Z","receivedAt":"2018-07-31T18:00:23Z","isPatch":true,"sender":{"key":"alban.gruin@gmail.com","avatar":"https://avatars.githubusercontent.com/u/6310153?v=4"},"body":"This makes rebase_path_todo(), get_missing_commit_check_level() and the\nenum check_level accessible outside sequencer.c, renames check_level to\nmissing_commit_check_level, and prefixes its value names by\nMISSING_COMMIT_ to avoid namespace pollution.\n\nThis function and this enum will eventually be moved to\nrebase-interactive.c and become static again, so no special attention\nwas given to the naming.\n\nThis will be needed for the rewrite of append_todo_help() from shell to\nC, as it will be in a new library source file, rebase-interactive.c.\n\nSigned-off-by: Alban Gruin <alban.gruin@gmail.com>\n---\nNo changes since v4.\n\n sequencer.c | 22 +++++++++-------------\n sequencer.h |  8 ++++++++\n 2 files changed, 17 insertions(+), 13 deletions(-)\n\ndiff --git a/sequencer.c b/sequencer.c\nindex 16c1411054..8eff526584 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -52,7 +52,7 @@ static GIT_PATH_FUNC(rebase_path, \"rebase-merge\")\n  * the lines are processed, they are removed from the front of this\n  * file and written to the tail of 'done'.\n  */\n-static GIT_PATH_FUNC(rebase_path_todo, \"rebase-merge/git-rebase-todo\")\n+GIT_PATH_FUNC(rebase_path_todo, \"rebase-merge/git-rebase-todo\")\n /*\n  * The rebase command lines that have already been processed. A line\n  * is moved here when it is first handled, before any associated user\n@@ -4249,24 +4249,20 @@ int transform_todos(unsigned flags)\n \treturn i;\n }\n \n-enum check_level {\n-\tCHECK_IGNORE = 0, CHECK_WARN, CHECK_ERROR\n-};\n-\n-static enum check_level get_missing_commit_check_level(void)\n+enum missing_commit_check_level get_missing_commit_check_level(void)\n {\n \tconst char *value;\n \n \tif (git_config_get_value(\"rebase.missingcommitscheck\", &value) ||\n \t\t\t!strcasecmp(\"ignore\", value))\n-\t\treturn CHECK_IGNORE;\n+\t\treturn MISSING_COMMIT_CHECK_IGNORE;\n \tif (!strcasecmp(\"warn\", value))\n-\t\treturn CHECK_WARN;\n+\t\treturn MISSING_COMMIT_CHECK_WARN;\n \tif (!strcasecmp(\"error\", value))\n-\t\treturn CHECK_ERROR;\n+\t\treturn MISSING_COMMIT_CHECK_ERROR;\n \twarning(_(\"unrecognized setting %s for option \"\n \t\t  \"rebase.missingCommitsCheck. Ignoring.\"), value);\n-\treturn CHECK_IGNORE;\n+\treturn MISSING_COMMIT_CHECK_IGNORE;\n }\n \n define_commit_slab(commit_seen, unsigned char);\n@@ -4278,7 +4274,7 @@ define_commit_slab(commit_seen, unsigned char);\n  */\n int check_todo_list(void)\n {\n-\tenum check_level check_level = get_missing_commit_check_level();\n+\tenum missing_commit_check_level check_level = get_missing_commit_check_level();\n \tstruct strbuf todo_file = STRBUF_INIT;\n \tstruct todo_list todo_list = TODO_LIST_INIT;\n \tstruct strbuf missing = STRBUF_INIT;\n@@ -4295,7 +4291,7 @@ int check_todo_list(void)\n \tadvise_to_edit_todo = res =\n \t\tparse_insn_buffer(todo_list.buf.buf, &todo_list);\n \n-\tif (res || check_level == CHECK_IGNORE)\n+\tif (res || check_level == MISSING_COMMIT_CHECK_IGNORE)\n \t\tgoto leave_check;\n \n \t/* Mark the commits in git-rebase-todo as seen */\n@@ -4330,7 +4326,7 @@ int check_todo_list(void)\n \tif (!missing.len)\n \t\tgoto leave_check;\n \n-\tif (check_level == CHECK_ERROR)\n+\tif (check_level == MISSING_COMMIT_CHECK_ERROR)\n \t\tadvise_to_edit_todo = res = 1;\n \n \tfprintf(stderr,\ndiff --git a/sequencer.h b/sequencer.h\nindex c5787c6b56..ffab798f1e 100644\n--- a/sequencer.h\n+++ b/sequencer.h\n@@ -3,6 +3,7 @@\n \n const char *git_path_commit_editmsg(void);\n const char *git_path_seq_dir(void);\n+const char *rebase_path_todo(void);\n \n #define APPEND_SIGNOFF_DEDUP (1u << 0)\n \n@@ -57,6 +58,12 @@ struct replay_opts {\n };\n #define REPLAY_OPTS_INIT { .action = -1, .current_fixups = STRBUF_INIT }\n \n+enum missing_commit_check_level {\n+\tMISSING_COMMIT_CHECK_IGNORE = 0,\n+\tMISSING_COMMIT_CHECK_WARN,\n+\tMISSING_COMMIT_CHECK_ERROR\n+};\n+\n /* Call this to setup defaults before parsing command line options */\n void sequencer_init_config(struct replay_opts *opts);\n int sequencer_pick_revisions(struct replay_opts *opts);\n@@ -79,6 +86,7 @@ int sequencer_make_script(FILE *out, int argc, const char **argv,\n \n int sequencer_add_exec_commands(const char *command);\n int transform_todos(unsigned flags);\n+enum missing_commit_check_level get_missing_commit_check_level(void);\n int check_todo_list(void);\n int skip_unnecessary_picks(void);\n int rearrange_squash(void);\n-- \n2.18.0\n\n"},{"id":"354077","messageId":"20180731180003.5421-3-alban.gruin@gmail.com","threadId":"48814","inReplyTo":"20180731180003.5421-1-alban.gruin@gmail.com","subject":"[GSoC][PATCH v5 02/20] rebase -i: rewrite append_todo_help() in C","fromName":"Alban Gruin","fromEmail":"alban.gruin@gmail.com","sentAt":"2018-07-31T17:59:45Z","receivedAt":"2018-07-31T18:00:25Z","isPatch":true,"sender":{"key":"alban.gruin@gmail.com","avatar":"https://avatars.githubusercontent.com/u/6310153?v=4"},"body":"This rewrites append_todo_help() from shell to C. It also incorporates\nsome parts of initiate_action() and complete_action() that also write\nhelp texts to the todo file.\n\nThis also introduces the source file rebase-interactive.c. This file\nwill contain functions necessary for interactive rebase that are too\nspecific for the sequencer, and is part of libgit.a.\n\nTwo flags are added to rebase--helper.c: one to call\nappend_todo_help() (`--append-todo-help`), and another one to tell\nappend_todo_help() to write the help text suited for the edit-todo\nmode (`--write-edit-todo`).\n\nFinally, append_todo_help() is removed from git-rebase--interactive.sh\nto use `rebase--helper --append-todo-help` instead.\n\nSigned-off-by: Alban Gruin <alban.gruin@gmail.com>\n---\nNo changes since v4.\n\n Makefile                   |  1 +\n builtin/rebase--helper.c   | 11 ++++--\n git-rebase--interactive.sh | 52 ++---------------------------\n rebase-interactive.c       | 68 ++++++++++++++++++++++++++++++++++++++\n rebase-interactive.h       |  6 ++++\n 5 files changed, 86 insertions(+), 52 deletions(-)\n create mode 100644 rebase-interactive.c\n create mode 100644 rebase-interactive.h\n\ndiff --git a/Makefile b/Makefile\nindex 08e5c54549..909a687857 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -922,6 +922,7 @@ LIB_OBJS += protocol.o\n LIB_OBJS += quote.o\n LIB_OBJS += reachable.o\n LIB_OBJS += read-cache.o\n+LIB_OBJS += rebase-interactive.o\n LIB_OBJS += reflog-walk.o\n LIB_OBJS += refs.o\n LIB_OBJS += refs/files-backend.o\ndiff --git a/builtin/rebase--helper.c b/builtin/rebase--helper.c\nindex f7c2a5fdc8..05e73e71d4 100644\n--- a/builtin/rebase--helper.c\n+++ b/builtin/rebase--helper.c\n@@ -3,6 +3,7 @@\n #include \"config.h\"\n #include \"parse-options.h\"\n #include \"sequencer.h\"\n+#include \"rebase-interactive.h\"\n \n static const char * const builtin_rebase_helper_usage[] = {\n \tN_(\"git rebase--helper [<options>]\"),\n@@ -12,12 +13,12 @@ static const char * const builtin_rebase_helper_usage[] = {\n int cmd_rebase__helper(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;\n+\tunsigned flags = 0, keep_empty = 0, rebase_merges = 0, write_edit_todo = 0;\n \tint abbreviate_commands = 0, rebase_cousins = -1;\n \tenum {\n \t\tCONTINUE = 1, ABORT, MAKE_SCRIPT, SHORTEN_OIDS, EXPAND_OIDS,\n \t\tCHECK_TODO_LIST, SKIP_UNNECESSARY_PICKS, REARRANGE_SQUASH,\n-\t\tADD_EXEC\n+\t\tADD_EXEC, APPEND_TODO_HELP\n \t} command = 0;\n \tstruct option options[] = {\n \t\tOPT_BOOL(0, \"ff\", &opts.allow_ff, N_(\"allow fast-forward\")),\n@@ -27,6 +28,8 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\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, \"write-edit-todo\", &write_edit_todo,\n+\t\t\t N_(\"append the edit-todo message to the todo-list\")),\n \t\tOPT_CMDMODE(0, \"continue\", &command, N_(\"continue rebase\"),\n \t\t\t\tCONTINUE),\n \t\tOPT_CMDMODE(0, \"abort\", &command, N_(\"abort rebase\"),\n@@ -45,6 +48,8 @@ int cmd_rebase__helper(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_CMDMODE(0, \"append-todo-help\", &command,\n+\t\t\t    N_(\"insert the help in the todo list\"), APPEND_TODO_HELP),\n \t\tOPT_END()\n \t};\n \n@@ -84,5 +89,7 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\n \t\treturn !!rearrange_squash();\n \tif (command == ADD_EXEC && argc == 2)\n \t\treturn !!sequencer_add_exec_commands(argv[1]);\n+\tif (command == APPEND_TODO_HELP && argc == 1)\n+\t\treturn !!append_todo_help(write_edit_todo, keep_empty);\n \tusage_with_options(builtin_rebase_helper_usage, options);\n }\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex 299ded2137..94c23a7af2 100644\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -39,38 +39,6 @@ comment_for_reflog () {\n \tesac\n }\n \n-append_todo_help () {\n-\tgettext \"\n-Commands:\n-p, pick <commit> = use commit\n-r, reword <commit> = use commit, but edit the commit message\n-e, edit <commit> = use commit, but stop for amending\n-s, squash <commit> = use commit, but meld into previous commit\n-f, fixup <commit> = like \\\"squash\\\", but discard this commit's log message\n-x, exec <command> = run command (the rest of the line) using shell\n-d, drop <commit> = remove commit\n-l, label <label> = label current HEAD with a name\n-t, reset <label> = reset HEAD to a label\n-m, merge [-C <commit> | -c <commit>] <label> [# <oneline>]\n-.       create a merge commit using the original merge commit's\n-.       message (or the oneline, if no original merge commit was\n-.       specified). Use -c <commit> to reword the commit message.\n-\n-These lines can be re-ordered; they are executed from top to bottom.\n-\" | git stripspace --comment-lines >>\"$todo\"\n-\n-\tif test $(get_missing_commit_check_level) = error\n-\tthen\n-\t\tgettext \"\n-Do not remove any line. Use 'drop' explicitly to remove a commit.\n-\" | git stripspace --comment-lines >>\"$todo\"\n-\telse\n-\t\tgettext \"\n-If you remove a line here THAT COMMIT WILL BE LOST.\n-\" | git stripspace --comment-lines >>\"$todo\"\n-\tfi\n-}\n-\n die_abort () {\n \tapply_autostash\n \trm -rf \"$state_dir\"\n@@ -143,13 +111,7 @@ initiate_action () {\n \t\tgit stripspace --strip-comments <\"$todo\" >\"$todo\".new\n \t\tmv -f \"$todo\".new \"$todo\"\n \t\tcollapse_todo_ids\n-\t\tappend_todo_help\n-\t\tgettext \"\n-You are editing the todo file of an ongoing interactive rebase.\n-To continue rebase after editing, run:\n-    git rebase --continue\n-\n-\" | git stripspace --comment-lines >>\"$todo\"\n+\t\tgit rebase--helper --append-todo-help --write-edit-todo\n \n \t\tgit_sequence_editor \"$todo\" ||\n \t\t\tdie \"$(gettext \"Could not execute editor\")\"\n@@ -220,17 +182,7 @@ $comment_char $(eval_ngettext \\\n \t\"Rebase \\$shortrevisions onto \\$shortonto (\\$todocount commands)\" \\\n \t\"$todocount\")\n EOF\n-\tappend_todo_help\n-\tgettext \"\n-\tHowever, if you remove everything, the rebase will be aborted.\n-\n-\t\" | git stripspace --comment-lines >>\"$todo\"\n-\n-\tif test -z \"$keep_empty\"\n-\tthen\n-\t\tprintf '%s\\n' \"$comment_char $(gettext \"Note that empty commits are commented out\")\" >>\"$todo\"\n-\tfi\n-\n+\tgit rebase--helper --append-todo-help ${keep_empty:+--keep-empty}\n \n \thas_action \"$todo\" ||\n \t\treturn 2\ndiff --git a/rebase-interactive.c b/rebase-interactive.c\nnew file mode 100644\nindex 0000000000..d7996bc8d9\n--- /dev/null\n+++ b/rebase-interactive.c\n@@ -0,0 +1,68 @@\n+#include \"cache.h\"\n+#include \"commit.h\"\n+#include \"rebase-interactive.h\"\n+#include \"sequencer.h\"\n+#include \"strbuf.h\"\n+\n+int append_todo_help(unsigned edit_todo, unsigned keep_empty)\n+{\n+\tstruct strbuf buf = STRBUF_INIT;\n+\tFILE *todo;\n+\tint ret;\n+\tconst char *msg = _(\"\\nCommands:\\n\"\n+\"p, pick <commit> = use commit\\n\"\n+\"r, reword <commit> = use commit, but edit the commit message\\n\"\n+\"e, edit <commit> = use commit, but stop for amending\\n\"\n+\"s, squash <commit> = use commit, but meld into previous commit\\n\"\n+\"f, fixup <commit> = like \\\"squash\\\", but discard this commit's log message\\n\"\n+\"x, exec <command> = run command (the rest of the line) using shell\\n\"\n+\"d, drop <commit> = remove commit\\n\"\n+\"l, label <label> = label current HEAD with a name\\n\"\n+\"t, reset <label> = reset HEAD to a label\\n\"\n+\"m, merge [-C <commit> | -c <commit>] <label> [# <oneline>]\\n\"\n+\".       create a merge commit using the original merge commit's\\n\"\n+\".       message (or the oneline, if no original merge commit was\\n\"\n+\".       specified). Use -c <commit> to reword the commit message.\\n\"\n+\"\\n\"\n+\"These lines can be re-ordered; they are executed from top to bottom.\\n\");\n+\n+\ttodo = fopen_or_warn(rebase_path_todo(), \"a\");\n+\tif (!todo)\n+\t\treturn 1;\n+\n+\tstrbuf_add_commented_lines(&buf, msg, strlen(msg));\n+\n+\tif (get_missing_commit_check_level() == MISSING_COMMIT_CHECK_ERROR)\n+\t\tmsg = _(\"\\nDo not remove any line. Use 'drop' \"\n+\t\t\t \"explicitly to remove a commit.\\n\");\n+\telse\n+\t\tmsg = _(\"\\nIf you remove a line here \"\n+\t\t\t \"THAT COMMIT WILL BE LOST.\\n\");\n+\n+\tstrbuf_add_commented_lines(&buf, msg, strlen(msg));\n+\n+\tif (edit_todo)\n+\t\tmsg = _(\"\\nYou are editing the todo file \"\n+\t\t\t\"of an ongoing interactive rebase.\\n\"\n+\t\t\t\"To continue rebase after editing, run:\\n\"\n+\t\t\t\"    git rebase --continue\\n\\n\");\n+\telse\n+\t\tmsg = _(\"\\nHowever, if you remove everything, \"\n+\t\t\t\"the rebase will be aborted.\\n\\n\");\n+\n+\tstrbuf_add_commented_lines(&buf, msg, strlen(msg));\n+\n+\tif (!keep_empty) {\n+\t\tmsg = _(\"Note that empty commits are commented out\");\n+\t\tstrbuf_add_commented_lines(&buf, msg, strlen(msg));\n+\t}\n+\n+\tret = fputs(buf.buf, todo);\n+\tif (ret < 0)\n+\t\terror_errno(_(\"could not append help text to '%s'\"), rebase_path_todo());\n+\n+\tfclose(todo);\n+\tstrbuf_release(&buf);\n+\n+\treturn ret;\n+}\ndiff --git a/rebase-interactive.h b/rebase-interactive.h\nnew file mode 100644\nindex 0000000000..47372624e0\n--- /dev/null\n+++ b/rebase-interactive.h\n@@ -0,0 +1,6 @@\n+#ifndef REBASE_INTERACTIVE_H\n+#define REBASE_INTERACTIVE_H\n+\n+int append_todo_help(unsigned edit_todo, unsigned keep_empty);\n+\n+#endif\n-- \n2.18.0\n\n"},{"id":"354078","messageId":"20180731180003.5421-4-alban.gruin@gmail.com","threadId":"48814","inReplyTo":"20180731180003.5421-1-alban.gruin@gmail.com","subject":"[GSoC][PATCH v5 03/20] editor: add a function to launch the sequence editor","fromName":"Alban Gruin","fromEmail":"alban.gruin@gmail.com","sentAt":"2018-07-31T17:59:46Z","receivedAt":"2018-07-31T18:00:26Z","isPatch":true,"sender":{"key":"alban.gruin@gmail.com","avatar":"https://avatars.githubusercontent.com/u/6310153?v=4"},"body":"As part of the rewrite of interactive rebase, the sequencer will need to\nopen the sequence editor to allow the user to edit the todo list.\nInstead of duplicating the existing launch_editor() function, this\nrefactors it to a new function, launch_specified_editor(), which takes\nthe editor as a parameter, in addition to the path, the buffer and the\nenvironment variables.  launch_sequence_editor() is then added to launch\nthe sequence editor.\n\nSigned-off-by: Alban Gruin <alban.gruin@gmail.com>\n---\nNo changes since v4.\n\n cache.h  |  1 +\n editor.c | 27 +++++++++++++++++++++++++--\n strbuf.h |  2 ++\n 3 files changed, 28 insertions(+), 2 deletions(-)\n\ndiff --git a/cache.h b/cache.h\nindex 8b447652a7..d70ae49ca2 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -1409,6 +1409,7 @@ extern const char *fmt_name(const char *name, const char *email);\n extern const char *ident_default_name(void);\n extern const char *ident_default_email(void);\n extern const char *git_editor(void);\n+extern const char *git_sequence_editor(void);\n extern const char *git_pager(int stdout_is_tty);\n extern int is_terminal_dumb(void);\n extern int git_ident_config(const char *, const char *, void *);\ndiff --git a/editor.c b/editor.c\nindex 9a9b4e12d1..c985eee1f9 100644\n--- a/editor.c\n+++ b/editor.c\n@@ -1,4 +1,5 @@\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"strbuf.h\"\n #include \"run-command.h\"\n #include \"sigchain.h\"\n@@ -34,10 +35,21 @@ const char *git_editor(void)\n \treturn editor;\n }\n \n-int launch_editor(const char *path, struct strbuf *buffer, const char *const *env)\n+const char *git_sequence_editor(void)\n {\n-\tconst char *editor = git_editor();\n+\tconst char *editor = getenv(\"GIT_SEQUENCE_EDITOR\");\n+\n+\tif (!editor)\n+\t\tgit_config_get_string_const(\"sequence.editor\", &editor);\n+\tif (!editor)\n+\t\teditor = git_editor();\n \n+\treturn editor;\n+}\n+\n+static int launch_specified_editor(const char *editor, const char *path,\n+\t\t\t\t   struct strbuf *buffer, const char *const *env)\n+{\n \tif (!editor)\n \t\treturn error(\"Terminal is dumb, but EDITOR unset\");\n \n@@ -95,3 +107,14 @@ int launch_editor(const char *path, struct strbuf *buffer, const char *const *en\n \t\treturn error_errno(\"could not read file '%s'\", path);\n \treturn 0;\n }\n+\n+int launch_editor(const char *path, struct strbuf *buffer, const char *const *env)\n+{\n+\treturn launch_specified_editor(git_editor(), path, buffer, env);\n+}\n+\n+int launch_sequence_editor(const char *path, struct strbuf *buffer,\n+\t\t\t   const char *const *env)\n+{\n+\treturn launch_specified_editor(git_sequence_editor(), path, buffer, env);\n+}\ndiff --git a/strbuf.h b/strbuf.h\nindex 60a35aef16..66da9822fd 100644\n--- a/strbuf.h\n+++ b/strbuf.h\n@@ -575,6 +575,8 @@ extern void strbuf_add_unique_abbrev(struct strbuf *sb,\n  * file's contents are not read into the buffer upon completion.\n  */\n extern int launch_editor(const char *path, struct strbuf *buffer, const char *const *env);\n+extern int launch_sequence_editor(const char *path, struct strbuf *buffer,\n+\t\t\t\t  const char *const *env);\n \n extern void strbuf_add_lines(struct strbuf *sb, const char *prefix, const char *buf, size_t size);\n \n-- \n2.18.0\n\n"},{"id":"354079","messageId":"20180731180003.5421-5-alban.gruin@gmail.com","threadId":"48814","inReplyTo":"20180731180003.5421-1-alban.gruin@gmail.com","subject":"[GSoC][PATCH v5 04/20] rebase -i: rewrite the edit-todo functionality in C","fromName":"Alban Gruin","fromEmail":"alban.gruin@gmail.com","sentAt":"2018-07-31T17:59:47Z","receivedAt":"2018-07-31T18:00:28Z","isPatch":true,"sender":{"key":"alban.gruin@gmail.com","avatar":"https://avatars.githubusercontent.com/u/6310153?v=4"},"body":"This rewrites the edit-todo functionality from shell to C.\n\nTo achieve that, a new command mode, `edit-todo`, is added, and the\n`write-edit-todo` flag is removed, as the shell script does not need to\nwrite the edit todo help message to the todo list anymore.\n\nThe shell version is then stripped in favour of a call to the helper.\n\nSigned-off-by: Alban Gruin <alban.gruin@gmail.com>\n---\nNo changes since v4.\n\n builtin/rebase--helper.c   | 13 ++++++++-----\n git-rebase--interactive.sh | 11 +----------\n rebase-interactive.c       | 31 +++++++++++++++++++++++++++++++\n rebase-interactive.h       |  1 +\n 4 files changed, 41 insertions(+), 15 deletions(-)\n\ndiff --git a/builtin/rebase--helper.c b/builtin/rebase--helper.c\nindex 05e73e71d4..731a64971d 100644\n--- a/builtin/rebase--helper.c\n+++ b/builtin/rebase--helper.c\n@@ -13,12 +13,12 @@ static const char * const builtin_rebase_helper_usage[] = {\n int cmd_rebase__helper(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, write_edit_todo = 0;\n+\tunsigned flags = 0, keep_empty = 0, rebase_merges = 0;\n \tint abbreviate_commands = 0, rebase_cousins = -1;\n \tenum {\n \t\tCONTINUE = 1, ABORT, MAKE_SCRIPT, SHORTEN_OIDS, EXPAND_OIDS,\n \t\tCHECK_TODO_LIST, SKIP_UNNECESSARY_PICKS, REARRANGE_SQUASH,\n-\t\tADD_EXEC, APPEND_TODO_HELP\n+\t\tADD_EXEC, APPEND_TODO_HELP, EDIT_TODO\n \t} command = 0;\n \tstruct option options[] = {\n \t\tOPT_BOOL(0, \"ff\", &opts.allow_ff, N_(\"allow fast-forward\")),\n@@ -28,8 +28,6 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\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, \"write-edit-todo\", &write_edit_todo,\n-\t\t\t N_(\"append the edit-todo message to the todo-list\")),\n \t\tOPT_CMDMODE(0, \"continue\", &command, N_(\"continue rebase\"),\n \t\t\t\tCONTINUE),\n \t\tOPT_CMDMODE(0, \"abort\", &command, N_(\"abort rebase\"),\n@@ -50,6 +48,9 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\n \t\t\tN_(\"insert exec commands in todo list\"), ADD_EXEC),\n \t\tOPT_CMDMODE(0, \"append-todo-help\", &command,\n \t\t\t    N_(\"insert the help in the todo list\"), APPEND_TODO_HELP),\n+\t\tOPT_CMDMODE(0, \"edit-todo\", &command,\n+\t\t\t    N_(\"edit the todo list during an interactive rebase\"),\n+\t\t\t    EDIT_TODO),\n \t\tOPT_END()\n \t};\n \n@@ -90,6 +91,8 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\n \tif (command == ADD_EXEC && argc == 2)\n \t\treturn !!sequencer_add_exec_commands(argv[1]);\n \tif (command == APPEND_TODO_HELP && argc == 1)\n-\t\treturn !!append_todo_help(write_edit_todo, keep_empty);\n+\t\treturn !!append_todo_help(0, keep_empty);\n+\tif (command == EDIT_TODO && argc == 1)\n+\t\treturn !!edit_todo_list(flags);\n \tusage_with_options(builtin_rebase_helper_usage, options);\n }\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex 94c23a7af2..2defe607f4 100644\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -108,16 +108,7 @@ initiate_action () {\n \t\t     --continue\n \t\t;;\n \tedit-todo)\n-\t\tgit stripspace --strip-comments <\"$todo\" >\"$todo\".new\n-\t\tmv -f \"$todo\".new \"$todo\"\n-\t\tcollapse_todo_ids\n-\t\tgit rebase--helper --append-todo-help --write-edit-todo\n-\n-\t\tgit_sequence_editor \"$todo\" ||\n-\t\t\tdie \"$(gettext \"Could not execute editor\")\"\n-\t\texpand_todo_ids\n-\n-\t\texit\n+\t\texec git rebase--helper --edit-todo\n \t\t;;\n \tshow-current-patch)\n \t\texec git show REBASE_HEAD --\ndiff --git a/rebase-interactive.c b/rebase-interactive.c\nindex d7996bc8d9..403ecbf3c9 100644\n--- a/rebase-interactive.c\n+++ b/rebase-interactive.c\n@@ -66,3 +66,34 @@ int append_todo_help(unsigned edit_todo, unsigned keep_empty)\n \n \treturn ret;\n }\n+\n+int edit_todo_list(unsigned flags)\n+{\n+\tstruct strbuf buf = STRBUF_INIT;\n+\tconst char *todo_file = rebase_path_todo();\n+\tFILE *todo;\n+\n+\tif (strbuf_read_file(&buf, todo_file, 0) < 0)\n+\t\treturn error_errno(_(\"could not read '%s'.\"), todo_file);\n+\n+\tstrbuf_stripspace(&buf, 1);\n+\ttodo = fopen_or_warn(todo_file, \"w\");\n+\tif (!todo) {\n+\t\tstrbuf_release(&buf);\n+\t\treturn 1;\n+\t}\n+\n+\tstrbuf_write(&buf, todo);\n+\tfclose(todo);\n+\tstrbuf_release(&buf);\n+\n+\ttransform_todos(flags | TODO_LIST_SHORTEN_IDS);\n+\tappend_todo_help(1, 0);\n+\n+\tif (launch_sequence_editor(todo_file, NULL, NULL))\n+\t\treturn 1;\n+\n+\ttransform_todos(flags & ~(TODO_LIST_SHORTEN_IDS));\n+\n+\treturn 0;\n+}\ndiff --git a/rebase-interactive.h b/rebase-interactive.h\nindex 47372624e0..155219e742 100644\n--- a/rebase-interactive.h\n+++ b/rebase-interactive.h\n@@ -2,5 +2,6 @@\n #define REBASE_INTERACTIVE_H\n \n int append_todo_help(unsigned edit_todo, unsigned keep_empty);\n+int edit_todo_list(unsigned flags);\n \n #endif\n-- \n2.18.0\n\n"},{"id":"354080","messageId":"20180731180003.5421-6-alban.gruin@gmail.com","threadId":"48814","inReplyTo":"20180731180003.5421-1-alban.gruin@gmail.com","subject":"[GSoC][PATCH v5 05/20] sequencer: add a new function to silence a command, except if it fails","fromName":"Alban Gruin","fromEmail":"alban.gruin@gmail.com","sentAt":"2018-07-31T17:59:48Z","receivedAt":"2018-07-31T18:00:29Z","isPatch":true,"sender":{"key":"alban.gruin@gmail.com","avatar":"https://avatars.githubusercontent.com/u/6310153?v=4"},"body":"This adds a new function, run_command_silent_on_success(), to\nredirect the stdout and stderr of a command to a strbuf, and then to run\nthat command. This strbuf is printed only if the command fails. It is\nfunctionnaly similar to output() from git-rebase.sh.\n\nrun_git_commit() is then refactored to use of\nrun_command_silent_on_success().\n\nSigned-off-by: Alban Gruin <alban.gruin@gmail.com>\n---\nNo changes since v4.\n\n sequencer.c | 51 +++++++++++++++++++++++++--------------------------\n 1 file changed, 25 insertions(+), 26 deletions(-)\n\ndiff --git a/sequencer.c b/sequencer.c\nindex 8eff526584..6d87f5ae6a 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -769,6 +769,23 @@ N_(\"you have staged changes in your working tree\\n\"\n #define VERIFY_MSG  (1<<4)\n #define CREATE_ROOT_COMMIT (1<<5)\n \n+static int run_command_silent_on_success(struct child_process *cmd)\n+{\n+\tstruct strbuf buf = STRBUF_INIT;\n+\tint rc;\n+\n+\tcmd->stdout_to_stderr = 1;\n+\trc = pipe_command(cmd,\n+\t\t\t  NULL, 0,\n+\t\t\t  NULL, 0,\n+\t\t\t  &buf, 0);\n+\n+\tif (rc)\n+\t\tfputs(buf.buf, stderr);\n+\tstrbuf_release(&buf);\n+\treturn rc;\n+}\n+\n /*\n  * If we are cherry-pick, and if the merge did not result in\n  * hand-editing, we will hit this commit and inherit the original\n@@ -823,18 +840,11 @@ static int run_git_commit(const char *defmsg, struct replay_opts *opts,\n \n \tcmd.git_cmd = 1;\n \n-\tif (is_rebase_i(opts)) {\n-\t\tif (!(flags & EDIT_MSG)) {\n-\t\t\tcmd.stdout_to_stderr = 1;\n-\t\t\tcmd.err = -1;\n-\t\t}\n-\n-\t\tif (read_env_script(&cmd.env_array)) {\n-\t\t\tconst char *gpg_opt = gpg_sign_opt_quoted(opts);\n+\tif (is_rebase_i(opts) && read_env_script(&cmd.env_array)) {\n+\t\tconst char *gpg_opt = gpg_sign_opt_quoted(opts);\n \n-\t\t\treturn error(_(staged_changes_advice),\n-\t\t\t\t     gpg_opt, gpg_opt);\n-\t\t}\n+\t\treturn error(_(staged_changes_advice),\n+\t\t\t     gpg_opt, gpg_opt);\n \t}\n \n \targv_array_push(&cmd.args, \"commit\");\n@@ -864,21 +874,10 @@ static int run_git_commit(const char *defmsg, struct replay_opts *opts,\n \tif (opts->allow_empty_message)\n \t\targv_array_push(&cmd.args, \"--allow-empty-message\");\n \n-\tif (cmd.err == -1) {\n-\t\t/* hide stderr on success */\n-\t\tstruct strbuf buf = STRBUF_INIT;\n-\t\tint rc = pipe_command(&cmd,\n-\t\t\t\t      NULL, 0,\n-\t\t\t\t      /* stdout is already redirected */\n-\t\t\t\t      NULL, 0,\n-\t\t\t\t      &buf, 0);\n-\t\tif (rc)\n-\t\t\tfputs(buf.buf, stderr);\n-\t\tstrbuf_release(&buf);\n-\t\treturn rc;\n-\t}\n-\n-\treturn run_command(&cmd);\n+\tif (is_rebase_i(opts) && !(flags & EDIT_MSG))\n+\t\treturn run_command_silent_on_success(&cmd);\n+\telse\n+\t\treturn run_command(&cmd);\n }\n \n static int rest_is_empty(const struct strbuf *sb, int start)\n-- \n2.18.0\n\n"},{"id":"354081","messageId":"20180731180003.5421-7-alban.gruin@gmail.com","threadId":"48814","inReplyTo":"20180731180003.5421-1-alban.gruin@gmail.com","subject":"[GSoC][PATCH v5 06/20] rebase -i: rewrite setup_reflog_action() in C","fromName":"Alban Gruin","fromEmail":"alban.gruin@gmail.com","sentAt":"2018-07-31T17:59:49Z","receivedAt":"2018-07-31T18:00:31Z","isPatch":true,"sender":{"key":"alban.gruin@gmail.com","avatar":"https://avatars.githubusercontent.com/u/6310153?v=4"},"body":"This rewrites (the misnamed) setup_reflog_action() from shell to C. The\nnew version is called prepare_branch_to_be_rebased().\n\nA new command is added to rebase--helper.c, “checkout-base”, as well as\na new flag, “verbose”, to avoid silencing the output of the checkout\noperation called by checkout_base_commit().\n\nThe function `run_git_checkout()` will also be used in the next commit,\ntherefore its code is not part of `checkout_base_commit()`.\n\nThe shell version is then stripped in favour of a call to the helper.\n\nAs $GIT_REFLOG_ACTION is no longer set at the first call of\ncheckout_onto(), a call to comment_for_reflog() is added at the\nbeginning of this function.\n\nSigned-off-by: Alban Gruin <alban.gruin@gmail.com>\n---\nNo changes since v4.\n\n builtin/rebase--helper.c   |  7 ++++++-\n git-rebase--interactive.sh | 16 ++--------------\n sequencer.c                | 30 ++++++++++++++++++++++++++++++\n sequencer.h                |  2 ++\n 4 files changed, 40 insertions(+), 15 deletions(-)\n\ndiff --git a/builtin/rebase--helper.c b/builtin/rebase--helper.c\nindex 731a64971d..0e76dadba6 100644\n--- a/builtin/rebase--helper.c\n+++ b/builtin/rebase--helper.c\n@@ -18,7 +18,7 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\n \tenum {\n \t\tCONTINUE = 1, ABORT, MAKE_SCRIPT, SHORTEN_OIDS, EXPAND_OIDS,\n \t\tCHECK_TODO_LIST, SKIP_UNNECESSARY_PICKS, REARRANGE_SQUASH,\n-\t\tADD_EXEC, APPEND_TODO_HELP, EDIT_TODO\n+\t\tADD_EXEC, APPEND_TODO_HELP, EDIT_TODO, PREPARE_BRANCH\n \t} command = 0;\n \tstruct option options[] = {\n \t\tOPT_BOOL(0, \"ff\", &opts.allow_ff, N_(\"allow fast-forward\")),\n@@ -28,6 +28,7 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\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__VERBOSE(&opts.verbose, N_(\"be verbose\")),\n \t\tOPT_CMDMODE(0, \"continue\", &command, N_(\"continue rebase\"),\n \t\t\t\tCONTINUE),\n \t\tOPT_CMDMODE(0, \"abort\", &command, N_(\"abort rebase\"),\n@@ -51,6 +52,8 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\n \t\tOPT_CMDMODE(0, \"edit-todo\", &command,\n \t\t\t    N_(\"edit the todo list during an interactive rebase\"),\n \t\t\t    EDIT_TODO),\n+\t\tOPT_CMDMODE(0, \"prepare-branch\", &command,\n+\t\t\t    N_(\"prepare the branch to be rebased\"), PREPARE_BRANCH),\n \t\tOPT_END()\n \t};\n \n@@ -94,5 +97,7 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\n \t\treturn !!append_todo_help(0, keep_empty);\n \tif (command == EDIT_TODO && argc == 1)\n \t\treturn !!edit_todo_list(flags);\n+\tif (command == PREPARE_BRANCH && argc == 2)\n+\t\treturn !!prepare_branch_to_be_rebased(&opts, argv[1]);\n \tusage_with_options(builtin_rebase_helper_usage, options);\n }\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex 2defe607f4..77e972bb6c 100644\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -72,6 +72,7 @@ collapse_todo_ids() {\n \n # Switch to the branch in $into and notify it in the reflog\n checkout_onto () {\n+\tcomment_for_reflog start\n \tGIT_REFLOG_ACTION=\"$GIT_REFLOG_ACTION: checkout $onto_name\"\n \toutput git checkout $onto || die_abort \"$(gettext \"could not detach HEAD\")\"\n \tgit update-ref ORIG_HEAD $orig_head\n@@ -119,19 +120,6 @@ initiate_action () {\n \tesac\n }\n \n-setup_reflog_action () {\n-\tcomment_for_reflog start\n-\n-\tif test ! -z \"$switch_to\"\n-\tthen\n-\t\tGIT_REFLOG_ACTION=\"$GIT_REFLOG_ACTION: checkout $switch_to\"\n-\t\toutput git checkout \"$switch_to\" -- ||\n-\t\t\tdie \"$(eval_gettext \"Could not checkout \\$switch_to\")\"\n-\n-\t\tcomment_for_reflog start\n-\tfi\n-}\n-\n init_basic_state () {\n \torig_head=$(git rev-parse --verify HEAD) || die \"$(gettext \"No HEAD?\")\"\n \tmkdir -p \"$state_dir\" || die \"$(eval_gettext \"Could not create temporary \\$state_dir\")\"\n@@ -211,7 +199,7 @@ git_rebase__interactive () {\n \t\treturn 0\n \tfi\n \n-\tsetup_reflog_action\n+\tgit rebase--helper --prepare-branch \"$switch_to\" ${verbose:+--verbose}\n \tinit_basic_state\n \n \tinit_revisions_and_shortrevisions\ndiff --git a/sequencer.c b/sequencer.c\nindex 6d87f5ae6a..52949f38b3 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -3141,6 +3141,36 @@ 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+{\n+\tstruct child_process cmd = CHILD_PROCESS_INIT;\n+\n+\tcmd.git_cmd = 1;\n+\n+\targv_array_push(&cmd.args, \"checkout\");\n+\targv_array_push(&cmd.args, 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+\telse\n+\t\treturn run_command_silent_on_success(&cmd);\n+}\n+\n+int prepare_branch_to_be_rebased(struct replay_opts *opts, 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\t\treturn error(_(\"could not checkout %s\"), commit);\n+\t}\n+\n+\treturn 0;\n+}\n+\n static const char rescheduled_advice[] =\n N_(\"Could not execute the todo command\\n\"\n \"\\n\"\ndiff --git a/sequencer.h b/sequencer.h\nindex ffab798f1e..93da713fe2 100644\n--- a/sequencer.h\n+++ b/sequencer.h\n@@ -106,6 +106,8 @@ int update_head_with_reflog(const struct commit *old_head,\n void commit_post_rewrite(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+\n #define SUMMARY_INITIAL_COMMIT   (1 << 0)\n #define SUMMARY_SHOW_AUTHOR_DATE (1 << 1)\n void print_commit_summary(const char *prefix, const struct object_id *oid,\n-- \n2.18.0\n\n"},{"id":"354085","messageId":"20180731180003.5421-8-alban.gruin@gmail.com","threadId":"48814","inReplyTo":"20180731180003.5421-1-alban.gruin@gmail.com","subject":"[GSoC][PATCH v5 07/20] rebase -i: rewrite checkout_onto() in C","fromName":"Alban Gruin","fromEmail":"alban.gruin@gmail.com","sentAt":"2018-07-31T17:59:50Z","receivedAt":"2018-07-31T18:00:33Z","isPatch":true,"sender":{"key":"alban.gruin@gmail.com","avatar":"https://avatars.githubusercontent.com/u/6310153?v=4"},"body":"This rewrites checkout_onto() from shell to C.\n\nA new command (“checkout-onto”) is added to rebase--helper.c. The shell\nversion is then stripped.\n\nSigned-off-by: Alban Gruin <alban.gruin@gmail.com>\n---\nNo changes since v4.\n\n builtin/rebase--helper.c   |  7 ++++++-\n git-rebase--interactive.sh | 25 ++++---------------------\n sequencer.c                | 19 +++++++++++++++++++\n sequencer.h                |  3 +++\n 4 files changed, 32 insertions(+), 22 deletions(-)\n\ndiff --git a/builtin/rebase--helper.c b/builtin/rebase--helper.c\nindex 0e76dadba6..7d9426d23c 100644\n--- a/builtin/rebase--helper.c\n+++ b/builtin/rebase--helper.c\n@@ -18,7 +18,8 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\n \tenum {\n \t\tCONTINUE = 1, ABORT, MAKE_SCRIPT, SHORTEN_OIDS, EXPAND_OIDS,\n \t\tCHECK_TODO_LIST, SKIP_UNNECESSARY_PICKS, REARRANGE_SQUASH,\n-\t\tADD_EXEC, APPEND_TODO_HELP, EDIT_TODO, PREPARE_BRANCH\n+\t\tADD_EXEC, APPEND_TODO_HELP, EDIT_TODO, PREPARE_BRANCH,\n+\t\tCHECKOUT_ONTO\n \t} command = 0;\n \tstruct option options[] = {\n \t\tOPT_BOOL(0, \"ff\", &opts.allow_ff, N_(\"allow fast-forward\")),\n@@ -54,6 +55,8 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\n \t\t\t    EDIT_TODO),\n \t\tOPT_CMDMODE(0, \"prepare-branch\", &command,\n \t\t\t    N_(\"prepare the branch to be rebased\"), PREPARE_BRANCH),\n+\t\tOPT_CMDMODE(0, \"checkout-onto\", &command,\n+\t\t\t    N_(\"checkout a commit\"), CHECKOUT_ONTO),\n \t\tOPT_END()\n \t};\n \n@@ -99,5 +102,7 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\n \t\treturn !!edit_todo_list(flags);\n \tif (command == PREPARE_BRANCH && argc == 2)\n \t\treturn !!prepare_branch_to_be_rebased(&opts, argv[1]);\n+\tif (command == CHECKOUT_ONTO && argc == 4)\n+\t\treturn !!checkout_onto(&opts, argv[1], argv[2], argv[3]);\n \tusage_with_options(builtin_rebase_helper_usage, options);\n }\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex 77e972bb6c..b68f108f28 100644\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -28,17 +28,6 @@ case \"$comment_char\" in\n \t;;\n esac\n \n-orig_reflog_action=\"$GIT_REFLOG_ACTION\"\n-\n-comment_for_reflog () {\n-\tcase \"$orig_reflog_action\" in\n-\t''|rebase*)\n-\t\tGIT_REFLOG_ACTION=\"rebase -i ($1)\"\n-\t\texport GIT_REFLOG_ACTION\n-\t\t;;\n-\tesac\n-}\n-\n die_abort () {\n \tapply_autostash\n \trm -rf \"$state_dir\"\n@@ -70,14 +59,6 @@ collapse_todo_ids() {\n \tgit rebase--helper --shorten-ids\n }\n \n-# Switch to the branch in $into and notify it in the reflog\n-checkout_onto () {\n-\tcomment_for_reflog start\n-\tGIT_REFLOG_ACTION=\"$GIT_REFLOG_ACTION: checkout $onto_name\"\n-\toutput git checkout $onto || die_abort \"$(gettext \"could not detach HEAD\")\"\n-\tgit update-ref ORIG_HEAD $orig_head\n-}\n-\n get_missing_commit_check_level () {\n \tcheck_level=$(git config --get rebase.missingCommitsCheck)\n \tcheck_level=${check_level:-ignore}\n@@ -176,7 +157,8 @@ EOF\n \n \tgit rebase--helper --check-todo-list || {\n \t\tret=$?\n-\t\tcheckout_onto\n+\t\tgit rebase--helper --checkout-onto \"$onto_name\" \"$onto\" \\\n+\t\t    \"$orig_head\" ${verbose:+--verbose}\n \t\texit $ret\n \t}\n \n@@ -186,7 +168,8 @@ EOF\n \tonto=\"$(git rebase--helper --skip-unnecessary-picks)\" ||\n \tdie \"Could not skip unnecessary pick commands\"\n \n-\tcheckout_onto\n+\tgit rebase--helper --checkout-onto \"$onto_name\" \"$onto\" \"$orig_head\" \\\n+\t    ${verbose:+--verbose}\n \trequire_clean_work_tree \"rebase\"\n \texec git rebase--helper ${force_rebase:+--no-ff} $allow_empty_message \\\n \t     --continue\ndiff --git a/sequencer.c b/sequencer.c\nindex 52949f38b3..4285247810 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -3171,6 +3171,25 @@ int prepare_branch_to_be_rebased(struct replay_opts *opts, const char *commit)\n \treturn 0;\n }\n \n+int checkout_onto(struct replay_opts *opts,\n+\t\t  const char *onto_name, const char *onto,\n+\t\t  const char *orig_head)\n+{\n+\tstruct object_id oid;\n+\tconst char *action = reflog_message(opts, \"start\", \"checkout %s\", onto_name);\n+\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+\t\tapply_autostash(opts);\n+\t\tsequencer_remove_state(opts);\n+\t\treturn error(_(\"could not detach HEAD\"));\n+\t}\n+\n+\treturn update_ref(NULL, \"ORIG_HEAD\", &oid, NULL, 0, UPDATE_REFS_MSG_ON_ERR);\n+}\n+\n static const char rescheduled_advice[] =\n N_(\"Could not execute the todo command\\n\"\n \"\\n\"\ndiff --git a/sequencer.h b/sequencer.h\nindex 93da713fe2..11a5334612 100644\n--- a/sequencer.h\n+++ b/sequencer.h\n@@ -107,6 +107,9 @@ void commit_post_rewrite(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 checkout_onto(struct replay_opts *opts,\n+\t\t  const char *onto_name, const char *onto,\n+\t\t  const char *orig_head);\n \n #define SUMMARY_INITIAL_COMMIT   (1 << 0)\n #define SUMMARY_SHOW_AUTHOR_DATE (1 << 1)\n-- \n2.18.0\n\n"},{"id":"354082","messageId":"20180731180003.5421-9-alban.gruin@gmail.com","threadId":"48814","inReplyTo":"20180731180003.5421-1-alban.gruin@gmail.com","subject":"[GSoC][PATCH v5 08/20] sequencer: refactor append_todo_help() to write its message to a buffer","fromName":"Alban Gruin","fromEmail":"alban.gruin@gmail.com","sentAt":"2018-07-31T17:59:51Z","receivedAt":"2018-07-31T18:00:35Z","isPatch":true,"sender":{"key":"alban.gruin@gmail.com","avatar":"https://avatars.githubusercontent.com/u/6310153?v=4"},"body":"This refactors append_todo_help() to write its message to a buffer\ninstead of the todo-list.  This is needed for the rewrite of\ncomplete_action(), which will come after the next commit.\n\nAs rebase--helper still needs the file manipulation part of\nappend_todo_help(), it is extracted to a temporary function,\nappend_todo_help_to_file().  This function will go away after the\nrewrite of complete_action().\n\nSigned-off-by: Alban Gruin <alban.gruin@gmail.com>\n---\nNo changes since v4.\n\n builtin/rebase--helper.c |  2 +-\n rebase-interactive.c     | 45 ++++++++++++++++++++++++++++------------\n rebase-interactive.h     |  4 +++-\n 3 files changed, 36 insertions(+), 15 deletions(-)\n\ndiff --git a/builtin/rebase--helper.c b/builtin/rebase--helper.c\nindex 7d9426d23c..313092c465 100644\n--- a/builtin/rebase--helper.c\n+++ b/builtin/rebase--helper.c\n@@ -97,7 +97,7 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\n \tif (command == ADD_EXEC && argc == 2)\n \t\treturn !!sequencer_add_exec_commands(argv[1]);\n \tif (command == APPEND_TODO_HELP && argc == 1)\n-\t\treturn !!append_todo_help(0, keep_empty);\n+\t\treturn !!append_todo_help_to_file(0, keep_empty);\n \tif (command == EDIT_TODO && argc == 1)\n \t\treturn !!edit_todo_list(flags);\n \tif (command == PREPARE_BRANCH && argc == 2)\ndiff --git a/rebase-interactive.c b/rebase-interactive.c\nindex 403ecbf3c9..d8b9465597 100644\n--- a/rebase-interactive.c\n+++ b/rebase-interactive.c\n@@ -4,11 +4,9 @@\n #include \"sequencer.h\"\n #include \"strbuf.h\"\n \n-int append_todo_help(unsigned edit_todo, unsigned keep_empty)\n+void append_todo_help(unsigned edit_todo, unsigned keep_empty,\n+\t\t      struct strbuf *buf)\n {\n-\tstruct strbuf buf = STRBUF_INIT;\n-\tFILE *todo;\n-\tint ret;\n \tconst char *msg = _(\"\\nCommands:\\n\"\n \"p, pick <commit> = use commit\\n\"\n \"r, reword <commit> = use commit, but edit the commit message\\n\"\n@@ -26,11 +24,7 @@ int append_todo_help(unsigned edit_todo, unsigned keep_empty)\n \"\\n\"\n \"These lines can be re-ordered; they are executed from top to bottom.\\n\");\n \n-\ttodo = fopen_or_warn(rebase_path_todo(), \"a\");\n-\tif (!todo)\n-\t\treturn 1;\n-\n-\tstrbuf_add_commented_lines(&buf, msg, strlen(msg));\n+\tstrbuf_add_commented_lines(buf, msg, strlen(msg));\n \n \tif (get_missing_commit_check_level() == MISSING_COMMIT_CHECK_ERROR)\n \t\tmsg = _(\"\\nDo not remove any line. Use 'drop' \"\n@@ -39,7 +33,7 @@ int append_todo_help(unsigned edit_todo, unsigned keep_empty)\n \t\tmsg = _(\"\\nIf you remove a line here \"\n \t\t\t \"THAT COMMIT WILL BE LOST.\\n\");\n \n-\tstrbuf_add_commented_lines(&buf, msg, strlen(msg));\n+\tstrbuf_add_commented_lines(buf, msg, strlen(msg));\n \n \tif (edit_todo)\n \t\tmsg = _(\"\\nYou are editing the todo file \"\n@@ -50,12 +44,25 @@ int append_todo_help(unsigned edit_todo, unsigned keep_empty)\n \t\tmsg = _(\"\\nHowever, if you remove everything, \"\n \t\t\t\"the rebase will be aborted.\\n\\n\");\n \n-\tstrbuf_add_commented_lines(&buf, msg, strlen(msg));\n+\tstrbuf_add_commented_lines(buf, msg, strlen(msg));\n \n \tif (!keep_empty) {\n \t\tmsg = _(\"Note that empty commits are commented out\");\n-\t\tstrbuf_add_commented_lines(&buf, msg, strlen(msg));\n+\t\tstrbuf_add_commented_lines(buf, msg, strlen(msg));\n \t}\n+}\n+\n+int append_todo_help_to_file(unsigned edit_todo, unsigned keep_empty)\n+{\n+\tstruct strbuf buf = STRBUF_INIT;\n+\tFILE *todo;\n+\tint ret;\n+\n+\ttodo = fopen_or_warn(rebase_path_todo(), \"a\");\n+\tif (!todo)\n+\t\treturn 1;\n+\n+\tappend_todo_help(edit_todo, keep_empty, &buf);\n \n \tret = fputs(buf.buf, todo);\n \tif (ret < 0)\n@@ -88,7 +95,19 @@ int edit_todo_list(unsigned flags)\n \tstrbuf_release(&buf);\n \n \ttransform_todos(flags | TODO_LIST_SHORTEN_IDS);\n-\tappend_todo_help(1, 0);\n+\n+\tstrbuf_read_file(&buf, todo_file, 0);\n+\tappend_todo_help(1, 0, &buf);\n+\n+\ttodo = fopen_or_warn(todo_file, \"w\");\n+\tif (!todo) {\n+\t\tstrbuf_release(&buf);\n+\t\treturn 1;\n+\t}\n+\n+\tstrbuf_write(&buf, todo);\n+\tfclose(todo);\n+\tstrbuf_release(&buf);\n \n \tif (launch_sequence_editor(todo_file, NULL, NULL))\n \t\treturn 1;\ndiff --git a/rebase-interactive.h b/rebase-interactive.h\nindex 155219e742..d33f3176b7 100644\n--- a/rebase-interactive.h\n+++ b/rebase-interactive.h\n@@ -1,7 +1,9 @@\n #ifndef REBASE_INTERACTIVE_H\n #define REBASE_INTERACTIVE_H\n \n-int append_todo_help(unsigned edit_todo, unsigned keep_empty);\n+void append_todo_help(unsigned edit_todo, unsigned keep_empty,\n+\t\t      struct strbuf *buf);\n+int append_todo_help_to_file(unsigned edit_todo, unsigned keep_empty);\n int edit_todo_list(unsigned flags);\n \n #endif\n-- \n2.18.0\n\n"},{"id":"354084","messageId":"20180731180003.5421-10-alban.gruin@gmail.com","threadId":"48814","inReplyTo":"20180731180003.5421-1-alban.gruin@gmail.com","subject":"[GSoC][PATCH v5 09/20] sequencer: change the way skip_unnecessary_picks() returns its result","fromName":"Alban Gruin","fromEmail":"alban.gruin@gmail.com","sentAt":"2018-07-31T17:59:52Z","receivedAt":"2018-07-31T18:00:35Z","isPatch":true,"sender":{"key":"alban.gruin@gmail.com","avatar":"https://avatars.githubusercontent.com/u/6310153?v=4"},"body":"Instead of skip_unnecessary_picks() printing its result to stdout, it\nreturns it into a struct object_id, as the rewrite of complete_action()\n(to come in the next commit) will need it.\n\nrebase--helper then is modified to fit this change.\n\nSigned-off-by: Alban Gruin <alban.gruin@gmail.com>\n---\nNo changes since v4.\n\n builtin/rebase--helper.c | 10 ++++++++--\n sequencer.c              | 13 ++++++-------\n sequencer.h              |  2 +-\n 3 files changed, 15 insertions(+), 10 deletions(-)\n\ndiff --git a/builtin/rebase--helper.c b/builtin/rebase--helper.c\nindex 313092c465..bed3dd2b95 100644\n--- a/builtin/rebase--helper.c\n+++ b/builtin/rebase--helper.c\n@@ -90,8 +90,14 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\n \t\treturn !!transform_todos(flags);\n \tif (command == CHECK_TODO_LIST && argc == 1)\n \t\treturn !!check_todo_list();\n-\tif (command == SKIP_UNNECESSARY_PICKS && argc == 1)\n-\t\treturn !!skip_unnecessary_picks();\n+\tif (command == SKIP_UNNECESSARY_PICKS && argc == 1) {\n+\t\tstruct object_id oid;\n+\t\tint ret = skip_unnecessary_picks(&oid);\n+\n+\t\tif (!ret)\n+\t\t\tputs(oid_to_hex(&oid));\n+\t\treturn !!ret;\n+\t}\n \tif (command == REARRANGE_SQUASH && argc == 1)\n \t\treturn !!rearrange_squash();\n \tif (command == ADD_EXEC && argc == 2)\ndiff --git a/sequencer.c b/sequencer.c\nindex 4285247810..a2e04b9eca 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -4420,17 +4420,17 @@ static int rewrite_file(const char *path, const char *buf, size_t len)\n }\n \n /* skip picking commits whose parents are unchanged */\n-int skip_unnecessary_picks(void)\n+int skip_unnecessary_picks(struct object_id *output_oid)\n {\n \tconst char *todo_file = rebase_path_todo();\n \tstruct strbuf buf = STRBUF_INIT;\n \tstruct todo_list todo_list = TODO_LIST_INIT;\n-\tstruct object_id onto_oid, *oid = &onto_oid, *parent_oid;\n+\tstruct object_id *parent_oid;\n \tint fd, i;\n \n \tif (!read_oneliner(&buf, rebase_path_onto(), 0))\n \t\treturn error(_(\"could not read 'onto'\"));\n-\tif (get_oid(buf.buf, &onto_oid)) {\n+\tif (get_oid(buf.buf, output_oid)) {\n \t\tstrbuf_release(&buf);\n \t\treturn error(_(\"need a HEAD to fixup\"));\n \t}\n@@ -4460,9 +4460,9 @@ int skip_unnecessary_picks(void)\n \t\tif (item->commit->parents->next)\n \t\t\tbreak; /* merge commit */\n \t\tparent_oid = &item->commit->parents->item->object.oid;\n-\t\tif (hashcmp(parent_oid->hash, oid->hash))\n+\t\tif (hashcmp(parent_oid->hash, output_oid->hash))\n \t\t\tbreak;\n-\t\toid = &item->commit->object.oid;\n+\t\toidcpy(output_oid, &item->commit->object.oid);\n \t}\n \tif (i > 0) {\n \t\tint offset = get_item_line_offset(&todo_list, i);\n@@ -4491,11 +4491,10 @@ int skip_unnecessary_picks(void)\n \n \t\ttodo_list.current = i;\n \t\tif (is_fixup(peek_command(&todo_list, 0)))\n-\t\t\trecord_in_rewritten(oid, peek_command(&todo_list, 0));\n+\t\t\trecord_in_rewritten(output_oid, peek_command(&todo_list, 0));\n \t}\n \n \ttodo_list_release(&todo_list);\n-\tprintf(\"%s\\n\", oid_to_hex(oid));\n \n \treturn 0;\n }\ndiff --git a/sequencer.h b/sequencer.h\nindex 11a5334612..f11dabfd65 100644\n--- a/sequencer.h\n+++ b/sequencer.h\n@@ -88,7 +88,7 @@ int sequencer_add_exec_commands(const char *command);\n int transform_todos(unsigned flags);\n enum missing_commit_check_level get_missing_commit_check_level(void);\n int check_todo_list(void);\n-int skip_unnecessary_picks(void);\n+int skip_unnecessary_picks(struct object_id *output_oid);\n int rearrange_squash(void);\n \n extern const char sign_off_header[];\n-- \n2.18.0\n\n"},{"id":"354083","messageId":"20180731180003.5421-11-alban.gruin@gmail.com","threadId":"48814","inReplyTo":"20180731180003.5421-1-alban.gruin@gmail.com","subject":"[GSoC][PATCH v5 10/20] t3404: todo list with commented-out commands only aborts","fromName":"Alban Gruin","fromEmail":"alban.gruin@gmail.com","sentAt":"2018-07-31T17:59:53Z","receivedAt":"2018-07-31T18:00:37Z","isPatch":true,"sender":{"key":"alban.gruin@gmail.com","avatar":"https://avatars.githubusercontent.com/u/6310153?v=4"},"body":"If the todo list generated by `--make-script` is empty,\ncomplete_action() writes a noop, but if it has only commented-out\ncommands, it will abort with the message \"Nothing to do\", and does not\nlaunch the editor.  This adds a new test to ensure that\ncomplete_action() behaves this way.\n\nSigned-off-by: Alban Gruin <alban.gruin@gmail.com>\n---\nNo changes since v4.\n\n t/t3404-rebase-interactive.sh | 10 ++++++++++\n 1 file changed, 10 insertions(+)\n\ndiff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh\nindex 01616901bd..496d88d7d6 100755\n--- a/t/t3404-rebase-interactive.sh\n+++ b/t/t3404-rebase-interactive.sh\n@@ -75,6 +75,16 @@ test_expect_success 'rebase --keep-empty' '\n \ttest_line_count = 6 actual\n '\n \n+cat > expect <<EOF\n+Nothing to do\n+EOF\n+\n+test_expect_success 'rebase -i with empty HEAD' '\n+\tset_fake_editor &&\n+\ttest_must_fail env FAKE_LINES=\"1 exec_true\" git rebase -i HEAD^ >actual 2>&1 &&\n+\ttest_i18ncmp expect actual\n+'\n+\n test_expect_success 'rebase -i with the exec command' '\n \tgit checkout master &&\n \t(\n-- \n2.18.0\n\n"},{"id":"354086","messageId":"20180731180003.5421-12-alban.gruin@gmail.com","threadId":"48814","inReplyTo":"20180731180003.5421-1-alban.gruin@gmail.com","subject":"[GSoC][PATCH v5 11/20] rebase -i: rewrite complete_action() in C","fromName":"Alban Gruin","fromEmail":"alban.gruin@gmail.com","sentAt":"2018-07-31T17:59:54Z","receivedAt":"2018-07-31T18:00:41Z","isPatch":true,"sender":{"key":"alban.gruin@gmail.com","avatar":"https://avatars.githubusercontent.com/u/6310153?v=4"},"body":"This rewrites complete_action() from shell to C.\n\nA new mode is added to rebase--helper (`--complete-action`), as well as\na new flag (`--autosquash`).\n\nFinally, complete_action() is stripped from git-rebase--interactive.sh.\n\nThe original complete_action() would return the code 2 when the todo\nlist contained no actions.  This was a special case for rebase -i and\n-p; git-rebase.sh would then apply the autostash, delete the state\ndirectory, and die with the message \"Nothing to do\".  This cleanup is\nrewritten in C instead of returning 2.  As rebase -i no longer returns\n2, the comment describing this behaviour in git-rebase.sh is updated to\nreflect this change.\n\nThe first check might seem useless as we write \"noop\" to the todo list\nif it is empty.  Actually, the todo list might contain commented\ncommands (ie. empty commits).  In this case, complete_action() won’t\nwrite \"noop\", and will abort without starting the editor.\n\nSigned-off-by: Alban Gruin <alban.gruin@gmail.com>\n---\nNo changes since v4.\n\n builtin/rebase--helper.c   | 12 ++++-\n git-rebase--interactive.sh | 53 ++------------------\n git-rebase.sh              |  2 +-\n sequencer.c                | 99 ++++++++++++++++++++++++++++++++++++++\n sequencer.h                |  4 ++\n 5 files changed, 118 insertions(+), 52 deletions(-)\n\ndiff --git a/builtin/rebase--helper.c b/builtin/rebase--helper.c\nindex bed3dd2b95..d7fa5a5062 100644\n--- a/builtin/rebase--helper.c\n+++ b/builtin/rebase--helper.c\n@@ -13,13 +13,13 @@ static const char * const builtin_rebase_helper_usage[] = {\n int cmd_rebase__helper(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;\n+\tunsigned flags = 0, keep_empty = 0, rebase_merges = 0, autosquash = 0;\n \tint abbreviate_commands = 0, rebase_cousins = -1;\n \tenum {\n \t\tCONTINUE = 1, ABORT, MAKE_SCRIPT, SHORTEN_OIDS, EXPAND_OIDS,\n \t\tCHECK_TODO_LIST, SKIP_UNNECESSARY_PICKS, REARRANGE_SQUASH,\n \t\tADD_EXEC, APPEND_TODO_HELP, EDIT_TODO, PREPARE_BRANCH,\n-\t\tCHECKOUT_ONTO\n+\t\tCHECKOUT_ONTO, COMPLETE_ACTION\n \t} command = 0;\n \tstruct option options[] = {\n \t\tOPT_BOOL(0, \"ff\", &opts.allow_ff, N_(\"allow fast-forward\")),\n@@ -29,6 +29,8 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\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 thas begin with squash!/fixup!\")),\n \t\tOPT__VERBOSE(&opts.verbose, N_(\"be verbose\")),\n \t\tOPT_CMDMODE(0, \"continue\", &command, N_(\"continue rebase\"),\n \t\t\t\tCONTINUE),\n@@ -57,6 +59,8 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\n \t\t\t    N_(\"prepare the branch to be rebased\"), PREPARE_BRANCH),\n \t\tOPT_CMDMODE(0, \"checkout-onto\", &command,\n \t\t\t    N_(\"checkout a commit\"), CHECKOUT_ONTO),\n+\t\tOPT_CMDMODE(0, \"complete-action\", &command,\n+\t\t\t    N_(\"complete the action\"), COMPLETE_ACTION),\n \t\tOPT_END()\n \t};\n \n@@ -110,5 +114,9 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\n \t\treturn !!prepare_branch_to_be_rebased(&opts, argv[1]);\n \tif (command == CHECKOUT_ONTO && argc == 4)\n \t\treturn !!checkout_onto(&opts, argv[1], argv[2], argv[3]);\n+\tif (command == COMPLETE_ACTION && argc == 6)\n+\t\treturn !!complete_action(&opts, flags, argv[1], argv[2], argv[3],\n+\t\t\t\t\t argv[4], argv[5], autosquash);\n+\n \tusage_with_options(builtin_rebase_helper_usage, options);\n }\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex b68f108f28..59dc4888a6 100644\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -127,54 +127,6 @@ init_revisions_and_shortrevisions () {\n \tfi\n }\n \n-complete_action() {\n-\ttest -s \"$todo\" || echo noop >> \"$todo\"\n-\ttest -z \"$autosquash\" || git rebase--helper --rearrange-squash || exit\n-\ttest -n \"$cmd\" && git rebase--helper --add-exec-commands \"$cmd\"\n-\n-\ttodocount=$(git stripspace --strip-comments <\"$todo\" | wc -l)\n-\ttodocount=${todocount##* }\n-\n-cat >>\"$todo\" <<EOF\n-\n-$comment_char $(eval_ngettext \\\n-\t\"Rebase \\$shortrevisions onto \\$shortonto (\\$todocount command)\" \\\n-\t\"Rebase \\$shortrevisions onto \\$shortonto (\\$todocount commands)\" \\\n-\t\"$todocount\")\n-EOF\n-\tgit rebase--helper --append-todo-help ${keep_empty:+--keep-empty}\n-\n-\thas_action \"$todo\" ||\n-\t\treturn 2\n-\n-\tcp \"$todo\" \"$todo\".backup\n-\tcollapse_todo_ids\n-\tgit_sequence_editor \"$todo\" ||\n-\t\tdie_abort \"$(gettext \"Could not execute editor\")\"\n-\n-\thas_action \"$todo\" ||\n-\t\treturn 2\n-\n-\tgit rebase--helper --check-todo-list || {\n-\t\tret=$?\n-\t\tgit rebase--helper --checkout-onto \"$onto_name\" \"$onto\" \\\n-\t\t    \"$orig_head\" ${verbose:+--verbose}\n-\t\texit $ret\n-\t}\n-\n-\texpand_todo_ids\n-\n-\ttest -n \"$force_rebase\" ||\n-\tonto=\"$(git rebase--helper --skip-unnecessary-picks)\" ||\n-\tdie \"Could not skip unnecessary pick commands\"\n-\n-\tgit rebase--helper --checkout-onto \"$onto_name\" \"$onto\" \"$orig_head\" \\\n-\t    ${verbose:+--verbose}\n-\trequire_clean_work_tree \"rebase\"\n-\texec git rebase--helper ${force_rebase:+--no-ff} $allow_empty_message \\\n-\t     --continue\n-}\n-\n git_rebase__interactive () {\n \tinitiate_action \"$action\"\n \tret=$?\n@@ -193,5 +145,8 @@ git_rebase__interactive () {\n \t\t$revisions ${restrict_revision+^$restrict_revision} >\"$todo\" ||\n \tdie \"$(gettext \"Could not generate todo list\")\"\n \n-\tcomplete_action\n+\texec git rebase--helper --complete-action \"$shortrevisions\" \"$onto_name\" \\\n+\t\t\"$shortonto\" \"$orig_head\" \"$cmd\" $allow_empty_message \\\n+\t\t${autosquash:+--autosquash} ${keep_empty:+--keep-empty} \\\n+\t\t${verbose:+--verbose} ${force_rebase:+--no-ff}\n }\ndiff --git a/git-rebase.sh b/git-rebase.sh\nindex 7973447645..51a6db7daa 100755\n--- a/git-rebase.sh\n+++ b/git-rebase.sh\n@@ -219,7 +219,7 @@ run_specific_rebase () {\n \tif test $ret -eq 0\n \tthen\n \t\tfinish_rebase\n-\telif test $ret -eq 2 # special exit status for rebase -i\n+\telif test $ret -eq 2 # special exit status for rebase -p\n \tthen\n \t\tapply_autostash &&\n \t\trm -rf \"$state_dir\" &&\ndiff --git a/sequencer.c b/sequencer.c\nindex a2e04b9eca..8102e24b19 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -30,6 +30,7 @@\n #include \"oidset.h\"\n #include \"commit-slab.h\"\n #include \"alias.h\"\n+#include \"rebase-interactive.h\"\n \n #define GIT_REFLOG_ACTION \"GIT_REFLOG_ACTION\"\n \n@@ -53,6 +54,9 @@ static GIT_PATH_FUNC(rebase_path, \"rebase-merge\")\n  * file and written to the tail of 'done'.\n  */\n GIT_PATH_FUNC(rebase_path_todo, \"rebase-merge/git-rebase-todo\")\n+static GIT_PATH_FUNC(rebase_path_todo_backup,\n+\t\t     \"rebase-merge/git-rebase-todo.backup\")\n+\n /*\n  * The rebase command lines that have already been processed. A line\n  * is moved here when it is first handled, before any associated user\n@@ -4499,6 +4503,101 @@ int skip_unnecessary_picks(struct object_id *output_oid)\n \treturn 0;\n }\n \n+int complete_action(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, const char *cmd,\n+\t\t    unsigned autosquash)\n+{\n+\tconst char *shortonto, *todo_file = rebase_path_todo();\n+\tstruct todo_list todo_list = TODO_LIST_INIT;\n+\tstruct strbuf *buf = &(todo_list.buf);\n+\tstruct object_id oid;\n+\tstruct stat st;\n+\n+\tget_oid(onto, &oid);\n+\tshortonto = find_unique_abbrev(&oid, DEFAULT_ABBREV);\n+\n+\tif (!lstat(todo_file, &st) && st.st_size == 0 &&\n+\t    write_message(\"noop\\n\", 5, todo_file, 0))\n+\t\treturn error_errno(_(\"could not write '%s'\"), todo_file);\n+\n+\tif (autosquash && rearrange_squash())\n+\t\treturn 1;\n+\n+\tif (cmd && *cmd)\n+\t\tsequencer_add_exec_commands(cmd);\n+\n+\tif (strbuf_read_file(buf, todo_file, 0) < 0)\n+\t\treturn error_errno(_(\"could not read '%s'.\"), todo_file);\n+\n+\tif (parse_insn_buffer(buf->buf, &todo_list)) {\n+\t\ttodo_list_release(&todo_list);\n+\t\treturn error(_(\"unusable todo list: '%s'\"), todo_file);\n+\t}\n+\n+\tif (count_commands(&todo_list) == 0) {\n+\t\tapply_autostash(opts);\n+\t\tsequencer_remove_state(opts);\n+\t\ttodo_list_release(&todo_list);\n+\n+\t\tfputs(\"Nothing to do\\n\", stderr);\n+\t\treturn 1;\n+\t}\n+\n+\tstrbuf_addch(buf, '\\n');\n+\tstrbuf_commented_addf(buf, Q_(\"Rebase %s onto %s (%d command)\",\n+\t\t\t\t      \"Rebase %s onto %s (%d commands)\",\n+\t\t\t\t      count_commands(&todo_list)),\n+\t\t\t      shortrevisions, shortonto, count_commands(&todo_list));\n+\tappend_todo_help(0, flags & TODO_LIST_KEEP_EMPTY, buf);\n+\n+\tif (write_message(buf->buf, buf->len, todo_file, 0)) {\n+\t\ttodo_list_release(&todo_list);\n+\t\treturn error_errno(_(\"could not write '%s'\"), todo_file);\n+\t}\n+\n+\tcopy_file(rebase_path_todo_backup(), todo_file, 0666);\n+\ttransform_todos(flags | TODO_LIST_SHORTEN_IDS);\n+\n+\tstrbuf_reset(buf);\n+\n+\tif (launch_sequence_editor(todo_file, buf, NULL)) {\n+\t\tapply_autostash(opts);\n+\t\tsequencer_remove_state(opts);\n+\t\ttodo_list_release(&todo_list);\n+\n+\t\treturn error(_(\"could not execute editor\"));\n+\t}\n+\n+\tstrbuf_stripspace(buf, 1);\n+\tif (buf->len == 0) {\n+\t\tapply_autostash(opts);\n+\t\tsequencer_remove_state(opts);\n+\t\ttodo_list_release(&todo_list);\n+\n+\t\tfputs(\"Nothing to do\\n\", stderr);\n+\t\treturn 1;\n+\t}\n+\n+\ttodo_list_release(&todo_list);\n+\n+\tif (check_todo_list()) {\n+\t\tcheckout_onto(opts, onto_name, onto, orig_head);\n+\t\treturn 1;\n+\t}\n+\n+\ttransform_todos(flags & ~(TODO_LIST_SHORTEN_IDS));\n+\n+\tif (opts->allow_ff && skip_unnecessary_picks(&oid))\n+\t\treturn error(_(\"could not skip unnecessary pick commands\"));\n+\n+\tcheckout_onto(opts, onto_name, oid_to_hex(&oid), orig_head);\n+\tif (require_clean_work_tree(\"rebase\", \"\", 1, 1))\n+\t\treturn 1;\n+\n+\treturn sequencer_continue(opts);\n+}\n+\n struct subject2item_entry {\n \tstruct hashmap_entry entry;\n \tint i;\ndiff --git a/sequencer.h b/sequencer.h\nindex f11dabfd65..3ab3791c8a 100644\n--- a/sequencer.h\n+++ b/sequencer.h\n@@ -89,6 +89,10 @@ int transform_todos(unsigned flags);\n enum missing_commit_check_level get_missing_commit_check_level(void);\n int check_todo_list(void);\n int skip_unnecessary_picks(struct object_id *output_oid);\n+int complete_action(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, const char *cmd,\n+\t\t    unsigned autosquash);\n int rearrange_squash(void);\n \n extern const char sign_off_header[];\n-- \n2.18.0\n\n"},{"id":"354087","messageId":"20180731180003.5421-13-alban.gruin@gmail.com","threadId":"48814","inReplyTo":"20180731180003.5421-1-alban.gruin@gmail.com","subject":"[GSoC][PATCH v5 12/20] rebase -i: remove unused modes and functions","fromName":"Alban Gruin","fromEmail":"alban.gruin@gmail.com","sentAt":"2018-07-31T17:59:55Z","receivedAt":"2018-07-31T18:00:43Z","isPatch":true,"sender":{"key":"alban.gruin@gmail.com","avatar":"https://avatars.githubusercontent.com/u/6310153?v=4"},"body":"This removes the modes `--skip-unnecessary-picks`, `--append-todo-help`,\nand `--checkout-onto` from rebase--helper.c, the functions of\ngit-rebase--interactive.sh that were rendered useless by the rewrite of\ncomplete_action(), and append_todo_help_to_file() from\nrebase-interactive.c.\n\nskip_unnecessary_picks() and checkout_onto() becomes static, as they are\nonly used inside of the sequencer.\n\nSigned-off-by: Alban Gruin <alban.gruin@gmail.com>\n---\nNo changes since v4.\n\n builtin/rebase--helper.c   | 23 ++----------------\n git-rebase--interactive.sh | 50 --------------------------------------\n rebase-interactive.c       | 22 -----------------\n rebase-interactive.h       |  1 -\n sequencer.c                |  8 +++---\n sequencer.h                |  4 ---\n 6 files changed, 6 insertions(+), 102 deletions(-)\n\ndiff --git a/builtin/rebase--helper.c b/builtin/rebase--helper.c\nindex d7fa5a5062..6085527b2b 100644\n--- a/builtin/rebase--helper.c\n+++ b/builtin/rebase--helper.c\n@@ -17,9 +17,8 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\n \tint abbreviate_commands = 0, rebase_cousins = -1;\n \tenum {\n \t\tCONTINUE = 1, ABORT, MAKE_SCRIPT, SHORTEN_OIDS, EXPAND_OIDS,\n-\t\tCHECK_TODO_LIST, SKIP_UNNECESSARY_PICKS, REARRANGE_SQUASH,\n-\t\tADD_EXEC, APPEND_TODO_HELP, EDIT_TODO, PREPARE_BRANCH,\n-\t\tCHECKOUT_ONTO, COMPLETE_ACTION\n+\t\tCHECK_TODO_LIST, REARRANGE_SQUASH, ADD_EXEC, EDIT_TODO, PREPARE_BRANCH,\n+\t\tCOMPLETE_ACTION\n \t} command = 0;\n \tstruct option options[] = {\n \t\tOPT_BOOL(0, \"ff\", &opts.allow_ff, N_(\"allow fast-forward\")),\n@@ -44,21 +43,15 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\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, \"skip-unnecessary-picks\", &command,\n-\t\t\tN_(\"skip unnecessary picks\"), SKIP_UNNECESSARY_PICKS),\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_CMDMODE(0, \"append-todo-help\", &command,\n-\t\t\t    N_(\"insert the help in the todo list\"), APPEND_TODO_HELP),\n \t\tOPT_CMDMODE(0, \"edit-todo\", &command,\n \t\t\t    N_(\"edit the todo list during an interactive rebase\"),\n \t\t\t    EDIT_TODO),\n \t\tOPT_CMDMODE(0, \"prepare-branch\", &command,\n \t\t\t    N_(\"prepare the branch to be rebased\"), PREPARE_BRANCH),\n-\t\tOPT_CMDMODE(0, \"checkout-onto\", &command,\n-\t\t\t    N_(\"checkout a commit\"), CHECKOUT_ONTO),\n \t\tOPT_CMDMODE(0, \"complete-action\", &command,\n \t\t\t    N_(\"complete the action\"), COMPLETE_ACTION),\n \t\tOPT_END()\n@@ -94,26 +87,14 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\n \t\treturn !!transform_todos(flags);\n \tif (command == CHECK_TODO_LIST && argc == 1)\n \t\treturn !!check_todo_list();\n-\tif (command == SKIP_UNNECESSARY_PICKS && argc == 1) {\n-\t\tstruct object_id oid;\n-\t\tint ret = skip_unnecessary_picks(&oid);\n-\n-\t\tif (!ret)\n-\t\t\tputs(oid_to_hex(&oid));\n-\t\treturn !!ret;\n-\t}\n \tif (command == REARRANGE_SQUASH && argc == 1)\n \t\treturn !!rearrange_squash();\n \tif (command == ADD_EXEC && argc == 2)\n \t\treturn !!sequencer_add_exec_commands(argv[1]);\n-\tif (command == APPEND_TODO_HELP && argc == 1)\n-\t\treturn !!append_todo_help_to_file(0, keep_empty);\n \tif (command == EDIT_TODO && argc == 1)\n \t\treturn !!edit_todo_list(flags);\n \tif (command == PREPARE_BRANCH && argc == 2)\n \t\treturn !!prepare_branch_to_be_rebased(&opts, argv[1]);\n-\tif (command == CHECKOUT_ONTO && argc == 4)\n-\t\treturn !!checkout_onto(&opts, argv[1], argv[2], argv[3]);\n \tif (command == COMPLETE_ACTION && argc == 6)\n \t\treturn !!complete_action(&opts, flags, argv[1], argv[2], argv[3],\n \t\t\t\t\t argv[4], argv[5], autosquash);\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex 59dc4888a6..0d66c0f8b8 100644\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -16,56 +16,6 @@ todo=\"$state_dir\"/git-rebase-todo\n GIT_CHERRY_PICK_HELP=\"$resolvemsg\"\n export GIT_CHERRY_PICK_HELP\n \n-comment_char=$(git config --get core.commentchar 2>/dev/null)\n-case \"$comment_char\" in\n-'' | auto)\n-\tcomment_char=\"#\"\n-\t;;\n-?)\n-\t;;\n-*)\n-\tcomment_char=$(echo \"$comment_char\" | cut -c1)\n-\t;;\n-esac\n-\n-die_abort () {\n-\tapply_autostash\n-\trm -rf \"$state_dir\"\n-\tdie \"$1\"\n-}\n-\n-has_action () {\n-\ttest -n \"$(git stripspace --strip-comments <\"$1\")\"\n-}\n-\n-git_sequence_editor () {\n-\tif test -z \"$GIT_SEQUENCE_EDITOR\"\n-\tthen\n-\t\tGIT_SEQUENCE_EDITOR=\"$(git config sequence.editor)\"\n-\t\tif [ -z \"$GIT_SEQUENCE_EDITOR\" ]\n-\t\tthen\n-\t\t\tGIT_SEQUENCE_EDITOR=\"$(git var GIT_EDITOR)\" || return $?\n-\t\tfi\n-\tfi\n-\n-\teval \"$GIT_SEQUENCE_EDITOR\" '\"$@\"'\n-}\n-\n-expand_todo_ids() {\n-\tgit rebase--helper --expand-ids\n-}\n-\n-collapse_todo_ids() {\n-\tgit rebase--helper --shorten-ids\n-}\n-\n-get_missing_commit_check_level () {\n-\tcheck_level=$(git config --get rebase.missingCommitsCheck)\n-\tcheck_level=${check_level:-ignore}\n-\t# Don't be case sensitive\n-\tprintf '%s' \"$check_level\" | tr 'A-Z' 'a-z'\n-}\n-\n # Initiate an action. If the cannot be any\n # further action it  may exec a command\n # or exit and not return.\ndiff --git a/rebase-interactive.c b/rebase-interactive.c\nindex d8b9465597..f99e596d28 100644\n--- a/rebase-interactive.c\n+++ b/rebase-interactive.c\n@@ -52,28 +52,6 @@ void append_todo_help(unsigned edit_todo, unsigned keep_empty,\n \t}\n }\n \n-int append_todo_help_to_file(unsigned edit_todo, unsigned keep_empty)\n-{\n-\tstruct strbuf buf = STRBUF_INIT;\n-\tFILE *todo;\n-\tint ret;\n-\n-\ttodo = fopen_or_warn(rebase_path_todo(), \"a\");\n-\tif (!todo)\n-\t\treturn 1;\n-\n-\tappend_todo_help(edit_todo, keep_empty, &buf);\n-\n-\tret = fputs(buf.buf, todo);\n-\tif (ret < 0)\n-\t\terror_errno(_(\"could not append help text to '%s'\"), rebase_path_todo());\n-\n-\tfclose(todo);\n-\tstrbuf_release(&buf);\n-\n-\treturn ret;\n-}\n-\n int edit_todo_list(unsigned flags)\n {\n \tstruct strbuf buf = STRBUF_INIT;\ndiff --git a/rebase-interactive.h b/rebase-interactive.h\nindex d33f3176b7..971da03776 100644\n--- a/rebase-interactive.h\n+++ b/rebase-interactive.h\n@@ -3,7 +3,6 @@\n \n void append_todo_help(unsigned edit_todo, unsigned keep_empty,\n \t\t      struct strbuf *buf);\n-int append_todo_help_to_file(unsigned edit_todo, unsigned keep_empty);\n int edit_todo_list(unsigned flags);\n \n #endif\ndiff --git a/sequencer.c b/sequencer.c\nindex 8102e24b19..58107932fd 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -3175,9 +3175,9 @@ int prepare_branch_to_be_rebased(struct replay_opts *opts, const char *commit)\n \treturn 0;\n }\n \n-int checkout_onto(struct replay_opts *opts,\n-\t\t  const char *onto_name, const char *onto,\n-\t\t  const char *orig_head)\n+static int checkout_onto(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 \tstruct object_id oid;\n \tconst char *action = reflog_message(opts, \"start\", \"checkout %s\", onto_name);\n@@ -4424,7 +4424,7 @@ static int rewrite_file(const char *path, const char *buf, size_t len)\n }\n \n /* skip picking commits whose parents are unchanged */\n-int skip_unnecessary_picks(struct object_id *output_oid)\n+static int skip_unnecessary_picks(struct object_id *output_oid)\n {\n \tconst char *todo_file = rebase_path_todo();\n \tstruct strbuf buf = STRBUF_INIT;\ndiff --git a/sequencer.h b/sequencer.h\nindex 3ab3791c8a..de9d4cf430 100644\n--- a/sequencer.h\n+++ b/sequencer.h\n@@ -88,7 +88,6 @@ int sequencer_add_exec_commands(const char *command);\n int transform_todos(unsigned flags);\n enum missing_commit_check_level get_missing_commit_check_level(void);\n int check_todo_list(void);\n-int skip_unnecessary_picks(struct object_id *output_oid);\n int complete_action(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, const char *cmd,\n@@ -111,9 +110,6 @@ void commit_post_rewrite(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 checkout_onto(struct replay_opts *opts,\n-\t\t  const char *onto_name, const char *onto,\n-\t\t  const char *orig_head);\n \n #define SUMMARY_INITIAL_COMMIT   (1 << 0)\n #define SUMMARY_SHOW_AUTHOR_DATE (1 << 1)\n-- \n2.18.0\n\n"},{"id":"354088","messageId":"20180731180003.5421-14-alban.gruin@gmail.com","threadId":"48814","inReplyTo":"20180731180003.5421-1-alban.gruin@gmail.com","subject":"[GSoC][PATCH v5 13/20] rebase -i: implement the logic to initialize $revisions in C","fromName":"Alban Gruin","fromEmail":"alban.gruin@gmail.com","sentAt":"2018-07-31T17:59:56Z","receivedAt":"2018-07-31T18:00:44Z","isPatch":true,"sender":{"key":"alban.gruin@gmail.com","avatar":"https://avatars.githubusercontent.com/u/6310153?v=4"},"body":"This rewrites the part of init_revisions_and_shortrevisions() needed by\n`--make-script` from shell to C.  The new version is called\nget_revision_ranges(), and is a static function inside of\nrebase--helper.c.  As this does not initialize $shortrevision, the\noriginal shell version is not yet stripped.\n\nUnlike init_revisions_and_shortrevisions(), get_revision_ranges()\ndoesn’t write $squash_onto to the state directory, it’s done by the\nhandler of `--make-script` instead.\n\nFinally, this drops the $revision argument passed to `--make-script` in\ngit-rebase--interactive.sh, and rebase--helper is changed accordingly.\n\nSigned-off-by: Alban Gruin <alban.gruin@gmail.com>\n---\nNo changes since v4.\n\n builtin/rebase--helper.c   | 56 ++++++++++++++++++++++++++++++++++++--\n git-rebase--interactive.sh |  4 ++-\n 2 files changed, 56 insertions(+), 4 deletions(-)\n\ndiff --git a/builtin/rebase--helper.c b/builtin/rebase--helper.c\nindex 6085527b2b..15fa556f65 100644\n--- a/builtin/rebase--helper.c\n+++ b/builtin/rebase--helper.c\n@@ -4,6 +4,25 @@\n #include \"parse-options.h\"\n #include \"sequencer.h\"\n #include \"rebase-interactive.h\"\n+#include \"argv-array.h\"\n+\n+static GIT_PATH_FUNC(path_squash_onto, \"rebase-merge/squash-onto\")\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)\n+{\n+\tconst char *base_rev = upstream ? upstream : onto;\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+\treturn 0;\n+}\n \n static const char * const builtin_rebase_helper_usage[] = {\n \tN_(\"git rebase--helper [<options>]\"),\n@@ -14,7 +33,9 @@ int cmd_rebase__helper(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;\n+\tint abbreviate_commands = 0, rebase_cousins = -1, ret;\n+\tconst char *head_hash = NULL, *onto = NULL, *restrict_revision = NULL,\n+\t\t*squash_onto = NULL, *upstream = NULL;\n \tenum {\n \t\tCONTINUE = 1, ABORT, MAKE_SCRIPT, SHORTEN_OIDS, EXPAND_OIDS,\n \t\tCHECK_TODO_LIST, REARRANGE_SQUASH, ADD_EXEC, EDIT_TODO, PREPARE_BRANCH,\n@@ -54,6 +75,13 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\n \t\t\t    N_(\"prepare the branch to be rebased\"), PREPARE_BRANCH),\n \t\tOPT_CMDMODE(0, \"complete-action\", &command,\n \t\t\t    N_(\"complete the action\"), COMPLETE_ACTION),\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_END()\n \t};\n \n@@ -81,8 +109,30 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\n \t\treturn !!sequencer_continue(&opts);\n \tif (command == ABORT && argc == 1)\n \t\treturn !!sequencer_remove_state(&opts);\n-\tif (command == MAKE_SCRIPT && argc > 1)\n-\t\treturn !!sequencer_make_script(stdout, argc, argv, flags);\n+\tif (command == MAKE_SCRIPT && argc == 1) {\n+\t\tchar *revisions = NULL;\n+\t\tstruct argv_array make_script_args = ARGV_ARRAY_INIT;\n+\n+\t\tif (!upstream && squash_onto)\n+\t\t\twrite_file(path_squash_onto(), \"%s\\n\", squash_onto);\n+\n+\t\tret = get_revision_ranges(upstream, onto, &head_hash, &revisions);\n+\t\tif (ret)\n+\t\t\treturn ret;\n+\n+\t\targv_array_pushl(&make_script_args, \"\", revisions, NULL);\n+\t\tif (restrict_revision)\n+\t\t\targv_array_push(&make_script_args, restrict_revision);\n+\n+\t\tret = sequencer_make_script(stdout,\n+\t\t\t\t\t    make_script_args.argc, make_script_args.argv,\n+\t\t\t\t\t    flags);\n+\n+\t\tfree(revisions);\n+\t\targv_array_clear(&make_script_args);\n+\n+\t\treturn !!ret;\n+\t}\n \tif ((command == SHORTEN_OIDS || command == EXPAND_OIDS) && argc == 1)\n \t\treturn !!transform_todos(flags);\n \tif (command == CHECK_TODO_LIST && argc == 1)\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex 0d66c0f8b8..4ca47aed1e 100644\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -92,7 +92,9 @@ git_rebase__interactive () {\n \tgit rebase--helper --make-script ${keep_empty:+--keep-empty} \\\n \t\t${rebase_merges:+--rebase-merges} \\\n \t\t${rebase_cousins:+--rebase-cousins} \\\n-\t\t$revisions ${restrict_revision+^$restrict_revision} >\"$todo\" ||\n+\t\t${upstream:+--upstream \"$upstream\"} ${onto:+--onto \"$onto\"} \\\n+\t\t${squash_onto:+--squash-onto \"$squash_onto\"} \\\n+\t\t${restrict_revision:+--restrict-revision ^\"$restrict_revision\"} >\"$todo\" ||\n \tdie \"$(gettext \"Could not generate todo list\")\"\n \n \texec git rebase--helper --complete-action \"$shortrevisions\" \"$onto_name\" \\\n-- \n2.18.0\n\n"},{"id":"354089","messageId":"20180731180003.5421-15-alban.gruin@gmail.com","threadId":"48814","inReplyTo":"20180731180003.5421-1-alban.gruin@gmail.com","subject":"[GSoC][PATCH v5 14/20] rebase -i: rewrite the rest of init_revisions_and_shortrevisions() in C","fromName":"Alban Gruin","fromEmail":"alban.gruin@gmail.com","sentAt":"2018-07-31T17:59:57Z","receivedAt":"2018-07-31T18:00:45Z","isPatch":true,"sender":{"key":"alban.gruin@gmail.com","avatar":"https://avatars.githubusercontent.com/u/6310153?v=4"},"body":"This rewrites the part of init_revisions_and_shortrevisions() needed by\n`--complete-action` (which initialize $shortrevisions) from shell to C.\n\nWhen `upstream` is empty, it means that the user launched a `rebase\n--root`, and `onto` contains the ID of an empty commit.  As a range\nbetween an empty commit and `head` is not really meaningful, `onto` is\nnot used to initialize `shortrevisions` in this case.\n\nThe corresponding arguments passed to `--complete-action` are then\ndropped, and init_revisions_and_shortrevisions() is stripped from\ngit-rebase--interactive.sh\n\nSigned-off-by: Alban Gruin <alban.gruin@gmail.com>\n---\nNo changes since v4.\n\n builtin/rebase--helper.c   | 40 ++++++++++++++++++++++++++++++++------\n git-rebase--interactive.sh | 27 ++++---------------------\n 2 files changed, 38 insertions(+), 29 deletions(-)\n\ndiff --git a/builtin/rebase--helper.c b/builtin/rebase--helper.c\nindex 15fa556f65..c4a4c5cfbb 100644\n--- a/builtin/rebase--helper.c\n+++ b/builtin/rebase--helper.c\n@@ -10,7 +10,7 @@ static GIT_PATH_FUNC(path_squash_onto, \"rebase-merge/squash-onto\")\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)\n+\t\t\t       char **revisions, char **shortrevisions)\n {\n \tconst char *base_rev = upstream ? upstream : onto;\n \tstruct object_id orig_head;\n@@ -19,7 +19,25 @@ static int get_revision_ranges(const char *upstream, const char *onto,\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+\tif (revisions)\n+\t\t*revisions = xstrfmt(\"%s...%s\", base_rev, *head_hash);\n+\tif (shortrevisions) {\n+\t\tconst char *shorthead;\n+\n+\t\tshorthead = find_unique_abbrev(&orig_head, DEFAULT_ABBREV);\n+\n+\t\tif (upstream) {\n+\t\t\tconst char *shortrev;\n+\t\t\tstruct object_id rev_oid;\n+\n+\t\t\tget_oid(base_rev, &rev_oid);\n+\t\t\tshortrev = find_unique_abbrev(&rev_oid, DEFAULT_ABBREV);\n+\n+\t\t\t*shortrevisions = xstrfmt(\"%s..%s\", shortrev, shorthead);\n+\t\t} else\n+\t\t\t*shortrevisions = xstrdup(shorthead);\n+\t}\n \n \treturn 0;\n }\n@@ -116,7 +134,7 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\n \t\tif (!upstream && squash_onto)\n \t\t\twrite_file(path_squash_onto(), \"%s\\n\", squash_onto);\n \n-\t\tret = get_revision_ranges(upstream, onto, &head_hash, &revisions);\n+\t\tret = get_revision_ranges(upstream, onto, &head_hash, &revisions, NULL);\n \t\tif (ret)\n \t\t\treturn ret;\n \n@@ -145,9 +163,19 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\n \t\treturn !!edit_todo_list(flags);\n \tif (command == PREPARE_BRANCH && argc == 2)\n \t\treturn !!prepare_branch_to_be_rebased(&opts, argv[1]);\n-\tif (command == COMPLETE_ACTION && argc == 6)\n-\t\treturn !!complete_action(&opts, flags, argv[1], argv[2], argv[3],\n-\t\t\t\t\t argv[4], argv[5], autosquash);\n+\tif (command == COMPLETE_ACTION && argc == 3) {\n+\t\tchar *shortrevisions = NULL;\n+\n+\t\tret = get_revision_ranges(upstream, onto, &head_hash, NULL, &shortrevisions);\n+\t\tif (ret)\n+\t\t\treturn ret;\n+\n+\t\tret = complete_action(&opts, flags, shortrevisions, argv[1], onto,\n+\t\t\t\t      head_hash, argv[2], autosquash);\n+\n+\t\tfree(shortrevisions);\n+\t\treturn !!ret;\n+\t}\n \n \tusage_with_options(builtin_rebase_helper_usage, options);\n }\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex 4ca47aed1e..08e9a21c2f 100644\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -60,23 +60,6 @@ init_basic_state () {\n \twrite_basic_state\n }\n \n-init_revisions_and_shortrevisions () {\n-\tshorthead=$(git rev-parse --short $orig_head)\n-\tshortonto=$(git rev-parse --short $onto)\n-\tif test -z \"$rebase_root\"\n-\t\t# this is now equivalent to ! -z \"$upstream\"\n-\tthen\n-\t\tshortupstream=$(git rev-parse --short $upstream)\n-\t\trevisions=$upstream...$orig_head\n-\t\tshortrevisions=$shortupstream..$shorthead\n-\telse\n-\t\trevisions=$onto...$orig_head\n-\t\tshortrevisions=$shorthead\n-\t\ttest -z \"$squash_onto\" ||\n-\t\techo \"$squash_onto\" >\"$state_dir\"/squash-onto\n-\tfi\n-}\n-\n git_rebase__interactive () {\n \tinitiate_action \"$action\"\n \tret=$?\n@@ -87,8 +70,6 @@ git_rebase__interactive () {\n \tgit rebase--helper --prepare-branch \"$switch_to\" ${verbose:+--verbose}\n \tinit_basic_state\n \n-\tinit_revisions_and_shortrevisions\n-\n \tgit rebase--helper --make-script ${keep_empty:+--keep-empty} \\\n \t\t${rebase_merges:+--rebase-merges} \\\n \t\t${rebase_cousins:+--rebase-cousins} \\\n@@ -97,8 +78,8 @@ git_rebase__interactive () {\n \t\t${restrict_revision:+--restrict-revision ^\"$restrict_revision\"} >\"$todo\" ||\n \tdie \"$(gettext \"Could not generate todo list\")\"\n \n-\texec git rebase--helper --complete-action \"$shortrevisions\" \"$onto_name\" \\\n-\t\t\"$shortonto\" \"$orig_head\" \"$cmd\" $allow_empty_message \\\n-\t\t${autosquash:+--autosquash} ${keep_empty:+--keep-empty} \\\n-\t\t${verbose:+--verbose} ${force_rebase:+--no-ff}\n+\texec git rebase--helper --complete-action \"$onto_name\" \"$cmd\" \\\n+\t\t$allow_empty_message ${autosquash:+--autosquash} ${verbose:+--verbose} \\\n+\t\t${keep_empty:+--keep-empty} ${force_rebase:+--no-ff} \\\n+\t\t${upstream:+--upstream \"$upstream\"} ${onto:+--onto \"$onto\"}\n }\n-- \n2.18.0\n\n"},{"id":"354090","messageId":"20180731180003.5421-17-alban.gruin@gmail.com","threadId":"48814","inReplyTo":"20180731180003.5421-1-alban.gruin@gmail.com","subject":"[GSoC][PATCH v5 16/20] rebase -i: rewrite init_basic_state() in C","fromName":"Alban Gruin","fromEmail":"alban.gruin@gmail.com","sentAt":"2018-07-31T17:59:59Z","receivedAt":"2018-07-31T18:00:48Z","isPatch":true,"sender":{"key":"alban.gruin@gmail.com","avatar":"https://avatars.githubusercontent.com/u/6310153?v=4"},"body":"This rewrites init_basic_state() from shell to C.  The call to\nwrite_basic_state() in cmd_rebase__helper() is replaced by a call to the\nnew function.\n\nThe shell version is then stripped from git-rebase--interactive.sh.\n\nSigned-off-by: Alban Gruin <alban.gruin@gmail.com>\n---\nNo changes since v4.\n\n builtin/rebase--helper.c   | 23 ++++++++++++++++++++++-\n git-rebase--interactive.sh |  9 ---------\n 2 files changed, 22 insertions(+), 10 deletions(-)\n\ndiff --git a/builtin/rebase--helper.c b/builtin/rebase--helper.c\nindex 06fe3c018b..ac21e8e06e 100644\n--- a/builtin/rebase--helper.c\n+++ b/builtin/rebase--helper.c\n@@ -5,10 +5,13 @@\n #include \"sequencer.h\"\n #include \"rebase-interactive.h\"\n #include \"argv-array.h\"\n+#include \"refs.h\"\n #include \"rerere.h\"\n #include \"alias.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 get_revision_ranges(const char *upstream, const char *onto,\n \t\t\t       const char **head_hash,\n@@ -44,6 +47,24 @@ static int get_revision_ranges(const char *upstream, const char *onto,\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 const char * const builtin_rebase_helper_usage[] = {\n \tN_(\"git rebase--helper [<options>]\"),\n \tNULL\n@@ -198,7 +219,7 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\n \t\tif (ret)\n \t\t\treturn ret;\n \n-\t\treturn !!write_basic_state(&opts, head_name, onto, head_hash);\n+\t\treturn !!init_basic_state(&opts, head_name, onto, head_hash);\n \t}\n \n \tusage_with_options(builtin_rebase_helper_usage, options);\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex 6367da66e2..761be95ed1 100644\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -51,14 +51,6 @@ initiate_action () {\n \tesac\n }\n \n-init_basic_state () {\n-\torig_head=$(git rev-parse --verify HEAD) || die \"$(gettext \"No HEAD?\")\"\n-\tmkdir -p \"$state_dir\" || die \"$(eval_gettext \"Could not create temporary \\$state_dir\")\"\n-\trm -f \"$(git rev-parse --git-path REBASE_HEAD)\"\n-\n-\t: > \"$state_dir\"/interactive || die \"$(gettext \"Could not mark as interactive\")\"\n-}\n-\n git_rebase__interactive () {\n \tinitiate_action \"$action\"\n \tret=$?\n@@ -67,7 +59,6 @@ git_rebase__interactive () {\n \tfi\n \n \tgit rebase--helper --prepare-branch \"$switch_to\" ${verbose:+--verbose}\n-\tinit_basic_state\n \n \tgit rebase--helper --init-basic-state ${upstream:+--upstream \"$upstream\"} \\\n \t\t${onto:+--onto \"$onto\"} ${head_name:+--head-name \"$head_name\"} \\\n-- \n2.18.0\n\n"},{"id":"354093","messageId":"20180731180003.5421-16-alban.gruin@gmail.com","threadId":"48814","inReplyTo":"20180731180003.5421-1-alban.gruin@gmail.com","subject":"[GSoC][PATCH v5 15/20] rebase -i: rewrite write_basic_state() in C","fromName":"Alban Gruin","fromEmail":"alban.gruin@gmail.com","sentAt":"2018-07-31T17:59:58Z","receivedAt":"2018-07-31T18:00:49Z","isPatch":true,"sender":{"key":"alban.gruin@gmail.com","avatar":"https://avatars.githubusercontent.com/u/6310153?v=4"},"body":"This rewrites write_basic_state() from git-rebase.sh in C.  This is the\nfirst step in the conversion of init_basic_state(), hence the mode in\nrebase--helper.c is called INIT_BASIC_STATE.  init_basic_state() will be\nconverted in the next commit.\n\nThe part of read_strategy_opts() that parses the stategy options is\nmoved to a new function to allow its use in rebase--helper.c.\n\nFinally, the call to write_basic_state() is removed from\ngit-rebase--interactive.sh, replaced by a call to `--init-basic-state`.\n\nSigned-off-by: Alban Gruin <alban.gruin@gmail.com>\n---\n builtin/rebase--helper.c   | 28 +++++++++++++-\n git-rebase--interactive.sh |  7 +++-\n sequencer.c                | 77 ++++++++++++++++++++++++++++++++------\n sequencer.h                |  4 ++\n 4 files changed, 102 insertions(+), 14 deletions(-)\n\ndiff --git a/builtin/rebase--helper.c b/builtin/rebase--helper.c\nindex c4a4c5cfbb..06fe3c018b 100644\n--- a/builtin/rebase--helper.c\n+++ b/builtin/rebase--helper.c\n@@ -5,6 +5,8 @@\n #include \"sequencer.h\"\n #include \"rebase-interactive.h\"\n #include \"argv-array.h\"\n+#include \"rerere.h\"\n+#include \"alias.h\"\n \n static GIT_PATH_FUNC(path_squash_onto, \"rebase-merge/squash-onto\")\n \n@@ -53,11 +55,12 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\n \tunsigned flags = 0, keep_empty = 0, rebase_merges = 0, autosquash = 0;\n \tint abbreviate_commands = 0, rebase_cousins = -1, ret;\n \tconst char *head_hash = NULL, *onto = NULL, *restrict_revision = NULL,\n-\t\t*squash_onto = NULL, *upstream = NULL;\n+\t\t*squash_onto = NULL, *upstream = NULL, *head_name = NULL;\n+\tchar *raw_strategies = NULL;\n \tenum {\n \t\tCONTINUE = 1, ABORT, MAKE_SCRIPT, SHORTEN_OIDS, EXPAND_OIDS,\n \t\tCHECK_TODO_LIST, REARRANGE_SQUASH, ADD_EXEC, EDIT_TODO, PREPARE_BRANCH,\n-\t\tCOMPLETE_ACTION\n+\t\tCOMPLETE_ACTION, INIT_BASIC_STATE\n \t} command = 0;\n \tstruct option options[] = {\n \t\tOPT_BOOL(0, \"ff\", &opts.allow_ff, N_(\"allow fast-forward\")),\n@@ -69,6 +72,7 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\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 thas 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\tCONTINUE),\n@@ -93,6 +97,8 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\n \t\t\t    N_(\"prepare the branch to be rebased\"), PREPARE_BRANCH),\n \t\tOPT_CMDMODE(0, \"complete-action\", &command,\n \t\t\t    N_(\"complete the action\"), COMPLETE_ACTION),\n+\t\tOPT_CMDMODE(0, \"init-basic-state\", &command,\n+\t\t\t    N_(\"initialise the rebase state\"), INIT_BASIC_STATE),\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@@ -100,6 +106,14 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\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\tOPT_STRING('S', \"gpg-sign\", &opts.gpg_sign, N_(\"gpg-sign\"),\n+\t\t\t   N_(\"GPG-sign commits\")),\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_RERERE_AUTOUPDATE(&opts.allow_rerere_auto),\n \t\tOPT_END()\n \t};\n \n@@ -176,6 +190,16 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\n \t\tfree(shortrevisions);\n \t\treturn !!ret;\n \t}\n+\tif (command == INIT_BASIC_STATE) {\n+\t\tif (raw_strategies)\n+\t\t\tparse_strategy_opts(&opts, raw_strategies);\n+\n+\t\tret = get_revision_ranges(upstream, onto, &head_hash, NULL, NULL);\n+\t\tif (ret)\n+\t\t\treturn ret;\n+\n+\t\treturn !!write_basic_state(&opts, head_name, onto, head_hash);\n+\t}\n \n \tusage_with_options(builtin_rebase_helper_usage, options);\n }\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex 08e9a21c2f..6367da66e2 100644\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -57,7 +57,6 @@ init_basic_state () {\n \trm -f \"$(git rev-parse --git-path REBASE_HEAD)\"\n \n \t: > \"$state_dir\"/interactive || die \"$(gettext \"Could not mark as interactive\")\"\n-\twrite_basic_state\n }\n \n git_rebase__interactive () {\n@@ -70,6 +69,12 @@ git_rebase__interactive () {\n \tgit rebase--helper --prepare-branch \"$switch_to\" ${verbose:+--verbose}\n \tinit_basic_state\n \n+\tgit rebase--helper --init-basic-state ${upstream:+--upstream \"$upstream\"} \\\n+\t\t${onto:+--onto \"$onto\"} ${head_name:+--head-name \"$head_name\"} \\\n+\t\t${verbose:+--verbose} ${strategy:+--strategy \"$strategy\"} \\\n+\t\t${strategy_opts:+--strategy-opts=\"$strategy_opts\"} \\\n+\t\t\"$allow_rerere_autoupdate\" \"$gpg_sign_opt\" \"$signoff\" || exit\n+\n \tgit rebase--helper --make-script ${keep_empty:+--keep-empty} \\\n \t\t${rebase_merges:+--rebase-merges} \\\n \t\t${rebase_cousins:+--rebase-cousins} \\\ndiff --git a/sequencer.c b/sequencer.c\nindex 58107932fd..961511dcb2 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -144,7 +144,7 @@ static GIT_PATH_FUNC(rebase_path_refs_to_delete, \"rebase-merge/refs-to-delete\")\n \n /*\n  * The following files are written by git-rebase just after parsing the\n- * command-line (and are only consumed, not modified, by the sequencer).\n+ * command-line.\n  */\n static GIT_PATH_FUNC(rebase_path_gpg_sign_opt, \"rebase-merge/gpg_sign_opt\")\n static GIT_PATH_FUNC(rebase_path_orig_head, \"rebase-merge/orig-head\")\n@@ -156,6 +156,7 @@ static GIT_PATH_FUNC(rebase_path_autostash, \"rebase-merge/autostash\")\n static GIT_PATH_FUNC(rebase_path_strategy, \"rebase-merge/strategy\")\n static GIT_PATH_FUNC(rebase_path_strategy_opts, \"rebase-merge/strategy_opts\")\n static GIT_PATH_FUNC(rebase_path_allow_rerere_autoupdate, \"rebase-merge/allow_rerere_autoupdate\")\n+static GIT_PATH_FUNC(rebase_path_quiet, \"rebase-merge/quiet\")\n \n static int git_sequencer_config(const char *k, const char *v, void *cb)\n {\n@@ -2205,21 +2206,14 @@ static int populate_opts_cb(const char *key, const char *value, void *data)\n \treturn 0;\n }\n \n-static void read_strategy_opts(struct replay_opts *opts, struct strbuf *buf)\n+void parse_strategy_opts(struct replay_opts *opts, char *raw_opts)\n {\n \tint i;\n-\tchar *strategy_opts_string;\n+\tchar *strategy_opts_string = raw_opts;\n \n-\tstrbuf_reset(buf);\n-\tif (!read_oneliner(buf, rebase_path_strategy(), 0))\n-\t\treturn;\n-\topts->strategy = strbuf_detach(buf, NULL);\n-\tif (!read_oneliner(buf, rebase_path_strategy_opts(), 0))\n-\t\treturn;\n-\n-\tstrategy_opts_string = buf->buf;\n \tif (*strategy_opts_string == ' ')\n \t\tstrategy_opts_string++;\n+\n \topts->xopts_nr = split_cmdline(strategy_opts_string,\n \t\t\t\t       (const char ***)&opts->xopts);\n \tfor (i = 0; i < opts->xopts_nr; i++) {\n@@ -2230,6 +2224,18 @@ static void read_strategy_opts(struct replay_opts *opts, struct strbuf *buf)\n \t}\n }\n \n+static void read_strategy_opts(struct replay_opts *opts, struct strbuf *buf)\n+{\n+\tstrbuf_reset(buf);\n+\tif (!read_oneliner(buf, rebase_path_strategy(), 0))\n+\t\treturn;\n+\topts->strategy = strbuf_detach(buf, NULL);\n+\tif (!read_oneliner(buf, rebase_path_strategy_opts(), 0))\n+\t\treturn;\n+\n+\tparse_strategy_opts(opts, buf->buf);\n+}\n+\n static int read_populate_opts(struct replay_opts *opts)\n {\n \tif (is_rebase_i(opts)) {\n@@ -2297,6 +2303,55 @@ static int read_populate_opts(struct replay_opts *opts)\n \treturn 0;\n }\n \n+static void write_strategy_opts(struct replay_opts *opts)\n+{\n+\tint i;\n+\tstruct strbuf buf = STRBUF_INIT;\n+\n+\tfor (i = 0; i < opts->xopts_nr; ++i)\n+\t\tstrbuf_addf(&buf, \" --%s\", opts->xopts[i]);\n+\n+\twrite_file(rebase_path_strategy_opts(), \"%s\\n\", buf.buf);\n+\tstrbuf_release(&buf);\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+{\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+\tif (orig_head)\n+\t\twrite_file(rebase_path_orig_head(), \"%s\\n\", orig_head);\n+\n+\tif (quiet)\n+\t\twrite_file(rebase_path_quiet(), \"%s\\n\", quiet);\n+\telse\n+\t\twrite_file(rebase_path_quiet(), \"\\n\");\n+\n+\tif (opts->verbose)\n+\t\twrite_file(rebase_path_verbose(), \"\");\n+\tif (opts->strategy)\n+\t\twrite_file(rebase_path_strategy(), \"%s\\n\", opts->strategy);\n+\tif (opts->xopts_nr > 0)\n+\t\twrite_strategy_opts(opts);\n+\n+\tif (opts->allow_rerere_auto == RERERE_AUTOUPDATE)\n+\t\twrite_file(rebase_path_allow_rerere_autoupdate(), \"--rerere-autoupdate\\n\");\n+\telse if (opts->allow_rerere_auto == RERERE_NOAUTOUPDATE)\n+\t\twrite_file(rebase_path_allow_rerere_autoupdate(), \"--no-rerere-autoupdate\\n\");\n+\n+\tif (opts->gpg_sign)\n+\t\twrite_file(rebase_path_gpg_sign_opt(), \"-S%s\\n\", opts->gpg_sign);\n+\tif (opts->signoff)\n+\t\twrite_file(rebase_path_signoff(), \"--signoff\\n\");\n+\n+\treturn 0;\n+}\n+\n static int walk_revs_populate_todo(struct todo_list *todo_list,\n \t\t\t\tstruct replay_opts *opts)\n {\ndiff --git a/sequencer.h b/sequencer.h\nindex de9d4cf430..62045131ae 100644\n--- a/sequencer.h\n+++ b/sequencer.h\n@@ -116,3 +116,7 @@ int prepare_branch_to_be_rebased(struct replay_opts *opts, const char *commit);\n void print_commit_summary(const char *prefix, const struct object_id *oid,\n \t\t\t  unsigned int flags);\n #endif\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-- \n2.18.0\n\n"},{"id":"354092","messageId":"20180731180003.5421-18-alban.gruin@gmail.com","threadId":"48814","inReplyTo":"20180731180003.5421-1-alban.gruin@gmail.com","subject":"[GSoC][PATCH v5 17/20] rebase -i: implement the main part of interactive rebase as a builtin","fromName":"Alban Gruin","fromEmail":"alban.gruin@gmail.com","sentAt":"2018-07-31T18:00:00Z","receivedAt":"2018-07-31T18:00:51Z","isPatch":true,"sender":{"key":"alban.gruin@gmail.com","avatar":"https://avatars.githubusercontent.com/u/6310153?v=4"},"body":"This rewrites the part of interactive rebase which initializes the\nbasic state, make the script and complete the action, as a buitin, named\ngit-rebase--interactive2 for now.  Others modes (`--continue`,\n`--edit-todo`, etc.) will be rewritten in the next commit.\n\ngit-rebase--interactive.sh is modified to call git-rebase--interactive2\ninstead of git-rebase--helper.\n\nSigned-off-by: Alban Gruin <alban.gruin@gmail.com>\n---\nNo changes since v4.\n\n .gitignore                     |   1 +\n Makefile                       |   1 +\n builtin.h                      |   1 +\n builtin/rebase--interactive2.c | 200 +++++++++++++++++++++++++++++++++\n git-rebase--interactive.sh     |  41 +++----\n git.c                          |   1 +\n 6 files changed, 226 insertions(+), 19 deletions(-)\n create mode 100644 builtin/rebase--interactive2.c\n\ndiff --git a/.gitignore b/.gitignore\nindex 3284a1e9b1..404c9a8472 100644\n--- a/.gitignore\n+++ b/.gitignore\n@@ -118,6 +118,7 @@\n /git-rebase--am\n /git-rebase--helper\n /git-rebase--interactive\n+/git-rebase--interactive2\n /git-rebase--merge\n /git-rebase--preserve-merges\n /git-receive-pack\ndiff --git a/Makefile b/Makefile\nindex 909a687857..71f8f45fe5 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -1060,6 +1060,7 @@ BUILTIN_OBJS += builtin/prune.o\n BUILTIN_OBJS += builtin/pull.o\n BUILTIN_OBJS += builtin/push.o\n BUILTIN_OBJS += builtin/read-tree.o\n+BUILTIN_OBJS += builtin/rebase--interactive2.o\n BUILTIN_OBJS += builtin/rebase--helper.o\n BUILTIN_OBJS += builtin/receive-pack.o\n BUILTIN_OBJS += builtin/reflog.o\ndiff --git a/builtin.h b/builtin.h\nindex 0362f1ce25..ed89b4f495 100644\n--- a/builtin.h\n+++ b/builtin.h\n@@ -202,6 +202,7 @@ extern int cmd_prune_packed(int argc, const char **argv, const char *prefix);\n extern int cmd_pull(int argc, const char **argv, const char *prefix);\n extern int cmd_push(int argc, const char **argv, const char *prefix);\n extern int cmd_read_tree(int argc, const char **argv, const char *prefix);\n+extern int cmd_rebase__interactive(int argc, const char **argv, const char *prefix);\n extern int cmd_rebase__helper(int argc, const char **argv, const char *prefix);\n extern int cmd_receive_pack(int argc, const char **argv, const char *prefix);\n extern int cmd_reflog(int argc, const char **argv, const char *prefix);\ndiff --git a/builtin/rebase--interactive2.c b/builtin/rebase--interactive2.c\nnew file mode 100644\nindex 0000000000..e89ef71499\n--- /dev/null\n+++ b/builtin/rebase--interactive2.c\n@@ -0,0 +1,200 @@\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 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 const char *cmd, 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+\tFILE *todo_list;\n+\n+\tif (prepare_branch_to_be_rebased(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+\ttodo_list = fopen(rebase_path_todo(), \"w\");\n+\tif (!todo_list) {\n+\t\tfree(revisions);\n+\t\tfree(shortrevisions);\n+\n+\t\treturn error_errno(_(\"could not open %s\"), rebase_path_todo());\n+\t}\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(todo_list,\n+\t\t\t\t    make_script_args.argc, make_script_args.argv,\n+\t\t\t\t    flags);\n+\tfclose(todo_list);\n+\n+\tif (ret)\n+\t\terror(_(\"could not generate todo list\"));\n+\telse {\n+\t\tdiscard_cache();\n+\t\tret = complete_action(opts, flags, shortrevisions, onto_name, onto,\n+\t\t\t\t      head_hash, cmd, autosquash);\n+\t}\n+\n+\tfree(revisions);\n+\tfree(shortrevisions);\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;\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+\tchar *raw_strategies = NULL;\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_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\tOPT_STRING('S', \"gpg-sign\", &opts.gpg_sign, N_(\"gpg-sign\"),\n+\t\t\t   N_(\"GPG-sign commits\")),\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_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+\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+\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+\treturn !!do_interactive_rebase(&opts, flags, switch_to, upstream, onto,\n+\t\t\t\t       onto_name, squash_onto, head_name, restrict_revision,\n+\t\t\t\t       raw_strategies, cmd, autosquash);\n+}\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex 761be95ed1..e87d708a4d 100644\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -58,24 +58,27 @@ git_rebase__interactive () {\n \t\treturn 0\n \tfi\n \n-\tgit rebase--helper --prepare-branch \"$switch_to\" ${verbose:+--verbose}\n+\ttest -n \"$keep_empty\" && keep_empty=\"--keep-empty\"\n+\ttest -n \"$rebase_merges\" && rebase_merges=\"--rebase-merges\"\n+\ttest -n \"$rebase_cousins\" && rebase_cousins=\"--rebase-cousins\"\n+\ttest -n \"$autosquash\" && autosquash=\"--autosquash\"\n+\ttest -n \"$verbose\" && verbose=\"--verbose\"\n+\ttest -n \"$force_rebase\" && force_rebase=\"--no-ff\"\n+\ttest -n \"$restrict_revisions\" && restrict_revisions=\"--restrict-revisions=^$restrict_revisions\"\n+\ttest -n \"$upstream\" && upstream=\"--upstream=$upstream\"\n+\ttest -n \"$onto\" && onto=\"--onto=$onto\"\n+\ttest -n \"$squash_onto\" && squash_onto=\"--squash-onto=$squash_onto\"\n+\ttest -n \"$onto_name\" && onto_name=\"--onto-name=$onto_name\"\n+\ttest -n \"$head_name\" && head_name=\"--head-name=$head_name\"\n+\ttest -n \"$strategy\" && strategy=\"--strategy=$strategy\"\n+\ttest -n \"$strategy_opts\" && strategy_opts=\"--strategy-opts=$strategy_opts\"\n+\ttest -n \"$switch_to\" && switch_to=\"--switch-to=$switch_to\"\n+\ttest -n \"$cmd\" && cmd=\"--cmd=$cmd\"\n \n-\tgit rebase--helper --init-basic-state ${upstream:+--upstream \"$upstream\"} \\\n-\t\t${onto:+--onto \"$onto\"} ${head_name:+--head-name \"$head_name\"} \\\n-\t\t${verbose:+--verbose} ${strategy:+--strategy \"$strategy\"} \\\n-\t\t${strategy_opts:+--strategy-opts=\"$strategy_opts\"} \\\n-\t\t\"$allow_rerere_autoupdate\" \"$gpg_sign_opt\" \"$signoff\" || exit\n-\n-\tgit rebase--helper --make-script ${keep_empty:+--keep-empty} \\\n-\t\t${rebase_merges:+--rebase-merges} \\\n-\t\t${rebase_cousins:+--rebase-cousins} \\\n-\t\t${upstream:+--upstream \"$upstream\"} ${onto:+--onto \"$onto\"} \\\n-\t\t${squash_onto:+--squash-onto \"$squash_onto\"} \\\n-\t\t${restrict_revision:+--restrict-revision ^\"$restrict_revision\"} >\"$todo\" ||\n-\tdie \"$(gettext \"Could not generate todo list\")\"\n-\n-\texec git rebase--helper --complete-action \"$onto_name\" \"$cmd\" \\\n-\t\t$allow_empty_message ${autosquash:+--autosquash} ${verbose:+--verbose} \\\n-\t\t${keep_empty:+--keep-empty} ${force_rebase:+--no-ff} \\\n-\t\t${upstream:+--upstream \"$upstream\"} ${onto:+--onto \"$onto\"}\n+\texec git rebase--interactive2 \"$keep_empty\" \"$rebase_merges\" \"$rebase_cousins\" \\\n+\t\t\"$upstream\" \"$onto\" \"$squash_onto\" \"$restrict_revision\" \\\n+\t\t\"$allow_empty_message\" \"$autosquash\" \"$verbose\" \\\n+\t\t\"$force_rebase\" \"$onto_name\" \"$head_name\" \"$strategy\" \\\n+\t\t\"$strategy_opts\" \"$cmd\" \"$switch_to\" \\\n+\t\t\"$allow_rerere_autoupdate\" \"$gpg_sign_opt\" \"$signoff\"\n }\ndiff --git a/git.c b/git.c\nindex 3fded74519..8309fb24a6 100644\n--- a/git.c\n+++ b/git.c\n@@ -518,6 +518,7 @@ static struct cmd_struct commands[] = {\n \t{ \"pull\", cmd_pull, RUN_SETUP | NEED_WORK_TREE },\n \t{ \"push\", cmd_push, RUN_SETUP },\n \t{ \"read-tree\", cmd_read_tree, RUN_SETUP | SUPPORT_SUPER_PREFIX},\n+\t{ \"rebase--interactive2\", cmd_rebase__interactive, RUN_SETUP | NEED_WORK_TREE },\n \t{ \"rebase--helper\", cmd_rebase__helper, RUN_SETUP | NEED_WORK_TREE },\n \t{ \"receive-pack\", cmd_receive_pack },\n \t{ \"reflog\", cmd_reflog, RUN_SETUP },\n-- \n2.18.0\n\n"},{"id":"354091","messageId":"20180731180003.5421-20-alban.gruin@gmail.com","threadId":"48814","inReplyTo":"20180731180003.5421-1-alban.gruin@gmail.com","subject":"[GSoC][PATCH v5 19/20] rebase -i: remove git-rebase--interactive.sh","fromName":"Alban Gruin","fromEmail":"alban.gruin@gmail.com","sentAt":"2018-07-31T18:00:02Z","receivedAt":"2018-07-31T18:00:54Z","isPatch":true,"sender":{"key":"alban.gruin@gmail.com","avatar":"https://avatars.githubusercontent.com/u/6310153?v=4"},"body":"This removes git-rebase--interactive.sh, as its functionnality has been\nreplaced by git-rebase--interactive2.\n\ngit-rebase--interactive2.c is then renamed to git-rebase--interactive.c.\n\nSigned-off-by: Alban Gruin <alban.gruin@gmail.com>\n---\nNo changes since v4.\n\n .gitignore                                    |  1 -\n Makefile                                      |  4 +-\n ...--interactive2.c => rebase--interactive.c} |  0\n git-rebase--interactive.sh                    | 84 -------------------\n git-rebase.sh                                 |  2 +-\n git.c                                         |  2 +-\n 6 files changed, 3 insertions(+), 90 deletions(-)\n rename builtin/{rebase--interactive2.c => rebase--interactive.c} (100%)\n delete mode 100644 git-rebase--interactive.sh\n\ndiff --git a/.gitignore b/.gitignore\nindex 404c9a8472..3284a1e9b1 100644\n--- a/.gitignore\n+++ b/.gitignore\n@@ -118,7 +118,6 @@\n /git-rebase--am\n /git-rebase--helper\n /git-rebase--interactive\n-/git-rebase--interactive2\n /git-rebase--merge\n /git-rebase--preserve-merges\n /git-receive-pack\ndiff --git a/Makefile b/Makefile\nindex 71f8f45fe5..584834726d 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -619,7 +619,6 @@ SCRIPT_SH += git-web--browse.sh\n SCRIPT_LIB += git-mergetool--lib\n SCRIPT_LIB += git-parse-remote\n SCRIPT_LIB += git-rebase--am\n-SCRIPT_LIB += git-rebase--interactive\n SCRIPT_LIB += git-rebase--preserve-merges\n SCRIPT_LIB += git-rebase--merge\n SCRIPT_LIB += git-sh-setup\n@@ -1060,8 +1059,8 @@ BUILTIN_OBJS += builtin/prune.o\n BUILTIN_OBJS += builtin/pull.o\n BUILTIN_OBJS += builtin/push.o\n BUILTIN_OBJS += builtin/read-tree.o\n-BUILTIN_OBJS += builtin/rebase--interactive2.o\n BUILTIN_OBJS += builtin/rebase--helper.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\n@@ -2400,7 +2399,6 @@ XGETTEXT_FLAGS_PERL = $(XGETTEXT_FLAGS) --language=Perl \\\n LOCALIZED_C = $(C_OBJ:o=c) $(LIB_H) $(GENERATED_H)\n LOCALIZED_SH = $(SCRIPT_SH)\n LOCALIZED_SH += git-parse-remote.sh\n-LOCALIZED_SH += git-rebase--interactive.sh\n LOCALIZED_SH += git-rebase--preserve-merges.sh\n LOCALIZED_SH += git-sh-setup.sh\n LOCALIZED_PERL = $(SCRIPT_PERL)\ndiff --git a/builtin/rebase--interactive2.c b/builtin/rebase--interactive.c\nsimilarity index 100%\nrename from builtin/rebase--interactive2.c\nrename to builtin/rebase--interactive.c\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\ndeleted file mode 100644\nindex e87d708a4d..0000000000\n--- a/git-rebase--interactive.sh\n+++ /dev/null\n@@ -1,84 +0,0 @@\n-# This shell script fragment is sourced by git-rebase to implement\n-# its interactive mode.  \"git rebase --interactive\" makes it easy\n-# to fix up commits in the middle of a series and rearrange commits.\n-#\n-# Copyright (c) 2006 Johannes E. Schindelin\n-#\n-# The original idea comes from Eric W. Biederman, in\n-# https://public-inbox.org/git/m1odwkyuf5.fsf_-_@ebiederm.dsl.xmission.com/\n-#\n-# The file containing rebase commands, comments, and empty lines.\n-# This file is created by \"git rebase -i\" then edited by the user.  As\n-# the lines are processed, they are removed from the front of this\n-# file and written to the tail of $done.\n-todo=\"$state_dir\"/git-rebase-todo\n-\n-GIT_CHERRY_PICK_HELP=\"$resolvemsg\"\n-export GIT_CHERRY_PICK_HELP\n-\n-# Initiate an action. If the cannot be any\n-# further action it  may exec a command\n-# or exit and not return.\n-#\n-# TODO: Consider a cleaner return model so it\n-# never exits and always return 0 if process\n-# is complete.\n-#\n-# Parameter 1 is the action to initiate.\n-#\n-# Returns 0 if the action was able to complete\n-# and if 1 if further processing is required.\n-initiate_action () {\n-\tcase \"$1\" in\n-\tcontinue)\n-\t\texec git rebase--helper ${force_rebase:+--no-ff} $allow_empty_message \\\n-\t\t     --continue\n-\t\t;;\n-\tskip)\n-\t\tgit rerere clear\n-\t\texec git rebase--helper ${force_rebase:+--no-ff} $allow_empty_message \\\n-\t\t     --continue\n-\t\t;;\n-\tedit-todo)\n-\t\texec git rebase--helper --edit-todo\n-\t\t;;\n-\tshow-current-patch)\n-\t\texec git show REBASE_HEAD --\n-\t\t;;\n-\t*)\n-\t\treturn 1 # continue\n-\t\t;;\n-\tesac\n-}\n-\n-git_rebase__interactive () {\n-\tinitiate_action \"$action\"\n-\tret=$?\n-\tif test $ret = 0; then\n-\t\treturn 0\n-\tfi\n-\n-\ttest -n \"$keep_empty\" && keep_empty=\"--keep-empty\"\n-\ttest -n \"$rebase_merges\" && rebase_merges=\"--rebase-merges\"\n-\ttest -n \"$rebase_cousins\" && rebase_cousins=\"--rebase-cousins\"\n-\ttest -n \"$autosquash\" && autosquash=\"--autosquash\"\n-\ttest -n \"$verbose\" && verbose=\"--verbose\"\n-\ttest -n \"$force_rebase\" && force_rebase=\"--no-ff\"\n-\ttest -n \"$restrict_revisions\" && restrict_revisions=\"--restrict-revisions=^$restrict_revisions\"\n-\ttest -n \"$upstream\" && upstream=\"--upstream=$upstream\"\n-\ttest -n \"$onto\" && onto=\"--onto=$onto\"\n-\ttest -n \"$squash_onto\" && squash_onto=\"--squash-onto=$squash_onto\"\n-\ttest -n \"$onto_name\" && onto_name=\"--onto-name=$onto_name\"\n-\ttest -n \"$head_name\" && head_name=\"--head-name=$head_name\"\n-\ttest -n \"$strategy\" && strategy=\"--strategy=$strategy\"\n-\ttest -n \"$strategy_opts\" && strategy_opts=\"--strategy-opts=$strategy_opts\"\n-\ttest -n \"$switch_to\" && switch_to=\"--switch-to=$switch_to\"\n-\ttest -n \"$cmd\" && cmd=\"--cmd=$cmd\"\n-\n-\texec git rebase--interactive2 \"$keep_empty\" \"$rebase_merges\" \"$rebase_cousins\" \\\n-\t\t\"$upstream\" \"$onto\" \"$squash_onto\" \"$restrict_revision\" \\\n-\t\t\"$allow_empty_message\" \"$autosquash\" \"$verbose\" \\\n-\t\t\"$force_rebase\" \"$onto_name\" \"$head_name\" \"$strategy\" \\\n-\t\t\"$strategy_opts\" \"$cmd\" \"$switch_to\" \\\n-\t\t\"$allow_rerere_autoupdate\" \"$gpg_sign_opt\" \"$signoff\"\n-}\ndiff --git a/git-rebase.sh b/git-rebase.sh\nindex d5950a3012..a707d59412 100755\n--- a/git-rebase.sh\n+++ b/git-rebase.sh\n@@ -223,7 +223,7 @@ run_interactive () {\n \ttest -n \"$cmd\" && cmd=\"--cmd=$cmd\"\n \ttest -n \"$action\" && action=\"--$action\"\n \n-\texec git rebase--interactive2 \"$action\" \"$keep_empty\" \"$rebase_merges\" \"$rebase_cousins\" \\\n+\texec git rebase--interactive \"$action\" \"$keep_empty\" \"$rebase_merges\" \"$rebase_cousins\" \\\n \t\t\"$upstream\" \"$onto\" \"$squash_onto\" \"$restrict_revision\" \\\n \t\t\"$allow_empty_message\" \"$autosquash\" \"$verbose\" \\\n \t\t\"$force_rebase\" \"$onto_name\" \"$head_name\" \"$strategy\" \\\ndiff --git a/git.c b/git.c\nindex 8309fb24a6..19d0b6e3b8 100644\n--- a/git.c\n+++ b/git.c\n@@ -518,7 +518,7 @@ static struct cmd_struct commands[] = {\n \t{ \"pull\", cmd_pull, RUN_SETUP | NEED_WORK_TREE },\n \t{ \"push\", cmd_push, RUN_SETUP },\n \t{ \"read-tree\", cmd_read_tree, RUN_SETUP | SUPPORT_SUPER_PREFIX},\n-\t{ \"rebase--interactive2\", cmd_rebase__interactive, RUN_SETUP | NEED_WORK_TREE },\n+\t{ \"rebase--interactive\", cmd_rebase__interactive, RUN_SETUP | NEED_WORK_TREE },\n \t{ \"rebase--helper\", cmd_rebase__helper, RUN_SETUP | NEED_WORK_TREE },\n \t{ \"receive-pack\", cmd_receive_pack },\n \t{ \"reflog\", cmd_reflog, RUN_SETUP },\n-- \n2.18.0\n\n"},{"id":"354094","messageId":"20180731180003.5421-19-alban.gruin@gmail.com","threadId":"48814","inReplyTo":"20180731180003.5421-1-alban.gruin@gmail.com","subject":"[GSoC][PATCH v5 18/20] rebase--interactive2: rewrite the submodes of interactive rebase in C","fromName":"Alban Gruin","fromEmail":"alban.gruin@gmail.com","sentAt":"2018-07-31T18:00:01Z","receivedAt":"2018-07-31T18:00:55Z","isPatch":true,"sender":{"key":"alban.gruin@gmail.com","avatar":"https://avatars.githubusercontent.com/u/6310153?v=4"},"body":"This rewrites the submodes of interactive rebase (`--continue`,\n`--skip`, `--edit-todo`, and `--show-current-patch`) in C.\n\ngit-rebase.sh is then modified to call directly git-rebase--interactive2\ninstead of git-rebase--interactive.sh.\n\nSigned-off-by: Alban Gruin <alban.gruin@gmail.com>\n---\nNo changes since v4.\n\n builtin/rebase--interactive2.c | 47 +++++++++++++++++++++++++++++++---\n git-rebase.sh                  | 45 +++++++++++++++++++++++++++++---\n 2 files changed, 84 insertions(+), 8 deletions(-)\n\ndiff --git a/builtin/rebase--interactive2.c b/builtin/rebase--interactive2.c\nindex e89ef71499..53b4f7483d 100644\n--- a/builtin/rebase--interactive2.c\n+++ b/builtin/rebase--interactive2.c\n@@ -134,11 +134,14 @@ 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;\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 \tchar *raw_strategies = NULL;\n+\tenum {\n+\t\tNONE = 0, CONTINUE, SKIP, EDIT_TODO, SHOW_CURRENT_PATCH\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@@ -151,6 +154,13 @@ int cmd_rebase__interactive(int argc, const char **argv, const char *prefix)\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_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@@ -194,7 +204,36 @@ 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-\treturn !!do_interactive_rebase(&opts, flags, switch_to, upstream, onto,\n-\t\t\t\t       onto_name, squash_onto, head_name, restrict_revision,\n-\t\t\t\t       raw_strategies, cmd, autosquash);\n+\tswitch (command) {\n+\tcase NONE:\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, cmd, autosquash);\n+\t\tbreak;\n+\tcase SKIP: {\n+\t\tstruct string_list merge_rr = STRING_LIST_INIT_DUP;\n+\n+\t\trerere_clear(&merge_rr);\n+\t\t/* fallthrough */\n+\tcase CONTINUE:\n+\t\tret = sequencer_continue(&opts);\n+\t\tbreak;\n+\t}\n+\tcase EDIT_TODO:\n+\t\tret = edit_todo_list(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+\tdefault:\n+\t\tBUG(\"invalid command '%d'\", command);\n+\t}\n+\n+\treturn !!ret;\n }\ndiff --git a/git-rebase.sh b/git-rebase.sh\nindex 51a6db7daa..d5950a3012 100755\n--- a/git-rebase.sh\n+++ b/git-rebase.sh\n@@ -200,19 +200,56 @@ finish_rebase () {\n \trm -rf \"$state_dir\"\n }\n \n+run_interactive () {\n+\tGIT_CHERRY_PICK_HELP=\"$resolvemsg\"\n+\texport GIT_CHERRY_PICK_HELP\n+\n+\ttest -n \"$keep_empty\" && keep_empty=\"--keep-empty\"\n+\ttest -n \"$rebase_merges\" && rebase_merges=\"--rebase-merges\"\n+\ttest -n \"$rebase_cousins\" && rebase_cousins=\"--rebase-cousins\"\n+\ttest -n \"$autosquash\" && autosquash=\"--autosquash\"\n+\ttest -n \"$verbose\" && verbose=\"--verbose\"\n+\ttest -n \"$force_rebase\" && force_rebase=\"--no-ff\"\n+\ttest -n \"$restrict_revisions\" && \\\n+\t\trestrict_revisions=\"--restrict-revisions=^$restrict_revisions\"\n+\ttest -n \"$upstream\" && upstream=\"--upstream=$upstream\"\n+\ttest -n \"$onto\" && onto=\"--onto=$onto\"\n+\ttest -n \"$squash_onto\" && squash_onto=\"--squash-onto=$squash_onto\"\n+\ttest -n \"$onto_name\" && onto_name=\"--onto-name=$onto_name\"\n+\ttest -n \"$head_name\" && head_name=\"--head-name=$head_name\"\n+\ttest -n \"$strategy\" && strategy=\"--strategy=$strategy\"\n+\ttest -n \"$strategy_opts\" && strategy_opts=\"--strategy-opts=$strategy_opts\"\n+\ttest -n \"$switch_to\" && switch_to=\"--switch-to=$switch_to\"\n+\ttest -n \"$cmd\" && cmd=\"--cmd=$cmd\"\n+\ttest -n \"$action\" && action=\"--$action\"\n+\n+\texec git rebase--interactive2 \"$action\" \"$keep_empty\" \"$rebase_merges\" \"$rebase_cousins\" \\\n+\t\t\"$upstream\" \"$onto\" \"$squash_onto\" \"$restrict_revision\" \\\n+\t\t\"$allow_empty_message\" \"$autosquash\" \"$verbose\" \\\n+\t\t\"$force_rebase\" \"$onto_name\" \"$head_name\" \"$strategy\" \\\n+\t\t\"$strategy_opts\" \"$cmd\" \"$switch_to\" \\\n+\t\t\"$allow_rerere_autoupdate\" \"$gpg_sign_opt\" \"$signoff\"\n+}\n+\n run_specific_rebase () {\n \tif [ \"$interactive_rebase\" = implied ]; then\n \t\tGIT_EDITOR=:\n \t\texport GIT_EDITOR\n \t\tautosquash=\n \tfi\n-\t. git-rebase--$type\n \n-\tif test -z \"$preserve_merges\"\n+\tif test -n \"$interactive_rebase\" -a -z \"$preserve_merges\"\n \tthen\n-\t\tgit_rebase__$type\n+\t\trun_interactive\n \telse\n-\t\tgit_rebase__preserve_merges\n+\t\t. git-rebase--$type\n+\n+\t\tif test -z \"$preserve_merges\"\n+\t\tthen\n+\t\t\tgit_rebase__$type\n+\t\telse\n+\t\t\tgit_rebase__preserve_merges\n+\t\tfi\n \tfi\n \n \tret=$?\n-- \n2.18.0\n\n"},{"id":"354095","messageId":"20180731180003.5421-21-alban.gruin@gmail.com","threadId":"48814","inReplyTo":"20180731180003.5421-1-alban.gruin@gmail.com","subject":"[GSoC][PATCH v5 20/20] rebase -i: move rebase--helper modes to rebase--interactive","fromName":"Alban Gruin","fromEmail":"alban.gruin@gmail.com","sentAt":"2018-07-31T18:00:03Z","receivedAt":"2018-07-31T18:00:57Z","isPatch":true,"sender":{"key":"alban.gruin@gmail.com","avatar":"https://avatars.githubusercontent.com/u/6310153?v=4"},"body":"This moves the rebase--helper modes still used by\ngit-rebase--preserve-merges.sh (`--shorten-ids`, `--expand-ids`,\n`--check-todo-list`, `--rearrange-squash` and `--add-exec-commands`) to\nrebase--interactive.c.\n\ngit-rebase--preserve-merges.sh is modified accordingly, and\nrebase--helper.c is removed as it is useless now.\n\nSigned-off-by: Alban Gruin <alban.gruin@gmail.com>\n---\n .gitignore                     |   1 -\n Makefile                       |   1 -\n builtin.h                      |   1 -\n builtin/rebase--helper.c       | 226 ---------------------------------\n builtin/rebase--interactive.c  |  27 +++-\n git-rebase--preserve-merges.sh |  10 +-\n git.c                          |   1 -\n 7 files changed, 31 insertions(+), 236 deletions(-)\n delete mode 100644 builtin/rebase--helper.c\n\ndiff --git a/.gitignore b/.gitignore\nindex 3284a1e9b1..406f26d050 100644\n--- a/.gitignore\n+++ b/.gitignore\n@@ -116,7 +116,6 @@\n /git-read-tree\n /git-rebase\n /git-rebase--am\n-/git-rebase--helper\n /git-rebase--interactive\n /git-rebase--merge\n /git-rebase--preserve-merges\ndiff --git a/Makefile b/Makefile\nindex 584834726d..ca3a0888dd 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -1059,7 +1059,6 @@ BUILTIN_OBJS += builtin/prune.o\n BUILTIN_OBJS += builtin/pull.o\n BUILTIN_OBJS += builtin/push.o\n BUILTIN_OBJS += builtin/read-tree.o\n-BUILTIN_OBJS += builtin/rebase--helper.o\n BUILTIN_OBJS += builtin/rebase--interactive.o\n BUILTIN_OBJS += builtin/receive-pack.o\n BUILTIN_OBJS += builtin/reflog.o\ndiff --git a/builtin.h b/builtin.h\nindex ed89b4f495..7feb689d87 100644\n--- a/builtin.h\n+++ b/builtin.h\n@@ -203,7 +203,6 @@ extern int cmd_pull(int argc, const char **argv, const char *prefix);\n extern int cmd_push(int argc, const char **argv, const char *prefix);\n extern int cmd_read_tree(int argc, const char **argv, const char *prefix);\n extern int cmd_rebase__interactive(int argc, const char **argv, const char *prefix);\n-extern int cmd_rebase__helper(int argc, const char **argv, const char *prefix);\n extern int cmd_receive_pack(int argc, const char **argv, const char *prefix);\n extern int cmd_reflog(int argc, const char **argv, const char *prefix);\n extern int cmd_remote(int argc, const char **argv, const char *prefix);\ndiff --git a/builtin/rebase--helper.c b/builtin/rebase--helper.c\ndeleted file mode 100644\nindex ac21e8e06e..0000000000\n--- a/builtin/rebase--helper.c\n+++ /dev/null\n@@ -1,226 +0,0 @@\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 \"alias.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 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;\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-\n-\tif (revisions)\n-\t\t*revisions = xstrfmt(\"%s...%s\", base_rev, *head_hash);\n-\tif (shortrevisions) {\n-\t\tconst char *shorthead;\n-\n-\t\tshorthead = find_unique_abbrev(&orig_head, DEFAULT_ABBREV);\n-\n-\t\tif (upstream) {\n-\t\t\tconst char *shortrev;\n-\t\t\tstruct object_id rev_oid;\n-\n-\t\t\tget_oid(base_rev, &rev_oid);\n-\t\t\tshortrev = find_unique_abbrev(&rev_oid, DEFAULT_ABBREV);\n-\n-\t\t\t*shortrevisions = xstrfmt(\"%s..%s\", shortrev, shorthead);\n-\t\t} else\n-\t\t\t*shortrevisions = xstrdup(shorthead);\n-\t}\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 const char * const builtin_rebase_helper_usage[] = {\n-\tN_(\"git rebase--helper [<options>]\"),\n-\tNULL\n-};\n-\n-int cmd_rebase__helper(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;\n-\tconst char *head_hash = NULL, *onto = NULL, *restrict_revision = NULL,\n-\t\t*squash_onto = NULL, *upstream = NULL, *head_name = NULL;\n-\tchar *raw_strategies = NULL;\n-\tenum {\n-\t\tCONTINUE = 1, ABORT, MAKE_SCRIPT, SHORTEN_OIDS, EXPAND_OIDS,\n-\t\tCHECK_TODO_LIST, REARRANGE_SQUASH, ADD_EXEC, EDIT_TODO, PREPARE_BRANCH,\n-\t\tCOMPLETE_ACTION, INIT_BASIC_STATE\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\tN_(\"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 thas 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\tCONTINUE),\n-\t\tOPT_CMDMODE(0, \"abort\", &command, N_(\"abort rebase\"),\n-\t\t\t\tABORT),\n-\t\tOPT_CMDMODE(0, \"make-script\", &command,\n-\t\t\tN_(\"make rebase script\"), MAKE_SCRIPT),\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_CMDMODE(0, \"edit-todo\", &command,\n-\t\t\t    N_(\"edit the todo list during an interactive rebase\"),\n-\t\t\t    EDIT_TODO),\n-\t\tOPT_CMDMODE(0, \"prepare-branch\", &command,\n-\t\t\t    N_(\"prepare the branch to be rebased\"), PREPARE_BRANCH),\n-\t\tOPT_CMDMODE(0, \"complete-action\", &command,\n-\t\t\t    N_(\"complete the action\"), COMPLETE_ACTION),\n-\t\tOPT_CMDMODE(0, \"init-basic-state\", &command,\n-\t\t\t    N_(\"initialise the rebase state\"), INIT_BASIC_STATE),\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\tOPT_STRING('S', \"gpg-sign\", &opts.gpg_sign, N_(\"gpg-sign\"),\n-\t\t\t   N_(\"GPG-sign commits\")),\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_RERERE_AUTOUPDATE(&opts.allow_rerere_auto),\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-\targc = parse_options(argc, argv, NULL, options,\n-\t\t\tbuiltin_rebase_helper_usage, PARSE_OPT_KEEP_ARGV0);\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 (command == CONTINUE && argc == 1)\n-\t\treturn !!sequencer_continue(&opts);\n-\tif (command == ABORT && argc == 1)\n-\t\treturn !!sequencer_remove_state(&opts);\n-\tif (command == MAKE_SCRIPT && argc == 1) {\n-\t\tchar *revisions = NULL;\n-\t\tstruct argv_array make_script_args = ARGV_ARRAY_INIT;\n-\n-\t\tif (!upstream && squash_onto)\n-\t\t\twrite_file(path_squash_onto(), \"%s\\n\", squash_onto);\n-\n-\t\tret = get_revision_ranges(upstream, onto, &head_hash, &revisions, NULL);\n-\t\tif (ret)\n-\t\t\treturn ret;\n-\n-\t\targv_array_pushl(&make_script_args, \"\", revisions, NULL);\n-\t\tif (restrict_revision)\n-\t\t\targv_array_push(&make_script_args, restrict_revision);\n-\n-\t\tret = sequencer_make_script(stdout,\n-\t\t\t\t\t    make_script_args.argc, make_script_args.argv,\n-\t\t\t\t\t    flags);\n-\n-\t\tfree(revisions);\n-\t\targv_array_clear(&make_script_args);\n-\n-\t\treturn !!ret;\n-\t}\n-\tif ((command == SHORTEN_OIDS || command == EXPAND_OIDS) && argc == 1)\n-\t\treturn !!transform_todos(flags);\n-\tif (command == CHECK_TODO_LIST && argc == 1)\n-\t\treturn !!check_todo_list();\n-\tif (command == REARRANGE_SQUASH && argc == 1)\n-\t\treturn !!rearrange_squash();\n-\tif (command == ADD_EXEC && argc == 2)\n-\t\treturn !!sequencer_add_exec_commands(argv[1]);\n-\tif (command == EDIT_TODO && argc == 1)\n-\t\treturn !!edit_todo_list(flags);\n-\tif (command == PREPARE_BRANCH && argc == 2)\n-\t\treturn !!prepare_branch_to_be_rebased(&opts, argv[1]);\n-\tif (command == COMPLETE_ACTION && argc == 3) {\n-\t\tchar *shortrevisions = NULL;\n-\n-\t\tret = get_revision_ranges(upstream, onto, &head_hash, NULL, &shortrevisions);\n-\t\tif (ret)\n-\t\t\treturn ret;\n-\n-\t\tret = complete_action(&opts, flags, shortrevisions, argv[1], onto,\n-\t\t\t\t      head_hash, argv[2], autosquash);\n-\n-\t\tfree(shortrevisions);\n-\t\treturn !!ret;\n-\t}\n-\tif (command == INIT_BASIC_STATE) {\n-\t\tif (raw_strategies)\n-\t\t\tparse_strategy_opts(&opts, raw_strategies);\n-\n-\t\tret = get_revision_ranges(upstream, onto, &head_hash, NULL, NULL);\n-\t\tif (ret)\n-\t\t\treturn ret;\n-\n-\t\treturn !!init_basic_state(&opts, head_name, onto, head_hash);\n-\t}\n-\n-\tusage_with_options(builtin_rebase_helper_usage, options);\n-}\ndiff --git a/builtin/rebase--interactive.c b/builtin/rebase--interactive.c\nindex 53b4f7483d..1e1756f1e8 100644\n--- a/builtin/rebase--interactive.c\n+++ b/builtin/rebase--interactive.c\n@@ -140,7 +140,8 @@ int cmd_rebase__interactive(int argc, const char **argv, const char *prefix)\n \t\t*switch_to = NULL, *cmd = NULL;\n \tchar *raw_strategies = NULL;\n \tenum {\n-\t\tNONE = 0, CONTINUE, SKIP, EDIT_TODO, SHOW_CURRENT_PATCH\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@@ -161,6 +162,16 @@ int cmd_rebase__interactive(int argc, const char **argv, const char *prefix)\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@@ -199,6 +210,7 @@ int cmd_rebase__interactive(int argc, const char **argv, const char *prefix)\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@@ -231,6 +243,19 @@ 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+\t\tret = transform_todos(flags);\n+\t\tbreak;\n+\tcase CHECK_TODO_LIST:\n+\t\tret = check_todo_list();\n+\t\tbreak;\n+\tcase REARRANGE_SQUASH:\n+\t\tret = rearrange_squash();\n+\t\tbreak;\n+\tcase ADD_EXEC:\n+\t\tret = sequencer_add_exec_commands(cmd);\n+\t\tbreak;\n \tdefault:\n \t\tBUG(\"invalid command '%d'\", command);\n \t}\ndiff --git a/git-rebase--preserve-merges.sh b/git-rebase--preserve-merges.sh\nindex c214c5e4d6..afbb65765d 100644\n--- a/git-rebase--preserve-merges.sh\n+++ b/git-rebase--preserve-merges.sh\n@@ -711,11 +711,11 @@ do_rest () {\n }\n \n expand_todo_ids() {\n-\tgit rebase--helper --expand-ids\n+\tgit rebase--interactive --expand-ids\n }\n \n collapse_todo_ids() {\n-\tgit rebase--helper --shorten-ids\n+\tgit rebase--interactive --shorten-ids\n }\n \n # Switch to the branch in $into and notify it in the reflog\n@@ -876,8 +876,8 @@ init_revisions_and_shortrevisions () {\n \n complete_action() {\n \ttest -s \"$todo\" || echo noop >> \"$todo\"\n-\ttest -z \"$autosquash\" || git rebase--helper --rearrange-squash || exit\n-\ttest -n \"$cmd\" && git rebase--helper --add-exec-commands \"$cmd\"\n+\ttest -z \"$autosquash\" || git rebase--interactive --rearrange-squash || exit\n+\ttest -n \"$cmd\" && git rebase--interactive --add-exec-commands --cmd \"$cmd\"\n \n \ttodocount=$(git stripspace --strip-comments <\"$todo\" | wc -l)\n \ttodocount=${todocount##* }\n@@ -912,7 +912,7 @@ However, if you remove everything, the rebase will be aborted.\n \thas_action \"$todo\" ||\n \t\treturn 2\n \n-\tgit rebase--helper --check-todo-list || {\n+\tgit rebase--interactive --check-todo-list || {\n \t\tret=$?\n \t\tcheckout_onto\n \t\texit $ret\ndiff --git a/git.c b/git.c\nindex 19d0b6e3b8..81aabd1423 100644\n--- a/git.c\n+++ b/git.c\n@@ -519,7 +519,6 @@ static struct cmd_struct commands[] = {\n \t{ \"push\", cmd_push, RUN_SETUP },\n \t{ \"read-tree\", cmd_read_tree, RUN_SETUP | SUPPORT_SUPER_PREFIX},\n \t{ \"rebase--interactive\", cmd_rebase__interactive, RUN_SETUP | NEED_WORK_TREE },\n-\t{ \"rebase--helper\", cmd_rebase__helper, RUN_SETUP | NEED_WORK_TREE },\n \t{ \"receive-pack\", cmd_receive_pack },\n \t{ \"reflog\", cmd_reflog, RUN_SETUP },\n \t{ \"remote\", cmd_remote, RUN_SETUP },\n-- \n2.18.0\n\n"},{"id":"354107","messageId":"xmqqftzzb3x5.fsf@gitster-ct.c.googlers.com","threadId":"48814","inReplyTo":"20180731180003.5421-1-alban.gruin@gmail.com","subject":"Re: [GSoC][PATCH v5 00/20] rebase -i: rewrite in C","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2018-07-31T19:28:38Z","receivedAt":"2018-07-31T19:28:43Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Alban Gruin <alban.gruin@gmail.com> writes:\n\n> This patch series rewrite the interactive rebase from shell to C.\n\nThanks.\n\n> It is based on ffc6fa0e39 (\"Fourth batch for 2.19 cycle\", 2018-07-24).\n> The v4 was based on b7bd9486 (\"Third batch for 2.19 cycle\", 2018-07-18).\n> I wanted to make sure my series works well with 'bb/pedantic',\n> 'jk/empty-pick-fix', and 'as/sequencer-customizable-comment-char', as\n> they modified sequencer.c.\n\nIt is a good practice to keey an eye on other topics in flight to\nmake sure you play well with others.\n\nWhat you can do better in a case like this is to apply the patches\non the same base as v4 and then trial merge the result into the\nnewer base of your choice (e.g. ffc6fa0e39), and also apply the same\npatches on top of the same newer base.  If\n\n (1) the application to the old base goes cleanly,\n (2) the trial merge goes cleanly, and \n (3) the result of the trial merge exactly matches the tree as applying\n     the patches on the newer base\n\nthen it is preferrable not to rebase but keep the old base as the\nprevious round to avoid needless churn.  For a new development like\nthis (as opposed to \"fix for long standing bugs\"), keeping an old\nand tested base does not matter too much, but it is a good\ndiscipline to get into to hold your base steady.\n\nThe patches looked all good and applied cleanly.  Will queue and\nwait for a few days to see if anybody spots something glaringly\nwrong (I expect none) and then merge it to 'next'.\n\nThanks.\n"},{"id":"354385","messageId":"20180803132610.GA28939@sigill.intra.peff.net","threadId":"48814","inReplyTo":"20180730182516.32644-1-szeder.dev@gmail.com","subject":"Re: [GSoC][PATCH v4 15/20] rebase -i: rewrite write_basic_state() in C","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2018-08-03T13:26:10Z","receivedAt":"2018-08-03T13:26:14Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Mon, Jul 30, 2018 at 08:25:16PM +0200, SZEDER Gábor wrote:\n\n> > diff --git a/sequencer.c b/sequencer.c\n> > index 1c035ceec7..d257903db0 100644\n> > --- a/sequencer.c\n> > +++ b/sequencer.c\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> > +{\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> > +\tif (orig_head)\n> > +\t\twrite_file(rebase_path_orig_head(), \"%s\\n\", orig_head);\n> > +\n> > +\tif (quiet)\n> > +\t\twrite_file(rebase_path_quiet(), \"%s\\n\", quiet);\n> > +\telse\n> > +\t\twrite_file(rebase_path_quiet(), \"\");\n> \n> This is not a faithful conversion of the original.  git-rebase.sh writes\n> this 'quiet' file with:\n> \n>   echo \"$GIT_QUIET\" > \"$state_dir\"/quiet\n> \n> which means that a single newline character was written even when\n> $GIT_QUIET was unset/empty.\n\nwrite_file() will call strbuf_complete_line(), so even passing \"\" will\nresult in a file with a newline in it (I didn't dig, but this comes from\ne7ffa38c in 2015, so it may well have been a response to the breakage\nyou were thinking of).\n\nSo actually all of the \"%s\\n\" here can be just \"%s\".\n\nBut there _is_ a reason not to use \"\", which is that it triggers\n-Wformat-zero-length (which is part of -Wall unless you explicitly turn\nit off, which our DEVELOPER=1 setup does). For a long time you _had_ to\ndo that, but these days we're actually clean with respect to that\nwarning.\n\nSo using \"\\n\" here is better, and likewise here:\n\n> > +\tif (opts->verbose)\n> > +\t\twrite_file(rebase_path_verbose(), \"\");\n\nUnless we really do want a zero-length file, in which case:\n\n  write_file_buf(path, \"\", 0);\n\nis the right option. That matches the shell version, but I'd be\nsurprised if it mattered, since it's clearly meant to be \"if this file\nexists, we're verbose\".\n\n-Peff\n"},{"id":"354735","messageId":"d83efc2e-3538-9547-244f-ca7653498c22@talktalk.net","threadId":"48814","inReplyTo":"20180731180003.5421-3-alban.gruin@gmail.com","subject":"Re: [GSoC][PATCH v5 02/20] rebase -i: rewrite append_todo_help() in C","fromName":"Phillip Wood","fromEmail":"phillip.wood@talktalk.net","sentAt":"2018-08-07T13:57:57Z","receivedAt":"2018-08-07T13:58:02Z","isPatch":true,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"Hi Alban\n\nOn 31/07/18 18:59, Alban Gruin wrote:\n> This rewrites append_todo_help() from shell to C. It also incorporates\n> some parts of initiate_action() and complete_action() that also write\n> help texts to the todo file.\n> \n> This also introduces the source file rebase-interactive.c. This file\n> will contain functions necessary for interactive rebase that are too\n> specific for the sequencer, and is part of libgit.a.\n> \n> Two flags are added to rebase--helper.c: one to call\n> append_todo_help() (`--append-todo-help`), and another one to tell\n> append_todo_help() to write the help text suited for the edit-todo\n> mode (`--write-edit-todo`).\n> \n> Finally, append_todo_help() is removed from git-rebase--interactive.sh\n> to use `rebase--helper --append-todo-help` instead.\n> \n> Signed-off-by: Alban Gruin <alban.gruin@gmail.com>\n> ---\n> No changes since v4.\n> \n>  Makefile                   |  1 +\n>  builtin/rebase--helper.c   | 11 ++++--\n>  git-rebase--interactive.sh | 52 ++---------------------------\n>  rebase-interactive.c       | 68 ++++++++++++++++++++++++++++++++++++++\n>  rebase-interactive.h       |  6 ++++\n>  5 files changed, 86 insertions(+), 52 deletions(-)\n>  create mode 100644 rebase-interactive.c\n>  create mode 100644 rebase-interactive.h\n> \n> diff --git a/Makefile b/Makefile\n> index 08e5c54549..909a687857 100644\n> --- a/Makefile\n> +++ b/Makefile\n> @@ -922,6 +922,7 @@ LIB_OBJS += protocol.o\n>  LIB_OBJS += quote.o\n>  LIB_OBJS += reachable.o\n>  LIB_OBJS += read-cache.o\n> +LIB_OBJS += rebase-interactive.o\n>  LIB_OBJS += reflog-walk.o\n>  LIB_OBJS += refs.o\n>  LIB_OBJS += refs/files-backend.o\n> diff --git a/builtin/rebase--helper.c b/builtin/rebase--helper.c\n> index f7c2a5fdc8..05e73e71d4 100644\n> --- a/builtin/rebase--helper.c\n> +++ b/builtin/rebase--helper.c\n> @@ -3,6 +3,7 @@\n>  #include \"config.h\"\n>  #include \"parse-options.h\"\n>  #include \"sequencer.h\"\n> +#include \"rebase-interactive.h\"\n>  \n>  static const char * const builtin_rebase_helper_usage[] = {\n>  \tN_(\"git rebase--helper [<options>]\"),\n> @@ -12,12 +13,12 @@ static const char * const builtin_rebase_helper_usage[] = {\n>  int cmd_rebase__helper(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;\n> +\tunsigned flags = 0, keep_empty = 0, rebase_merges = 0, write_edit_todo = 0;\n>  \tint abbreviate_commands = 0, rebase_cousins = -1;\n>  \tenum {\n>  \t\tCONTINUE = 1, ABORT, MAKE_SCRIPT, SHORTEN_OIDS, EXPAND_OIDS,\n>  \t\tCHECK_TODO_LIST, SKIP_UNNECESSARY_PICKS, REARRANGE_SQUASH,\n> -\t\tADD_EXEC\n> +\t\tADD_EXEC, APPEND_TODO_HELP\n>  \t} command = 0;\n>  \tstruct option options[] = {\n>  \t\tOPT_BOOL(0, \"ff\", &opts.allow_ff, N_(\"allow fast-forward\")),\n> @@ -27,6 +28,8 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\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, \"write-edit-todo\", &write_edit_todo,\n> +\t\t\t N_(\"append the edit-todo message to the todo-list\")),\n>  \t\tOPT_CMDMODE(0, \"continue\", &command, N_(\"continue rebase\"),\n>  \t\t\t\tCONTINUE),\n>  \t\tOPT_CMDMODE(0, \"abort\", &command, N_(\"abort rebase\"),\n> @@ -45,6 +48,8 @@ int cmd_rebase__helper(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_CMDMODE(0, \"append-todo-help\", &command,\n> +\t\t\t    N_(\"insert the help in the todo list\"), APPEND_TODO_HELP),\n>  \t\tOPT_END()\n>  \t};\n>  \n> @@ -84,5 +89,7 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\n>  \t\treturn !!rearrange_squash();\n>  \tif (command == ADD_EXEC && argc == 2)\n>  \t\treturn !!sequencer_add_exec_commands(argv[1]);\n> +\tif (command == APPEND_TODO_HELP && argc == 1)\n> +\t\treturn !!append_todo_help(write_edit_todo, keep_empty);\n>  \tusage_with_options(builtin_rebase_helper_usage, options);\n>  }\n> diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\n> index 299ded2137..94c23a7af2 100644\n> --- a/git-rebase--interactive.sh\n> +++ b/git-rebase--interactive.sh\n> @@ -39,38 +39,6 @@ comment_for_reflog () {\n>  \tesac\n>  }\n>  \n> -append_todo_help () {\n> -\tgettext \"\n> -Commands:\n> -p, pick <commit> = use commit\n> -r, reword <commit> = use commit, but edit the commit message\n> -e, edit <commit> = use commit, but stop for amending\n> -s, squash <commit> = use commit, but meld into previous commit\n> -f, fixup <commit> = like \\\"squash\\\", but discard this commit's log message\n> -x, exec <command> = run command (the rest of the line) using shell\n> -d, drop <commit> = remove commit\n> -l, label <label> = label current HEAD with a name\n> -t, reset <label> = reset HEAD to a label\n> -m, merge [-C <commit> | -c <commit>] <label> [# <oneline>]\n> -.       create a merge commit using the original merge commit's\n> -.       message (or the oneline, if no original merge commit was\n> -.       specified). Use -c <commit> to reword the commit message.\n> -\n> -These lines can be re-ordered; they are executed from top to bottom.\n> -\" | git stripspace --comment-lines >>\"$todo\"\n> -\n> -\tif test $(get_missing_commit_check_level) = error\n> -\tthen\n> -\t\tgettext \"\n> -Do not remove any line. Use 'drop' explicitly to remove a commit.\n> -\" | git stripspace --comment-lines >>\"$todo\"\n> -\telse\n> -\t\tgettext \"\n> -If you remove a line here THAT COMMIT WILL BE LOST.\n> -\" | git stripspace --comment-lines >>\"$todo\"\n> -\tfi\n> -}\n> -\n>  die_abort () {\n>  \tapply_autostash\n>  \trm -rf \"$state_dir\"\n> @@ -143,13 +111,7 @@ initiate_action () {\n>  \t\tgit stripspace --strip-comments <\"$todo\" >\"$todo\".new\n>  \t\tmv -f \"$todo\".new \"$todo\"\n>  \t\tcollapse_todo_ids\n> -\t\tappend_todo_help\n> -\t\tgettext \"\n> -You are editing the todo file of an ongoing interactive rebase.\n> -To continue rebase after editing, run:\n> -    git rebase --continue\n> -\n> -\" | git stripspace --comment-lines >>\"$todo\"\n> +\t\tgit rebase--helper --append-todo-help --write-edit-todo\n>  \n>  \t\tgit_sequence_editor \"$todo\" ||\n>  \t\t\tdie \"$(gettext \"Could not execute editor\")\"\n> @@ -220,17 +182,7 @@ $comment_char $(eval_ngettext \\\n>  \t\"Rebase \\$shortrevisions onto \\$shortonto (\\$todocount commands)\" \\\n>  \t\"$todocount\")\n>  EOF\n> -\tappend_todo_help\n> -\tgettext \"\n> -\tHowever, if you remove everything, the rebase will be aborted.\n> -\n> -\t\" | git stripspace --comment-lines >>\"$todo\"\n> -\n> -\tif test -z \"$keep_empty\"\n> -\tthen\n> -\t\tprintf '%s\\n' \"$comment_char $(gettext \"Note that empty commits are commented out\")\" >>\"$todo\"\n> -\tfi\n> -\n> +\tgit rebase--helper --append-todo-help ${keep_empty:+--keep-empty}\n>  \n>  \thas_action \"$todo\" ||\n>  \t\treturn 2\n> diff --git a/rebase-interactive.c b/rebase-interactive.c\n> new file mode 100644\n> index 0000000000..d7996bc8d9\n> --- /dev/null\n> +++ b/rebase-interactive.c\n> @@ -0,0 +1,68 @@\n> +#include \"cache.h\"\n> +#include \"commit.h\"\n> +#include \"rebase-interactive.h\"\n> +#include \"sequencer.h\"\n> +#include \"strbuf.h\"\n> +\n> +int append_todo_help(unsigned edit_todo, unsigned keep_empty)\n> +{\n> +\tstruct strbuf buf = STRBUF_INIT;\n> +\tFILE *todo;\n> +\tint ret;\n> +\tconst char *msg = _(\"\\nCommands:\\n\"\n> +\"p, pick <commit> = use commit\\n\"\n> +\"r, reword <commit> = use commit, but edit the commit message\\n\"\n> +\"e, edit <commit> = use commit, but stop for amending\\n\"\n> +\"s, squash <commit> = use commit, but meld into previous commit\\n\"\n> +\"f, fixup <commit> = like \\\"squash\\\", but discard this commit's log message\\n\"\n> +\"x, exec <command> = run command (the rest of the line) using shell\\n\"\n> +\"d, drop <commit> = remove commit\\n\"\n> +\"l, label <label> = label current HEAD with a name\\n\"\n> +\"t, reset <label> = reset HEAD to a label\\n\"\n> +\"m, merge [-C <commit> | -c <commit>] <label> [# <oneline>]\\n\"\n> +\".       create a merge commit using the original merge commit's\\n\"\n> +\".       message (or the oneline, if no original merge commit was\\n\"\n> +\".       specified). Use -c <commit> to reword the commit message.\\n\"\n> +\"\\n\"\n> +\"These lines can be re-ordered; they are executed from top to bottom.\\n\");\n> +\n> +\ttodo = fopen_or_warn(rebase_path_todo(), \"a\");\n> +\tif (!todo)\n> +\t\treturn 1;\n> +\n> +\tstrbuf_add_commented_lines(&buf, msg, strlen(msg));\n> +\n> +\tif (get_missing_commit_check_level() == MISSING_COMMIT_CHECK_ERROR)\n> +\t\tmsg = _(\"\\nDo not remove any line. Use 'drop' \"\n> +\t\t\t \"explicitly to remove a commit.\\n\");\n> +\telse\n> +\t\tmsg = _(\"\\nIf you remove a line here \"\n> +\t\t\t \"THAT COMMIT WILL BE LOST.\\n\");\n> +\n> +\tstrbuf_add_commented_lines(&buf, msg, strlen(msg));\n> +\n> +\tif (edit_todo)\n> +\t\tmsg = _(\"\\nYou are editing the todo file \"\n> +\t\t\t\"of an ongoing interactive rebase.\\n\"\n> +\t\t\t\"To continue rebase after editing, run:\\n\"\n> +\t\t\t\"    git rebase --continue\\n\\n\");\n> +\telse\n> +\t\tmsg = _(\"\\nHowever, if you remove everything, \"\n> +\t\t\t\"the rebase will be aborted.\\n\\n\");\n> +\n> +\tstrbuf_add_commented_lines(&buf, msg, strlen(msg));\n> +\n> +\tif (!keep_empty) {\n> +\t\tmsg = _(\"Note that empty commits are commented out\");\n> +\t\tstrbuf_add_commented_lines(&buf, msg, strlen(msg));\n> +\t}\n> +\n> +\tret = fputs(buf.buf, todo);\n\nIt is not worth changing the patch just for this but strbuf_write()\nmight be clearer (you use it in a later patch)\n\n> +\tif (ret < 0)\n> +\t\terror_errno(_(\"could not append help text to '%s'\"), rebase_path_todo());\n> +\n> +\tfclose(todo);\n\nYou should definitely check the return value and return an error if\nappropriate as fputs() might not actually write any data until you try\nand close the file.\n\nBest Wishes\n\nPhillip\n\n> +\tstrbuf_release(&buf);\n> +\n> +\treturn ret;\n> +}\n> diff --git a/rebase-interactive.h b/rebase-interactive.h\n> new file mode 100644\n> index 0000000000..47372624e0\n> --- /dev/null\n> +++ b/rebase-interactive.h\n> @@ -0,0 +1,6 @@\n> +#ifndef REBASE_INTERACTIVE_H\n> +#define REBASE_INTERACTIVE_H\n> +\n> +int append_todo_help(unsigned edit_todo, unsigned keep_empty);\n> +\n> +#endif\n> \n\n"},{"id":"354736","messageId":"325fd5d2-2a93-2270-7d1e-394c265f42d4@talktalk.net","threadId":"48814","inReplyTo":"20180731180003.5421-5-alban.gruin@gmail.com","subject":"Re: [GSoC][PATCH v5 04/20] rebase -i: rewrite the edit-todo functionality in C","fromName":"Phillip Wood","fromEmail":"phillip.wood@talktalk.net","sentAt":"2018-08-07T14:00:59Z","receivedAt":"2018-08-07T14:01:03Z","isPatch":true,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"On 31/07/18 18:59, Alban Gruin wrote:\n> This rewrites the edit-todo functionality from shell to C.\n> \n> To achieve that, a new command mode, `edit-todo`, is added, and the\n> `write-edit-todo` flag is removed, as the shell script does not need to\n> write the edit todo help message to the todo list anymore.\n> \n> The shell version is then stripped in favour of a call to the helper.\n> \n> Signed-off-by: Alban Gruin <alban.gruin@gmail.com>\n> ---\n> No changes since v4.\n> \n>  builtin/rebase--helper.c   | 13 ++++++++-----\n>  git-rebase--interactive.sh | 11 +----------\n>  rebase-interactive.c       | 31 +++++++++++++++++++++++++++++++\n>  rebase-interactive.h       |  1 +\n>  4 files changed, 41 insertions(+), 15 deletions(-)\n> \n> diff --git a/builtin/rebase--helper.c b/builtin/rebase--helper.c\n> index 05e73e71d4..731a64971d 100644\n> --- a/builtin/rebase--helper.c\n> +++ b/builtin/rebase--helper.c\n> @@ -13,12 +13,12 @@ static const char * const builtin_rebase_helper_usage[] = {\n>  int cmd_rebase__helper(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, write_edit_todo = 0;\n> +\tunsigned flags = 0, keep_empty = 0, rebase_merges = 0;\n>  \tint abbreviate_commands = 0, rebase_cousins = -1;\n>  \tenum {\n>  \t\tCONTINUE = 1, ABORT, MAKE_SCRIPT, SHORTEN_OIDS, EXPAND_OIDS,\n>  \t\tCHECK_TODO_LIST, SKIP_UNNECESSARY_PICKS, REARRANGE_SQUASH,\n> -\t\tADD_EXEC, APPEND_TODO_HELP\n> +\t\tADD_EXEC, APPEND_TODO_HELP, EDIT_TODO\n>  \t} command = 0;\n>  \tstruct option options[] = {\n>  \t\tOPT_BOOL(0, \"ff\", &opts.allow_ff, N_(\"allow fast-forward\")),\n> @@ -28,8 +28,6 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\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, \"write-edit-todo\", &write_edit_todo,\n> -\t\t\t N_(\"append the edit-todo message to the todo-list\")),\n>  \t\tOPT_CMDMODE(0, \"continue\", &command, N_(\"continue rebase\"),\n>  \t\t\t\tCONTINUE),\n>  \t\tOPT_CMDMODE(0, \"abort\", &command, N_(\"abort rebase\"),\n> @@ -50,6 +48,9 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\n>  \t\t\tN_(\"insert exec commands in todo list\"), ADD_EXEC),\n>  \t\tOPT_CMDMODE(0, \"append-todo-help\", &command,\n>  \t\t\t    N_(\"insert the help in the todo list\"), APPEND_TODO_HELP),\n> +\t\tOPT_CMDMODE(0, \"edit-todo\", &command,\n> +\t\t\t    N_(\"edit the todo list during an interactive rebase\"),\n> +\t\t\t    EDIT_TODO),\n>  \t\tOPT_END()\n>  \t};\n>  \n> @@ -90,6 +91,8 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\n>  \tif (command == ADD_EXEC && argc == 2)\n>  \t\treturn !!sequencer_add_exec_commands(argv[1]);\n>  \tif (command == APPEND_TODO_HELP && argc == 1)\n> -\t\treturn !!append_todo_help(write_edit_todo, keep_empty);\n> +\t\treturn !!append_todo_help(0, keep_empty);\n> +\tif (command == EDIT_TODO && argc == 1)\n> +\t\treturn !!edit_todo_list(flags);\n>  \tusage_with_options(builtin_rebase_helper_usage, options);\n>  }\n> diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\n> index 94c23a7af2..2defe607f4 100644\n> --- a/git-rebase--interactive.sh\n> +++ b/git-rebase--interactive.sh\n> @@ -108,16 +108,7 @@ initiate_action () {\n>  \t\t     --continue\n>  \t\t;;\n>  \tedit-todo)\n> -\t\tgit stripspace --strip-comments <\"$todo\" >\"$todo\".new\n> -\t\tmv -f \"$todo\".new \"$todo\"\n> -\t\tcollapse_todo_ids\n> -\t\tgit rebase--helper --append-todo-help --write-edit-todo\n> -\n> -\t\tgit_sequence_editor \"$todo\" ||\n> -\t\t\tdie \"$(gettext \"Could not execute editor\")\"\n> -\t\texpand_todo_ids\n> -\n> -\t\texit\n> +\t\texec git rebase--helper --edit-todo\n>  \t\t;;\n>  \tshow-current-patch)\n>  \t\texec git show REBASE_HEAD --\n> diff --git a/rebase-interactive.c b/rebase-interactive.c\n> index d7996bc8d9..403ecbf3c9 100644\n> --- a/rebase-interactive.c\n> +++ b/rebase-interactive.c\n> @@ -66,3 +66,34 @@ int append_todo_help(unsigned edit_todo, unsigned keep_empty)\n>  \n>  \treturn ret;\n>  }\n> +\n> +int edit_todo_list(unsigned flags)\n> +{\n> +\tstruct strbuf buf = STRBUF_INIT;\n> +\tconst char *todo_file = rebase_path_todo();\n> +\tFILE *todo;\n> +\n> +\tif (strbuf_read_file(&buf, todo_file, 0) < 0)\n> +\t\treturn error_errno(_(\"could not read '%s'.\"), todo_file);\n> +\n> +\tstrbuf_stripspace(&buf, 1);\n> +\ttodo = fopen_or_warn(todo_file, \"w\");\n\nThis truncates the existing file, if there are any errors writing the\nnew one then the user has lost the old one. write_message() in\nsequencer.c avoids this problem by writing a new file and then renaming\nit if the write is successful, maybe it is worth exporting it so it can\nbe used elsewhere.\n\n> +\tif (!todo) {\n> +\t\tstrbuf_release(&buf);\n> +\t\treturn 1;\n> +\t}\n> +\n> +\tstrbuf_write(&buf, todo);\n> +\tfclose(todo);\n\nThere needs to be some error checking after the write and the close\n(using write_message() would mean you only have to check for errors in\none place)\n\nBest Wishes\n\nPhillip\n\n> +\tstrbuf_release(&buf);\n> +\n> +\ttransform_todos(flags | TODO_LIST_SHORTEN_IDS);\n> +\tappend_todo_help(1, 0);\n> +\n> +\tif (launch_sequence_editor(todo_file, NULL, NULL))\n> +\t\treturn 1;\n> +\n> +\ttransform_todos(flags & ~(TODO_LIST_SHORTEN_IDS));\n> +\n> +\treturn 0;\n> +}\n> diff --git a/rebase-interactive.h b/rebase-interactive.h\n> index 47372624e0..155219e742 100644\n> --- a/rebase-interactive.h\n> +++ b/rebase-interactive.h\n> @@ -2,5 +2,6 @@\n>  #define REBASE_INTERACTIVE_H\n>  \n>  int append_todo_help(unsigned edit_todo, unsigned keep_empty);\n> +int edit_todo_list(unsigned flags);\n>  \n>  #endif\n> \n\n"},{"id":"354742","messageId":"CAP8UFD3KbDrvU3zj24F7FF9ui2X75Vih4CoYE=cCZEWMsKP9Fw@mail.gmail.com","threadId":"48814","inReplyTo":"d83efc2e-3538-9547-244f-ca7653498c22@talktalk.net","subject":"Re: [GSoC][PATCH v5 02/20] rebase -i: rewrite append_todo_help() in C","fromName":"Christian Couder","fromEmail":"christian.couder@gmail.com","sentAt":"2018-08-07T15:25:02Z","receivedAt":"2018-08-07T15:25:05Z","isPatch":true,"sender":{"key":"christian.couder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/208954?v=4"},"body":"Hi Phillip,\n\nOn Tue, Aug 7, 2018 at 3:57 PM, Phillip Wood <phillip.wood@talktalk.net> wrote:\n>\n> On 31/07/18 18:59, Alban Gruin wrote:\n>>\n>> +\n>> +     ret = fputs(buf.buf, todo);\n>\n> It is not worth changing the patch just for this but strbuf_write()\n> might be clearer (you use it in a later patch)\n>\n>> +     if (ret < 0)\n>> +             error_errno(_(\"could not append help text to '%s'\"), rebase_path_todo());\n>> +\n>> +     fclose(todo);\n>\n> You should definitely check the return value and return an error if\n> appropriate as fputs() might not actually write any data until you try\n> and close the file.\n\nI agree about checking the return value from fputs(), but it seems to\nme that we don't usually check the value of fclose().\n\nThanks,\nChristian.\n"},{"id":"354747","messageId":"6832700d-d7be-1df1-8b24-6e0290de63ed@talktalk.net","threadId":"48814","inReplyTo":"CAP8UFD3KbDrvU3zj24F7FF9ui2X75Vih4CoYE=cCZEWMsKP9Fw@mail.gmail.com","subject":"Re: [GSoC][PATCH v5 02/20] rebase -i: rewrite append_todo_help() in C","fromName":"Phillip Wood","fromEmail":"phillip.wood@talktalk.net","sentAt":"2018-08-07T16:15:48Z","receivedAt":"2018-08-07T16:15:58Z","isPatch":true,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"Hi Christian\nOn 07/08/18 16:25, Christian Couder wrote:\n> Hi Phillip,\n> \n> On Tue, Aug 7, 2018 at 3:57 PM, Phillip Wood <phillip.wood@talktalk.net> wrote:\n>>\n>> On 31/07/18 18:59, Alban Gruin wrote:\n>>>\n>>> +\n>>> +     ret = fputs(buf.buf, todo);\n>>\n>> It is not worth changing the patch just for this but strbuf_write()\n>> might be clearer (you use it in a later patch)\n>>\n>>> +     if (ret < 0)\n>>> +             error_errno(_(\"could not append help text to '%s'\"), rebase_path_todo());\n>>> +\n>>> +     fclose(todo);\n>>\n>> You should definitely check the return value and return an error if\n>> appropriate as fputs() might not actually write any data until you try\n>> and close the file.\n> \n> I agree about checking the return value from fputs(), but it seems to\n> me that we don't usually check the value of fclose().\n\nA quick grep shows you're right, there are only a handful of places \nwhere the return value of fclose() is checked (there aren't many checks \nfor the return value of close() either), I'm don't think that is safe \nthough given that write errors may only show up when the file gets \nflushed by closing it.\n\nBest Wishes\n\nPhillip\n\n> Thanks,\n> Christian.\n> \n\n"},{"id":"354748","messageId":"CAP8UFD2_oxn=auXb1tYCb5xED5YmKU3W=fCrpMsyxdZBfs2qcw@mail.gmail.com","threadId":"48814","inReplyTo":"6832700d-d7be-1df1-8b24-6e0290de63ed@talktalk.net","subject":"Re: [GSoC][PATCH v5 02/20] rebase -i: rewrite append_todo_help() in C","fromName":"Christian Couder","fromEmail":"christian.couder@gmail.com","sentAt":"2018-08-07T16:28:58Z","receivedAt":"2018-08-07T16:29:01Z","isPatch":true,"sender":{"key":"christian.couder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/208954?v=4"},"body":"On Tue, Aug 7, 2018 at 6:15 PM, Phillip Wood <phillip.wood@talktalk.net> wrote:\n> On 07/08/18 16:25, Christian Couder wrote:\n>>\n>> I agree about checking the return value from fputs(), but it seems to\n>> me that we don't usually check the value of fclose().\n>\n> A quick grep shows you're right, there are only a handful of places where\n> the return value of fclose() is checked (there aren't many checks for the\n> return value of close() either), I'm don't think that is safe though given\n> that write errors may only show up when the file gets flushed by closing it.\n\nI vaguely remember we tried to check those return values but it didn't\nwork well sometimes.\n"},{"id":"354757","messageId":"1424a96b-26e8-aaa8-8e3c-ed84d58c26af@talktalk.net","threadId":"48814","inReplyTo":"CAP8UFD2_oxn=auXb1tYCb5xED5YmKU3W=fCrpMsyxdZBfs2qcw@mail.gmail.com","subject":"Re: [GSoC][PATCH v5 02/20] rebase -i: rewrite append_todo_help() in C","fromName":"Phillip Wood","fromEmail":"phillip.wood@talktalk.net","sentAt":"2018-08-07T17:31:23Z","receivedAt":"2018-08-07T17:31:29Z","isPatch":true,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"Hi Christian\nOn 07/08/18 17:28, Christian Couder wrote:\n> On Tue, Aug 7, 2018 at 6:15 PM, Phillip Wood <phillip.wood@talktalk.net> wrote:\n>> On 07/08/18 16:25, Christian Couder wrote:\n>>>\n>>> I agree about checking the return value from fputs(), but it seems to\n>>> me that we don't usually check the value of fclose().\n>>\n>> A quick grep shows you're right, there are only a handful of places where\n>> the return value of fclose() is checked (there aren't many checks for the\n>> return value of close() either), I'm don't think that is safe though given\n>> that write errors may only show up when the file gets flushed by closing it.\n> \n> I vaguely remember we tried to check those return values but it didn't\n> work well sometimes.\n> \n\nI think there's no point in checking the return value after a successful\nread, or when writing and the file is being closed (and then possibly\nremoved) in some clean-up in an error path, but if the code cares about\nensuring the data is written then I think it should be checking the\nreturn value, close_tempfile_gently() does for example.\n\nIn the sequencer code there are some examples where it probably should\nbe checking the return value, and places such as rewrite_file() and\nwrite_message() (which uses the lockfile api) where the return code is\nchecked (there are a couple of recently added callers of write_message()\nin the code to recreate octopus merges that don't check its return value\nbut all the other callers do).\n\nBest Wishes\n\nPhillip\n"},{"id":"354822","messageId":"d8f0e5a2-f621-7847-5113-df4a6da11151@gmail.com","threadId":"48814","inReplyTo":"d83efc2e-3538-9547-244f-ca7653498c22@talktalk.net","subject":"Re: [GSoC][PATCH v5 02/20] rebase -i: rewrite append_todo_help() in C","fromName":"Alban Gruin","fromEmail":"alban.gruin@gmail.com","sentAt":"2018-08-08T15:16:59Z","receivedAt":"2018-08-08T15:17:18Z","isPatch":true,"sender":{"key":"alban.gruin@gmail.com","avatar":"https://avatars.githubusercontent.com/u/6310153?v=4"},"body":"Hi Phillip,\n\nLe 07/08/2018 à 15:57, Phillip Wood a écrit :\n>> +\tif (ret < 0)\n>> +\t\terror_errno(_(\"could not append help text to '%s'\"), rebase_path_todo());\n>> +\n>> +\tfclose(todo);\n> \n> You should definitely check the return value and return an error if\n> appropriate as fputs() might not actually write any data until you try\n> and close the file.\n> \n\nIs this worth a reroll, as this goes away in a later patch (refactored\nin 08/20, removed in 12/20)?\n\n> Best Wishes\n> \n> Phillip\n> \n>> +\tstrbuf_release(&buf);\n>> +\n>> +\treturn ret;\n>> +}\n>> diff --git a/rebase-interactive.h b/rebase-interactive.h\n>> new file mode 100644\n>> index 0000000000..47372624e0\n>> --- /dev/null\n>> +++ b/rebase-interactive.h\n>> @@ -0,0 +1,6 @@\n>> +#ifndef REBASE_INTERACTIVE_H\n>> +#define REBASE_INTERACTIVE_H\n>> +\n>> +int append_todo_help(unsigned edit_todo, unsigned keep_empty);\n>> +\n>> +#endif\n>>\n> \n\nCheers,\nAlban\n\n"},{"id":"354823","messageId":"6826d318-b0ab-4e8e-e2ba-5425e3bf6f5f@gmail.com","threadId":"48814","inReplyTo":"325fd5d2-2a93-2270-7d1e-394c265f42d4@talktalk.net","subject":"Re: [GSoC][PATCH v5 04/20] rebase -i: rewrite the edit-todo functionality in C","fromName":"Alban Gruin","fromEmail":"alban.gruin@gmail.com","sentAt":"2018-08-08T15:17:19Z","receivedAt":"2018-08-08T15:17:24Z","isPatch":true,"sender":{"key":"alban.gruin@gmail.com","avatar":"https://avatars.githubusercontent.com/u/6310153?v=4"},"body":"Hi Phillip,\n\nLe 07/08/2018 à 16:00, Phillip Wood a écrit :\n> On 31/07/18 18:59, Alban Gruin wrote:\n>> +\n>> +int edit_todo_list(unsigned flags)\n>> +{\n>> +\tstruct strbuf buf = STRBUF_INIT;\n>> +\tconst char *todo_file = rebase_path_todo();\n>> +\tFILE *todo;\n>> +\n>> +\tif (strbuf_read_file(&buf, todo_file, 0) < 0)\n>> +\t\treturn error_errno(_(\"could not read '%s'.\"), todo_file);\n>> +\n>> +\tstrbuf_stripspace(&buf, 1);\n>> +\ttodo = fopen_or_warn(todo_file, \"w\");\n> \n> This truncates the existing file, if there are any errors writing the\n> new one then the user has lost the old one. write_message() in\n> sequencer.c avoids this problem by writing a new file and then renaming\n> it if the write is successful, maybe it is worth exporting it so it can\n> be used elsewhere.\n> \n>> +\tif (!todo) {\n>> +\t\tstrbuf_release(&buf);\n>> +\t\treturn 1;\n>> +\t}\n>> +\n>> +\tstrbuf_write(&buf, todo);\n>> +\tfclose(todo);\n> \n> There needs to be some error checking after the write and the close\n> (using write_message() would mean you only have to check for errors in\n> one place)\n> \n\nRight.  Should I find a new nawe for write_message()?\n\nCheers,\nAlban\n\n"},{"id":"354854","messageId":"89a83826-53e6-aea1-2012-475a09f76ddc@talktalk.net","threadId":"48814","inReplyTo":"d8f0e5a2-f621-7847-5113-df4a6da11151@gmail.com","subject":"Re: [GSoC][PATCH v5 02/20] rebase -i: rewrite append_todo_help() in C","fromName":"Phillip Wood","fromEmail":"phillip.wood@talktalk.net","sentAt":"2018-08-08T16:00:59Z","receivedAt":"2018-08-08T16:01:11Z","isPatch":true,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"Hi Alban\n\nOn 08/08/18 16:16, Alban Gruin wrote:\n> Hi Phillip,\n> \n> Le 07/08/2018 à 15:57, Phillip Wood a écrit :\n>>> +\tif (ret < 0)\n>>> +\t\terror_errno(_(\"could not append help text to '%s'\"), rebase_path_todo());\n>>> +\n>>> +\tfclose(todo);\n>>\n>> You should definitely check the return value and return an error if\n>> appropriate as fputs() might not actually write any data until you try\n>> and close the file.\n>>\n> \n> Is this worth a reroll, as this goes away in a later patch (refactored\n> in 08/20, removed in 12/20)?\n>\n\nAh, I've only made it to patch 10 at the moment! If this is going to be \nremoved don't worry about it.\n\nBest Wishes\n\nPhillip\n\n>> Best Wishes\n>>\n>> Phillip\n>>\n>>> +\tstrbuf_release(&buf);\n>>> +\n>>> +\treturn ret;\n>>> +}\n>>> diff --git a/rebase-interactive.h b/rebase-interactive.h\n>>> new file mode 100644\n>>> index 0000000000..47372624e0\n>>> --- /dev/null\n>>> +++ b/rebase-interactive.h\n>>> @@ -0,0 +1,6 @@\n>>> +#ifndef REBASE_INTERACTIVE_H\n>>> +#define REBASE_INTERACTIVE_H\n>>> +\n>>> +int append_todo_help(unsigned edit_todo, unsigned keep_empty);\n>>> +\n>>> +#endif\n>>>\n>>\n> \n> Cheers,\n> Alban\n> \n\n"},{"id":"354857","messageId":"75549397-9080-3b5a-8655-cea04065b2eb@talktalk.net","threadId":"48814","inReplyTo":"6826d318-b0ab-4e8e-e2ba-5425e3bf6f5f@gmail.com","subject":"Re: [GSoC][PATCH v5 04/20] rebase -i: rewrite the edit-todo functionality in C","fromName":"Phillip Wood","fromEmail":"phillip.wood@talktalk.net","sentAt":"2018-08-08T16:04:04Z","receivedAt":"2018-08-08T16:04:16Z","isPatch":true,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"On 08/08/18 16:17, Alban Gruin wrote:\n> Hi Phillip,\n> \n> Le 07/08/2018 à 16:00, Phillip Wood a écrit :\n>> On 31/07/18 18:59, Alban Gruin wrote:\n>>> +\n>>> +int edit_todo_list(unsigned flags)\n>>> +{\n>>> +\tstruct strbuf buf = STRBUF_INIT;\n>>> +\tconst char *todo_file = rebase_path_todo();\n>>> +\tFILE *todo;\n>>> +\n>>> +\tif (strbuf_read_file(&buf, todo_file, 0) < 0)\n>>> +\t\treturn error_errno(_(\"could not read '%s'.\"), todo_file);\n>>> +\n>>> +\tstrbuf_stripspace(&buf, 1);\n>>> +\ttodo = fopen_or_warn(todo_file, \"w\");\n>>\n>> This truncates the existing file, if there are any errors writing the\n>> new one then the user has lost the old one. write_message() in\n>> sequencer.c avoids this problem by writing a new file and then renaming\n>> it if the write is successful, maybe it is worth exporting it so it can\n>> be used elsewhere.\n>>\n>>> +\tif (!todo) {\n>>> +\t\tstrbuf_release(&buf);\n>>> +\t\treturn 1;\n>>> +\t}\n>>> +\n>>> +\tstrbuf_write(&buf, todo);\n>>> +\tfclose(todo);\n>>\n>> There needs to be some error checking after the write and the close\n>> (using write_message() would mean you only have to check for errors in\n>> one place)\n>>\n> \n> Right.  Should I find a new nawe for write_message()?\n\nThat might be a good idea, I'm not sure what it should be though, maybe \nwrite_file()?, perhaps someone else might have a better suggestion.\n\nBest Wishes\n\nPhillip\n\n> \n> Cheers,\n> Alban\n> \n\n"},{"id":"354988","messageId":"bc07317b-ba44-7a3c-7cb4-504b7dbc7c34@gmail.com","threadId":"48814","inReplyTo":"75549397-9080-3b5a-8655-cea04065b2eb@talktalk.net","subject":"Re: [GSoC][PATCH v5 04/20] rebase -i: rewrite the edit-todo functionality in C","fromName":"Alban Gruin","fromEmail":"alban.gruin@gmail.com","sentAt":"2018-08-09T13:30:35Z","receivedAt":"2018-08-09T13:30:49Z","isPatch":true,"sender":{"key":"alban.gruin@gmail.com","avatar":"https://avatars.githubusercontent.com/u/6310153?v=4"},"body":"Hi Phillip,\n\nLe 08/08/2018 à 18:04, Phillip Wood a écrit :\n>>>> +int edit_todo_list(unsigned flags)\n>>>> +{\n>>>> +    struct strbuf buf = STRBUF_INIT;\n>>>> +    const char *todo_file = rebase_path_todo();\n>>>> +    FILE *todo;\n>>>> +\n>>>> +    if (strbuf_read_file(&buf, todo_file, 0) < 0)\n>>>> +        return error_errno(_(\"could not read '%s'.\"), todo_file);\n>>>> +\n>>>> +    strbuf_stripspace(&buf, 1);\n>>>> +    todo = fopen_or_warn(todo_file, \"w\");\n>>>\n>>> This truncates the existing file, if there are any errors writing the\n>>> new one then the user has lost the old one. write_message() in\n>>> sequencer.c avoids this problem by writing a new file and then renaming\n>>> it if the write is successful, maybe it is worth exporting it so it can\n>>> be used elsewhere.\n>>>\n>>>> +    if (!todo) {\n>>>> +        strbuf_release(&buf);\n>>>> +        return 1;\n>>>> +    }\n>>>> +\n>>>> +    strbuf_write(&buf, todo);\n>>>> +    fclose(todo);\n>>>\n>>> There needs to be some error checking after the write and the close\n>>> (using write_message() would mean you only have to check for errors in\n>>> one place)\n>>>\n>>\n>> Right.  Should I find a new nawe for write_message()?\n> \n> That might be a good idea, I'm not sure what it should be though, maybe\n> write_file()?, perhaps someone else might have a better suggestion.\n> \n\nwrite_file() already exists in wrapper.c.  I wondered, as this make use\nof the lockfile API, perhaps it could be moved to lockfile.{c,h}, and\nrenamed to something like write_file_with_lock().\n\nCheers,\nAlban\n\n"},{"id":"354990","messageId":"f2698204-c376-0b0c-b151-22b45d482b7c@talktalk.net","threadId":"48814","inReplyTo":"20180731180003.5421-12-alban.gruin@gmail.com","subject":"Re: [GSoC][PATCH v5 11/20] rebase -i: rewrite complete_action() in C","fromName":"Phillip Wood","fromEmail":"phillip.wood@talktalk.net","sentAt":"2018-08-09T14:22:08Z","receivedAt":"2018-08-09T14:22:25Z","isPatch":true,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"Hi Alban\n\nIts nice to see things coming together so that the rebase happens in the \nsame process as the some of the todo file preparation. I've ended up \nmaking quite a few comments on the new implementation, but they're all \nlittle things, the basic idea looks sound to me.\n\nOn 31/07/18 18:59, Alban Gruin wrote:\n> This rewrites complete_action() from shell to C.\n> \n> A new mode is added to rebase--helper (`--complete-action`), as well as\n> a new flag (`--autosquash`).\n> \n> Finally, complete_action() is stripped from git-rebase--interactive.sh.\n> \n> The original complete_action() would return the code 2 when the todo\n> list contained no actions.  This was a special case for rebase -i and\n> -p; git-rebase.sh would then apply the autostash, delete the state\n> directory, and die with the message \"Nothing to do\".  This cleanup is\n> rewritten in C instead of returning 2.  As rebase -i no longer returns\n> 2, the comment describing this behaviour in git-rebase.sh is updated to\n> reflect this change.\n> \n> The first check might seem useless as we write \"noop\" to the todo list\n> if it is empty.  Actually, the todo list might contain commented\n> commands (ie. empty commits).  In this case, complete_action() won’t\n> write \"noop\", and will abort without starting the editor.\n> \n> Signed-off-by: Alban Gruin <alban.gruin@gmail.com>\n> ---\n> No changes since v4.\n> \n>   builtin/rebase--helper.c   | 12 ++++-\n>   git-rebase--interactive.sh | 53 ++------------------\n>   git-rebase.sh              |  2 +-\n>   sequencer.c                | 99 ++++++++++++++++++++++++++++++++++++++\n>   sequencer.h                |  4 ++\n>   5 files changed, 118 insertions(+), 52 deletions(-)\n> \n> diff --git a/builtin/rebase--helper.c b/builtin/rebase--helper.c\n> index bed3dd2b95..d7fa5a5062 100644\n> --- a/builtin/rebase--helper.c\n> +++ b/builtin/rebase--helper.c\n> @@ -13,13 +13,13 @@ static const char * const builtin_rebase_helper_usage[] = {\n>   int cmd_rebase__helper(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;\n> +\tunsigned flags = 0, keep_empty = 0, rebase_merges = 0, autosquash = 0;\n>   \tint abbreviate_commands = 0, rebase_cousins = -1;\n>   \tenum {\n>   \t\tCONTINUE = 1, ABORT, MAKE_SCRIPT, SHORTEN_OIDS, EXPAND_OIDS,\n>   \t\tCHECK_TODO_LIST, SKIP_UNNECESSARY_PICKS, REARRANGE_SQUASH,\n>   \t\tADD_EXEC, APPEND_TODO_HELP, EDIT_TODO, PREPARE_BRANCH,\n> -\t\tCHECKOUT_ONTO\n> +\t\tCHECKOUT_ONTO, COMPLETE_ACTION\n>   \t} command = 0;\n>   \tstruct option options[] = {\n>   \t\tOPT_BOOL(0, \"ff\", &opts.allow_ff, N_(\"allow fast-forward\")),\n> @@ -29,6 +29,8 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\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 thas begin with squash!/fixup!\")),\n\ns/thas/that/\n\n>   \t\tOPT__VERBOSE(&opts.verbose, N_(\"be verbose\")),\n>   \t\tOPT_CMDMODE(0, \"continue\", &command, N_(\"continue rebase\"),\n>   \t\t\t\tCONTINUE),\n> @@ -57,6 +59,8 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\n>   \t\t\t    N_(\"prepare the branch to be rebased\"), PREPARE_BRANCH),\n>   \t\tOPT_CMDMODE(0, \"checkout-onto\", &command,\n>   \t\t\t    N_(\"checkout a commit\"), CHECKOUT_ONTO),\n> +\t\tOPT_CMDMODE(0, \"complete-action\", &command,\n> +\t\t\t    N_(\"complete the action\"), COMPLETE_ACTION),\n>   \t\tOPT_END()\n>   \t};\n>   \n> @@ -110,5 +114,9 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\n>   \t\treturn !!prepare_branch_to_be_rebased(&opts, argv[1]);\n>   \tif (command == CHECKOUT_ONTO && argc == 4)\n>   \t\treturn !!checkout_onto(&opts, argv[1], argv[2], argv[3]);\n> +\tif (command == COMPLETE_ACTION && argc == 6)\n> +\t\treturn !!complete_action(&opts, flags, argv[1], argv[2], argv[3],\n> +\t\t\t\t\t argv[4], argv[5], autosquash);\n> +\n>   \tusage_with_options(builtin_rebase_helper_usage, options);\n>   }\n> diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\n> index b68f108f28..59dc4888a6 100644\n> --- a/git-rebase--interactive.sh\n> +++ b/git-rebase--interactive.sh\n> @@ -127,54 +127,6 @@ init_revisions_and_shortrevisions () {\n>   \tfi\n>   }\n>   \n> -complete_action() {\n> -\ttest -s \"$todo\" || echo noop >> \"$todo\"\n> -\ttest -z \"$autosquash\" || git rebase--helper --rearrange-squash || exit\n> -\ttest -n \"$cmd\" && git rebase--helper --add-exec-commands \"$cmd\"\n> -\n> -\ttodocount=$(git stripspace --strip-comments <\"$todo\" | wc -l)\n> -\ttodocount=${todocount##* }\n> -\n> -cat >>\"$todo\" <<EOF\n> -\n> -$comment_char $(eval_ngettext \\\n> -\t\"Rebase \\$shortrevisions onto \\$shortonto (\\$todocount command)\" \\\n> -\t\"Rebase \\$shortrevisions onto \\$shortonto (\\$todocount commands)\" \\\n> -\t\"$todocount\")\n> -EOF\n> -\tgit rebase--helper --append-todo-help ${keep_empty:+--keep-empty}\n> -\n> -\thas_action \"$todo\" ||\n> -\t\treturn 2\n> -\n> -\tcp \"$todo\" \"$todo\".backup\n> -\tcollapse_todo_ids\n> -\tgit_sequence_editor \"$todo\" ||\n> -\t\tdie_abort \"$(gettext \"Could not execute editor\")\"\n> -\n> -\thas_action \"$todo\" ||\n> -\t\treturn 2\n> -\n> -\tgit rebase--helper --check-todo-list || {\n> -\t\tret=$?\n> -\t\tgit rebase--helper --checkout-onto \"$onto_name\" \"$onto\" \\\n> -\t\t    \"$orig_head\" ${verbose:+--verbose}\n> -\t\texit $ret\n> -\t}\n> -\n> -\texpand_todo_ids\n> -\n> -\ttest -n \"$force_rebase\" ||\n> -\tonto=\"$(git rebase--helper --skip-unnecessary-picks)\" ||\n> -\tdie \"Could not skip unnecessary pick commands\"\n> -\n> -\tgit rebase--helper --checkout-onto \"$onto_name\" \"$onto\" \"$orig_head\" \\\n> -\t    ${verbose:+--verbose}\n> -\trequire_clean_work_tree \"rebase\"\n> -\texec git rebase--helper ${force_rebase:+--no-ff} $allow_empty_message \\\n> -\t     --continue\n> -}\n> -\n>   git_rebase__interactive () {\n>   \tinitiate_action \"$action\"\n>   \tret=$?\n> @@ -193,5 +145,8 @@ git_rebase__interactive () {\n>   \t\t$revisions ${restrict_revision+^$restrict_revision} >\"$todo\" ||\n>   \tdie \"$(gettext \"Could not generate todo list\")\"\n>   \n> -\tcomplete_action\n> +\texec git rebase--helper --complete-action \"$shortrevisions\" \"$onto_name\" \\\n> +\t\t\"$shortonto\" \"$orig_head\" \"$cmd\" $allow_empty_message \\\n> +\t\t${autosquash:+--autosquash} ${keep_empty:+--keep-empty} \\\n> +\t\t${verbose:+--verbose} ${force_rebase:+--no-ff}\n>   }\n> diff --git a/git-rebase.sh b/git-rebase.sh\n> index 7973447645..51a6db7daa 100755\n> --- a/git-rebase.sh\n> +++ b/git-rebase.sh\n> @@ -219,7 +219,7 @@ run_specific_rebase () {\n>   \tif test $ret -eq 0\n>   \tthen\n>   \t\tfinish_rebase\n> -\telif test $ret -eq 2 # special exit status for rebase -i\n> +\telif test $ret -eq 2 # special exit status for rebase -p\n>   \tthen\n>   \t\tapply_autostash &&\n>   \t\trm -rf \"$state_dir\" &&\n> diff --git a/sequencer.c b/sequencer.c\n> index a2e04b9eca..8102e24b19 100644\n> --- a/sequencer.c\n> +++ b/sequencer.c\n> @@ -30,6 +30,7 @@\n>   #include \"oidset.h\"\n>   #include \"commit-slab.h\"\n>   #include \"alias.h\"\n> +#include \"rebase-interactive.h\"\n>   \n>   #define GIT_REFLOG_ACTION \"GIT_REFLOG_ACTION\"\n>   \n> @@ -53,6 +54,9 @@ static GIT_PATH_FUNC(rebase_path, \"rebase-merge\")\n>    * file and written to the tail of 'done'.\n>    */\n>   GIT_PATH_FUNC(rebase_path_todo, \"rebase-merge/git-rebase-todo\")\n> +static GIT_PATH_FUNC(rebase_path_todo_backup,\n> +\t\t     \"rebase-merge/git-rebase-todo.backup\")\n> +\n>   /*\n>    * The rebase command lines that have already been processed. A line\n>    * is moved here when it is first handled, before any associated user\n> @@ -4499,6 +4503,101 @@ int skip_unnecessary_picks(struct object_id *output_oid)\n>   \treturn 0;\n>   }\n>   \n> +int complete_action(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, const char *cmd,\n> +\t\t    unsigned autosquash)\n> +{\n> +\tconst char *shortonto, *todo_file = rebase_path_todo();\n> +\tstruct todo_list todo_list = TODO_LIST_INIT;\n> +\tstruct strbuf *buf = &(todo_list.buf);\n> +\tstruct object_id oid;\n> +\tstruct stat st;\n> +\n> +\tget_oid(onto, &oid);\n\nIs onto guaranteed to exist? If not the return value of get_oid() needs \nto be checked. Otherwise a comment or an assertion might be useful here.\n\n> +\tshortonto = find_unique_abbrev(&oid, DEFAULT_ABBREV);\n> +\n> +\tif (!lstat(todo_file, &st) && st.st_size == 0 &&\n> +\t    write_message(\"noop\\n\", 5, todo_file, 0))\n> +\t\treturn error_errno(_(\"could not write '%s'\"), todo_file);\n> +\n> +\tif (autosquash && rearrange_squash())\n> +\t\treturn 1;\n\ngit functions normally return -1 for an error as the 'return error(...)' \ndoes above, is there a reason for a different return value here?\n\n> +\n> +\tif (cmd && *cmd)\n> +\t\tsequencer_add_exec_commands(cmd); > +\n> +\tif (strbuf_read_file(buf, todo_file, 0) < 0)\n> +\t\treturn error_errno(_(\"could not read '%s'.\"), todo_file);\n> +\n> +\tif (parse_insn_buffer(buf->buf, &todo_list)) {\n\nI was worried when I saw this because buf is an alias of todo_list.buf \nand I thought passing the same buffer in twice would end badly. However \nparse_insn_buffer() has a confusing signature, it expects the caller to \nhave filled todo_list.buf with the buffer to be parsed and to pass a \npointer to the same buffer. I think this should be cleaned up at some \npoint but it is outside the scope of this series.\n\n> +\t\ttodo_list_release(&todo_list);\n> +\t\treturn error(_(\"unusable todo list: '%s'\"), todo_file);\n> +\t}\n> +\n> +\tif (count_commands(&todo_list) == 0) {\n> +\t\tapply_autostash(opts);\n> +\t\tsequencer_remove_state(opts);\n> +\t\ttodo_list_release(&todo_list);\n> +\n> +\t\tfputs(\"Nothing to do\\n\", stderr);\n\nThe capital 'N' is a faithful copy of the current message in rebase.sh. \nHowever it might be worth changing it to 'n' to match the normal style \nof git error messages starting with a lowercase letter.\n\n> +\t\treturn 1;\n\nIt might be better to do 'return error(...)' instead\n\n> +\t}\n> +\n> +\tstrbuf_addch(buf, '\\n');\n> +\tstrbuf_commented_addf(buf, Q_(\"Rebase %s onto %s (%d command)\",\n> +\t\t\t\t      \"Rebase %s onto %s (%d commands)\",\n> +\t\t\t\t      count_commands(&todo_list)),\n> +\t\t\t      shortrevisions, shortonto, count_commands(&todo_list));\n> +\tappend_todo_help(0, flags & TODO_LIST_KEEP_EMPTY, buf);\n> +\n> +\tif (write_message(buf->buf, buf->len, todo_file, 0)) {\n> +\t\ttodo_list_release(&todo_list);\n> +\t\treturn error_errno(_(\"could not write '%s'\"), todo_file);\n> +\t}\n> +\n> +\tcopy_file(rebase_path_todo_backup(), todo_file, 0666);\n> +\ttransform_todos(flags | TODO_LIST_SHORTEN_IDS);\n\nBoth of the above lines can fail, so the return values need checking I \nthink.\n\n> +\n> +\tstrbuf_reset(buf);\n> +\n> +\tif (launch_sequence_editor(todo_file, buf, NULL)) {\n> +\t\tapply_autostash(opts);\n> +\t\tsequencer_remove_state(opts);\n> +\t\ttodo_list_release(&todo_list);\n> +\n> +\t\treturn error(_(\"could not execute editor\"));\n\nI think  launch_sequence_editor() will have printed an error message \nalready, so this is unnecessary.\n\n> +\t}\n> +\n> +\tstrbuf_stripspace(buf, 1);\n> +\tif (buf->len == 0) {\n> +\t\tapply_autostash(opts);\n> +\t\tsequencer_remove_state(opts);\n> +\t\ttodo_list_release(&todo_list);\n> +\n> +\t\tfputs(\"Nothing to do\\n\", stderr);\n> +\t\treturn 1;\n\nSee my comments above about 'N' and using 'return error(...)'\n\n> +\t}\n> +\n> +\ttodo_list_release(&todo_list);\n> +\n> +\tif (check_todo_list()) {\n> +\t\tcheckout_onto(opts, onto_name, onto, orig_head);\n> +\t\treturn 1;\n\ns/1/-1/?\n\n> +\t}\n> +\n> +\ttransform_todos(flags & ~(TODO_LIST_SHORTEN_IDS));\n\nI think the return value of transform_todos() needs to be checked\n\n> +\tif (opts->allow_ff && skip_unnecessary_picks(&oid))\n> +\t\treturn error(_(\"could not skip unnecessary pick commands\"));\n> +\n> +\tcheckout_onto(opts, onto_name, oid_to_hex(&oid), orig_head);\n> +\tif (require_clean_work_tree(\"rebase\", \"\", 1, 1))\n> +\t\treturn 1;\n\ns/1/-1/?\n\nBest Wishes\n\nPhillip\n\n> +\n> +\treturn sequencer_continue(opts);\n> +}\n> +\n>   struct subject2item_entry {\n>   \tstruct hashmap_entry entry;\n>   \tint i;\n> diff --git a/sequencer.h b/sequencer.h\n> index f11dabfd65..3ab3791c8a 100644\n> --- a/sequencer.h\n> +++ b/sequencer.h\n> @@ -89,6 +89,10 @@ int transform_todos(unsigned flags);\n>   enum missing_commit_check_level get_missing_commit_check_level(void);\n>   int check_todo_list(void);\n>   int skip_unnecessary_picks(struct object_id *output_oid);\n> +int complete_action(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, const char *cmd,\n> +\t\t    unsigned autosquash);\n>   int rearrange_squash(void);\n>   \n>   extern const char sign_off_header[];\n> \n\n"},{"id":"354996","messageId":"329d89f1-5ade-aeec-40bc-cd7168822d3e@talktalk.net","threadId":"48814","inReplyTo":"bc07317b-ba44-7a3c-7cb4-504b7dbc7c34@gmail.com","subject":"Re: [GSoC][PATCH v5 04/20] rebase -i: rewrite the edit-todo functionality in C","fromName":"Phillip Wood","fromEmail":"phillip.wood@talktalk.net","sentAt":"2018-08-09T15:35:45Z","receivedAt":"2018-08-09T15:35:59Z","isPatch":true,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"Hi Alban\n\nOn 09/08/18 14:30, Alban Gruin wrote:\n> Hi Phillip,\n> \n> Le 08/08/2018 à 18:04, Phillip Wood a écrit :\n>>>>> +int edit_todo_list(unsigned flags)\n>>>>> +{\n>>>>> +    struct strbuf buf = STRBUF_INIT;\n>>>>> +    const char *todo_file = rebase_path_todo();\n>>>>> +    FILE *todo;\n>>>>> +\n>>>>> +    if (strbuf_read_file(&buf, todo_file, 0) < 0)\n>>>>> +        return error_errno(_(\"could not read '%s'.\"), todo_file);\n>>>>> +\n>>>>> +    strbuf_stripspace(&buf, 1);\n>>>>> +    todo = fopen_or_warn(todo_file, \"w\");\n>>>>\n>>>> This truncates the existing file, if there are any errors writing the\n>>>> new one then the user has lost the old one. write_message() in\n>>>> sequencer.c avoids this problem by writing a new file and then renaming\n>>>> it if the write is successful, maybe it is worth exporting it so it can\n>>>> be used elsewhere.\n>>>>\n>>>>> +    if (!todo) {\n>>>>> +        strbuf_release(&buf);\n>>>>> +        return 1;\n>>>>> +    }\n>>>>> +\n>>>>> +    strbuf_write(&buf, todo);\n>>>>> +    fclose(todo);\n>>>>\n>>>> There needs to be some error checking after the write and the close\n>>>> (using write_message() would mean you only have to check for errors in\n>>>> one place)\n>>>>\n>>>\n>>> Right.  Should I find a new nawe for write_message()?\n>>\n>> That might be a good idea, I'm not sure what it should be though, maybe\n>> write_file()?, perhaps someone else might have a better suggestion.\n>>\n> \n> write_file() already exists in wrapper.c.  I wondered, as this make use\n> of the lockfile API, perhaps it could be moved to lockfile.{c,h}, and\n> renamed to something like write_file_with_lock().\n\nHmm, I'm not sure about that, to me the use of the lockfile api is just \na way to get the semantics of an atomic update to the file. Looking in \nwrapper.c there is write_file_buf() which could maybe be changed to to \nan atomic update. Looking at the current callers to that function they \nlook like they would work with such a change (sadly none of them bother \nto check the return value to see if the write was successful). I don't \nthink we need to worry about them being broken by having a stale \nlockfile left over if there's an error as I think the lockfile api \nautomatically cleans them up but I'm not an expert on that api so it \nwould be worth checking with someone like Johannes or Jeff King (I seem \nto remember him working in that area relatively recently).\n\nBest Wishes\n\nPhillip\n\n\n> Cheers,\n> Alban\n> \n\n"},{"id":"355007","messageId":"d8b203b6-6fbe-1751-3c85-a8e7991bd765@talktalk.net","threadId":"48814","inReplyTo":"329d89f1-5ade-aeec-40bc-cd7168822d3e@talktalk.net","subject":"Re: [GSoC][PATCH v5 04/20] rebase -i: rewrite the edit-todo functionality in C","fromName":"Phillip Wood","fromEmail":"phillip.wood@talktalk.net","sentAt":"2018-08-09T16:09:35Z","receivedAt":"2018-08-09T16:09:50Z","isPatch":true,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"Hi Alban\n\nOn 09/08/18 16:35, Phillip Wood wrote:\n> Hi Alban\n> \n> On 09/08/18 14:30, Alban Gruin wrote:\n>> Hi Phillip,\n>>\n>> Le 08/08/2018 à 18:04, Phillip Wood a écrit :\n>>>>>> +int edit_todo_list(unsigned flags)\n>>>>>> +{\n>>>>>> +    struct strbuf buf = STRBUF_INIT;\n>>>>>> +    const char *todo_file = rebase_path_todo();\n>>>>>> +    FILE *todo;\n>>>>>> +\n>>>>>> +    if (strbuf_read_file(&buf, todo_file, 0) < 0)\n>>>>>> +        return error_errno(_(\"could not read '%s'.\"), todo_file);\n>>>>>> +\n>>>>>> +    strbuf_stripspace(&buf, 1);\n>>>>>> +    todo = fopen_or_warn(todo_file, \"w\");\n>>>>>\n>>>>> This truncates the existing file, if there are any errors writing the\n>>>>> new one then the user has lost the old one. write_message() in\n>>>>> sequencer.c avoids this problem by writing a new file and then \n>>>>> renaming\n>>>>> it if the write is successful, maybe it is worth exporting it so it \n>>>>> can\n>>>>> be used elsewhere.\n>>>>>\n>>>>>> +    if (!todo) {\n>>>>>> +        strbuf_release(&buf);\n>>>>>> +        return 1;\n>>>>>> +    }\n>>>>>> +\n>>>>>> +    strbuf_write(&buf, todo);\n>>>>>> +    fclose(todo);\n>>>>>\n>>>>> There needs to be some error checking after the write and the close\n>>>>> (using write_message() would mean you only have to check for errors in\n>>>>> one place)\n>>>>>\n>>>>\n>>>> Right.  Should I find a new nawe for write_message()?\n>>>\n>>> That might be a good idea, I'm not sure what it should be though, maybe\n>>> write_file()?, perhaps someone else might have a better suggestion.\n>>>\n>>\n>> write_file() already exists in wrapper.c.  I wondered, as this make use\n>> of the lockfile API, perhaps it could be moved to lockfile.{c,h}, and\n>> renamed to something like write_file_with_lock().\n> \n> Hmm, I'm not sure about that, to me the use of the lockfile api is just \n> a way to get the semantics of an atomic update to the file. Looking in \n> wrapper.c there is write_file_buf() which could maybe be changed to to \n> an atomic update. Looking at the current callers to that function they \n> look like they would work with such a change (sadly none of them bother \n> to check the return value to see if the write was successful). I don't \n> think we need to worry about them being broken by having a stale \n> lockfile left over if there's an error as I think the lockfile api \n> automatically cleans them up but I'm not an expert on that api so it \n> would be worth checking with someone like Johannes or Jeff King (I seem \n> to remember him working in that area relatively recently).\n\nOn second thoughts the current function dies rather than returning an \nerror so it would be a bit of work to do the conversion properly. For \nnow you could just make write_message() available outside sequencer.c \nand see if anyone comes up with a better name when v6 is reviewed.\n\nBest Wishes\n\nPhillip\n\n> Best Wishes\n> \n> Phillip\n> \n> \n>> Cheers,\n>> Alban\n>>\n> \n\n"},{"id":"355008","messageId":"df96eadb-8c97-2c21-3ab9-6ffbaa61160c@gmail.com","threadId":"48814","inReplyTo":"f2698204-c376-0b0c-b151-22b45d482b7c@talktalk.net","subject":"Re: [GSoC][PATCH v5 11/20] rebase -i: rewrite complete_action() in C","fromName":"Alban Gruin","fromEmail":"alban.gruin@gmail.com","sentAt":"2018-08-09T17:00:27Z","receivedAt":"2018-08-09T17:00:34Z","isPatch":true,"sender":{"key":"alban.gruin@gmail.com","avatar":"https://avatars.githubusercontent.com/u/6310153?v=4"},"body":"Le 09/08/2018 à 16:22, Phillip Wood a écrit :\n>>   +int complete_action(struct replay_opts *opts, unsigned flags,\n>> +            const char *shortrevisions, const char *onto_name,\n>> +            const char *onto, const char *orig_head, const char *cmd,\n>> +            unsigned autosquash)\n>> +{\n>> +    const char *shortonto, *todo_file = rebase_path_todo();\n>> +    struct todo_list todo_list = TODO_LIST_INIT;\n>> +    struct strbuf *buf = &(todo_list.buf);\n>> +    struct object_id oid;\n>> +    struct stat st;\n>> +\n>> +    get_oid(onto, &oid);\n> \n> Is onto guaranteed to exist? If not the return value of get_oid() needs\n> to be checked. Otherwise a comment or an assertion might be useful here.\n> \n\nYes, either the user defines it manually (with --onto=), or it is\nautomatically determinated by git-rebase.sh.\n\n>> +    shortonto = find_unique_abbrev(&oid, DEFAULT_ABBREV);\n>> +\n>> +    if (!lstat(todo_file, &st) && st.st_size == 0 &&\n>> +        write_message(\"noop\\n\", 5, todo_file, 0))\n>> +        return error_errno(_(\"could not write '%s'\"), todo_file);\n>> +\n>> +    if (autosquash && rearrange_squash())\n>> +        return 1;\n> \n> git functions normally return -1 for an error as the 'return error(...)'\n> does above, is there a reason for a different return value here?\n> \n\nNo, I will fix this.\n\n>> +\n>> +    if (cmd && *cmd)\n>> +        sequencer_add_exec_commands(cmd); > +\n>> +    if (strbuf_read_file(buf, todo_file, 0) < 0)\n>> +        return error_errno(_(\"could not read '%s'.\"), todo_file);\n>> +\n>> +    if (parse_insn_buffer(buf->buf, &todo_list)) {\n> \n> I was worried when I saw this because buf is an alias of todo_list.buf\n> and I thought passing the same buffer in twice would end badly. However\n> parse_insn_buffer() has a confusing signature, it expects the caller to\n> have filled todo_list.buf with the buffer to be parsed and to pass a\n> pointer to the same buffer. I think this should be cleaned up at some\n> point but it is outside the scope of this series.\n> \n>> +        todo_list_release(&todo_list);\n>> +        return error(_(\"unusable todo list: '%s'\"), todo_file);\n>> +    }\n>> +\n>> +    if (count_commands(&todo_list) == 0) {\n>> +        apply_autostash(opts);\n>> +        sequencer_remove_state(opts);\n>> +        todo_list_release(&todo_list);\n>> +\n>> +        fputs(\"Nothing to do\\n\", stderr);\n> \n> The capital 'N' is a faithful copy of the current message in rebase.sh.\n> However it might be worth changing it to 'n' to match the normal style\n> of git error messages starting with a lowercase letter.\n> \n>> +        return 1;\n> \n> It might be better to do 'return error(...)' instead\n> \n\nThis will require a test change – not a big deal, of course.  It’s\nperhaps a good idea to mark this string for translation, too.\n\n>> +    }\n>> +\n>> +    strbuf_addch(buf, '\\n');\n>> +    strbuf_commented_addf(buf, Q_(\"Rebase %s onto %s (%d command)\",\n>> +                      \"Rebase %s onto %s (%d commands)\",\n>> +                      count_commands(&todo_list)),\n>> +                  shortrevisions, shortonto,\n>> count_commands(&todo_list));\n>> +    append_todo_help(0, flags & TODO_LIST_KEEP_EMPTY, buf);\n>> +\n>> +    if (write_message(buf->buf, buf->len, todo_file, 0)) {\n>> +        todo_list_release(&todo_list);\n>> +        return error_errno(_(\"could not write '%s'\"), todo_file);\n>> +    }\n>> +\n>> +    copy_file(rebase_path_todo_backup(), todo_file, 0666);\n>> +    transform_todos(flags | TODO_LIST_SHORTEN_IDS);\n> \n> Both of the above lines can fail, so the return values need checking I\n> think.\n> \n>> +\n>> +    strbuf_reset(buf);\n>> +\n>> +    if (launch_sequence_editor(todo_file, buf, NULL)) {\n>> +        apply_autostash(opts);\n>> +        sequencer_remove_state(opts);\n>> +        todo_list_release(&todo_list);\n>> +\n>> +        return error(_(\"could not execute editor\"));\n> \n> I think  launch_sequence_editor() will have printed an error message\n> already, so this is unnecessary.\n> \n\nAnd the error would be more specific, true.\n\nThanks!\nAlban\n\n"},{"id":"355094","messageId":"20180810165147.4779-1-alban.gruin@gmail.com","threadId":"48814","inReplyTo":"20180731180003.5421-1-alban.gruin@gmail.com","subject":"[GSoC][PATCH v6 00/20] rebase -i: rewrite in C","fromName":"Alban Gruin","fromEmail":"alban.gruin@gmail.com","sentAt":"2018-08-10T16:51:27Z","receivedAt":"2018-08-10T16:52:16Z","isPatch":true,"sender":{"key":"alban.gruin@gmail.com","avatar":"https://avatars.githubusercontent.com/u/6310153?v=4"},"body":"This patch series rewrite the interactive rebase from shell to C.\n\nIt is based on ffc6fa0e39 (\"Fourth batch for 2.19 cycle\", 2018-07-24).\nThis apply cleanly to 1d89318c48 (\"Fifth batch for 2.19 cycle\"), and\ndoes not break tests.\n\nChanges since v5:\n\n - [01/20] Make write_message() public.\n\n - [04/20] Use write_message() inside of edit_todo_list().\n\n - [08/20, 11/20 & 17/20] Return -1 instead of 1 in case of error inside\n   of complete_action(), edit_todo_list(), append_todo_help_to_file(),\n   and do_interactive_rebase().\n\n - [11/20] Better error management in complete_action().\n\n - [11/20] Use error() to show the message \"Nothing to do\".\n\n - [11/20] Typofix.\n\nAlban Gruin (20):\n  sequencer: make three functions and an enum from sequencer.c public\n  rebase -i: rewrite append_todo_help() in C\n  editor: add a function to launch the sequence editor\n  rebase -i: rewrite the edit-todo functionality in C\n  sequencer: add a new function to silence a command, except if it fails\n  rebase -i: rewrite setup_reflog_action() in C\n  rebase -i: rewrite checkout_onto() in C\n  sequencer: refactor append_todo_help() to write its message to a\n    buffer\n  sequencer: change the way skip_unnecessary_picks() returns its result\n  t3404: todo list with commented-out commands only aborts\n  rebase -i: rewrite complete_action() in C\n  rebase -i: remove unused modes and functions\n  rebase -i: implement the logic to initialize $revisions in C\n  rebase -i: rewrite the rest of init_revisions_and_shortrevisions() in\n    C\n  rebase -i: rewrite write_basic_state() in C\n  rebase -i: rewrite init_basic_state() in C\n  rebase -i: implement the main part of interactive rebase as a builtin\n  rebase--interactive2: rewrite the submodes of interactive rebase in C\n  rebase -i: remove git-rebase--interactive.sh\n  rebase -i: move rebase--helper modes to rebase--interactive\n\n .gitignore                     |   1 -\n Makefile                       |   5 +-\n builtin.h                      |   2 +-\n builtin/rebase--helper.c       |  88 ---------\n builtin/rebase--interactive.c  | 264 +++++++++++++++++++++++++++\n cache.h                        |   1 +\n editor.c                       |  27 ++-\n git-rebase--interactive.sh     | 283 -----------------------------\n git-rebase--preserve-merges.sh |  10 +-\n git-rebase.sh                  |  47 ++++-\n git.c                          |   2 +-\n rebase-interactive.c           |  90 ++++++++++\n rebase-interactive.h           |   8 +\n sequencer.c                    | 318 +++++++++++++++++++++++++++------\n sequencer.h                    |  22 ++-\n strbuf.h                       |   2 +\n t/t3404-rebase-interactive.sh  |  10 ++\n 17 files changed, 731 insertions(+), 449 deletions(-)\n delete mode 100644 builtin/rebase--helper.c\n create mode 100644 builtin/rebase--interactive.c\n delete mode 100644 git-rebase--interactive.sh\n create mode 100644 rebase-interactive.c\n create mode 100644 rebase-interactive.h\n\n-- \n2.18.0\n\n"},{"id":"355095","messageId":"20180810165147.4779-2-alban.gruin@gmail.com","threadId":"48814","inReplyTo":"20180810165147.4779-1-alban.gruin@gmail.com","subject":"[GSoC][PATCH v6 01/20] sequencer: make three functions and an enum from sequencer.c public","fromName":"Alban Gruin","fromEmail":"alban.gruin@gmail.com","sentAt":"2018-08-10T16:51:28Z","receivedAt":"2018-08-10T16:52:19Z","isPatch":true,"sender":{"key":"alban.gruin@gmail.com","avatar":"https://avatars.githubusercontent.com/u/6310153?v=4"},"body":"This makes rebase_path_todo(), get_missing_commit_check_level(),\nwrite_message() and the enum check_level accessible outside sequencer.c,\nrenames check_level to missing_commit_check_level, and prefixes its\nvalue names by MISSING_COMMIT_ to avoid namespace pollution.\n\nThis function and this enum will eventually be moved to\nrebase-interactive.c and become static again, so no special attention\nwas given to the naming.\n\nThis will be needed for the rewrite of append_todo_help() from shell to\nC, as it will be in a new library source file, rebase-interactive.c.\n\nSigned-off-by: Alban Gruin <alban.gruin@gmail.com>\n---\n sequencer.c | 26 +++++++++++---------------\n sequencer.h | 11 +++++++++++\n 2 files changed, 22 insertions(+), 15 deletions(-)\n\ndiff --git a/sequencer.c b/sequencer.c\nindex 16c1411054..dd1b060863 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -52,7 +52,7 @@ static GIT_PATH_FUNC(rebase_path, \"rebase-merge\")\n  * the lines are processed, they are removed from the front of this\n  * file and written to the tail of 'done'.\n  */\n-static GIT_PATH_FUNC(rebase_path_todo, \"rebase-merge/git-rebase-todo\")\n+GIT_PATH_FUNC(rebase_path_todo, \"rebase-merge/git-rebase-todo\")\n /*\n  * The rebase command lines that have already been processed. A line\n  * is moved here when it is first handled, before any associated user\n@@ -373,8 +373,8 @@ static void print_advice(int show_hint, struct replay_opts *opts)\n \t}\n }\n \n-static int write_message(const void *buf, size_t len, const char *filename,\n-\t\t\t int append_eol)\n+int write_message(const void *buf, size_t len, const char *filename,\n+\t\t  int append_eol)\n {\n \tstruct lock_file msg_file = LOCK_INIT;\n \n@@ -4249,24 +4249,20 @@ int transform_todos(unsigned flags)\n \treturn i;\n }\n \n-enum check_level {\n-\tCHECK_IGNORE = 0, CHECK_WARN, CHECK_ERROR\n-};\n-\n-static enum check_level get_missing_commit_check_level(void)\n+enum missing_commit_check_level get_missing_commit_check_level(void)\n {\n \tconst char *value;\n \n \tif (git_config_get_value(\"rebase.missingcommitscheck\", &value) ||\n \t\t\t!strcasecmp(\"ignore\", value))\n-\t\treturn CHECK_IGNORE;\n+\t\treturn MISSING_COMMIT_CHECK_IGNORE;\n \tif (!strcasecmp(\"warn\", value))\n-\t\treturn CHECK_WARN;\n+\t\treturn MISSING_COMMIT_CHECK_WARN;\n \tif (!strcasecmp(\"error\", value))\n-\t\treturn CHECK_ERROR;\n+\t\treturn MISSING_COMMIT_CHECK_ERROR;\n \twarning(_(\"unrecognized setting %s for option \"\n \t\t  \"rebase.missingCommitsCheck. Ignoring.\"), value);\n-\treturn CHECK_IGNORE;\n+\treturn MISSING_COMMIT_CHECK_IGNORE;\n }\n \n define_commit_slab(commit_seen, unsigned char);\n@@ -4278,7 +4274,7 @@ define_commit_slab(commit_seen, unsigned char);\n  */\n int check_todo_list(void)\n {\n-\tenum check_level check_level = get_missing_commit_check_level();\n+\tenum missing_commit_check_level check_level = get_missing_commit_check_level();\n \tstruct strbuf todo_file = STRBUF_INIT;\n \tstruct todo_list todo_list = TODO_LIST_INIT;\n \tstruct strbuf missing = STRBUF_INIT;\n@@ -4295,7 +4291,7 @@ int check_todo_list(void)\n \tadvise_to_edit_todo = res =\n \t\tparse_insn_buffer(todo_list.buf.buf, &todo_list);\n \n-\tif (res || check_level == CHECK_IGNORE)\n+\tif (res || check_level == MISSING_COMMIT_CHECK_IGNORE)\n \t\tgoto leave_check;\n \n \t/* Mark the commits in git-rebase-todo as seen */\n@@ -4330,7 +4326,7 @@ int check_todo_list(void)\n \tif (!missing.len)\n \t\tgoto leave_check;\n \n-\tif (check_level == CHECK_ERROR)\n+\tif (check_level == MISSING_COMMIT_CHECK_ERROR)\n \t\tadvise_to_edit_todo = res = 1;\n \n \tfprintf(stderr,\ndiff --git a/sequencer.h b/sequencer.h\nindex c5787c6b56..792e448b67 100644\n--- a/sequencer.h\n+++ b/sequencer.h\n@@ -3,6 +3,7 @@\n \n const char *git_path_commit_editmsg(void);\n const char *git_path_seq_dir(void);\n+const char *rebase_path_todo(void);\n \n #define APPEND_SIGNOFF_DEDUP (1u << 0)\n \n@@ -57,6 +58,15 @@ struct replay_opts {\n };\n #define REPLAY_OPTS_INIT { .action = -1, .current_fixups = STRBUF_INIT }\n \n+enum missing_commit_check_level {\n+\tMISSING_COMMIT_CHECK_IGNORE = 0,\n+\tMISSING_COMMIT_CHECK_WARN,\n+\tMISSING_COMMIT_CHECK_ERROR\n+};\n+\n+int write_message(const void *buf, size_t len, const char *filename,\n+\t\t  int append_eol);\n+\n /* Call this to setup defaults before parsing command line options */\n void sequencer_init_config(struct replay_opts *opts);\n int sequencer_pick_revisions(struct replay_opts *opts);\n@@ -79,6 +89,7 @@ int sequencer_make_script(FILE *out, int argc, const char **argv,\n \n int sequencer_add_exec_commands(const char *command);\n int transform_todos(unsigned flags);\n+enum missing_commit_check_level get_missing_commit_check_level(void);\n int check_todo_list(void);\n int skip_unnecessary_picks(void);\n int rearrange_squash(void);\n-- \n2.18.0\n\n"},{"id":"355096","messageId":"20180810165147.4779-3-alban.gruin@gmail.com","threadId":"48814","inReplyTo":"20180810165147.4779-1-alban.gruin@gmail.com","subject":"[GSoC][PATCH v6 02/20] rebase -i: rewrite append_todo_help() in C","fromName":"Alban Gruin","fromEmail":"alban.gruin@gmail.com","sentAt":"2018-08-10T16:51:29Z","receivedAt":"2018-08-10T16:52:21Z","isPatch":true,"sender":{"key":"alban.gruin@gmail.com","avatar":"https://avatars.githubusercontent.com/u/6310153?v=4"},"body":"This rewrites append_todo_help() from shell to C. It also incorporates\nsome parts of initiate_action() and complete_action() that also write\nhelp texts to the todo file.\n\nThis also introduces the source file rebase-interactive.c. This file\nwill contain functions necessary for interactive rebase that are too\nspecific for the sequencer, and is part of libgit.a.\n\nTwo flags are added to rebase--helper.c: one to call\nappend_todo_help() (`--append-todo-help`), and another one to tell\nappend_todo_help() to write the help text suited for the edit-todo\nmode (`--write-edit-todo`).\n\nFinally, append_todo_help() is removed from git-rebase--interactive.sh\nto use `rebase--helper --append-todo-help` instead.\n\nSigned-off-by: Alban Gruin <alban.gruin@gmail.com>\n---\nNo changes since v5.\n\n Makefile                   |  1 +\n builtin/rebase--helper.c   | 11 ++++--\n git-rebase--interactive.sh | 52 ++---------------------------\n rebase-interactive.c       | 68 ++++++++++++++++++++++++++++++++++++++\n rebase-interactive.h       |  6 ++++\n 5 files changed, 86 insertions(+), 52 deletions(-)\n create mode 100644 rebase-interactive.c\n create mode 100644 rebase-interactive.h\n\ndiff --git a/Makefile b/Makefile\nindex 08e5c54549..909a687857 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -922,6 +922,7 @@ LIB_OBJS += protocol.o\n LIB_OBJS += quote.o\n LIB_OBJS += reachable.o\n LIB_OBJS += read-cache.o\n+LIB_OBJS += rebase-interactive.o\n LIB_OBJS += reflog-walk.o\n LIB_OBJS += refs.o\n LIB_OBJS += refs/files-backend.o\ndiff --git a/builtin/rebase--helper.c b/builtin/rebase--helper.c\nindex f7c2a5fdc8..05e73e71d4 100644\n--- a/builtin/rebase--helper.c\n+++ b/builtin/rebase--helper.c\n@@ -3,6 +3,7 @@\n #include \"config.h\"\n #include \"parse-options.h\"\n #include \"sequencer.h\"\n+#include \"rebase-interactive.h\"\n \n static const char * const builtin_rebase_helper_usage[] = {\n \tN_(\"git rebase--helper [<options>]\"),\n@@ -12,12 +13,12 @@ static const char * const builtin_rebase_helper_usage[] = {\n int cmd_rebase__helper(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;\n+\tunsigned flags = 0, keep_empty = 0, rebase_merges = 0, write_edit_todo = 0;\n \tint abbreviate_commands = 0, rebase_cousins = -1;\n \tenum {\n \t\tCONTINUE = 1, ABORT, MAKE_SCRIPT, SHORTEN_OIDS, EXPAND_OIDS,\n \t\tCHECK_TODO_LIST, SKIP_UNNECESSARY_PICKS, REARRANGE_SQUASH,\n-\t\tADD_EXEC\n+\t\tADD_EXEC, APPEND_TODO_HELP\n \t} command = 0;\n \tstruct option options[] = {\n \t\tOPT_BOOL(0, \"ff\", &opts.allow_ff, N_(\"allow fast-forward\")),\n@@ -27,6 +28,8 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\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, \"write-edit-todo\", &write_edit_todo,\n+\t\t\t N_(\"append the edit-todo message to the todo-list\")),\n \t\tOPT_CMDMODE(0, \"continue\", &command, N_(\"continue rebase\"),\n \t\t\t\tCONTINUE),\n \t\tOPT_CMDMODE(0, \"abort\", &command, N_(\"abort rebase\"),\n@@ -45,6 +48,8 @@ int cmd_rebase__helper(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_CMDMODE(0, \"append-todo-help\", &command,\n+\t\t\t    N_(\"insert the help in the todo list\"), APPEND_TODO_HELP),\n \t\tOPT_END()\n \t};\n \n@@ -84,5 +89,7 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\n \t\treturn !!rearrange_squash();\n \tif (command == ADD_EXEC && argc == 2)\n \t\treturn !!sequencer_add_exec_commands(argv[1]);\n+\tif (command == APPEND_TODO_HELP && argc == 1)\n+\t\treturn !!append_todo_help(write_edit_todo, keep_empty);\n \tusage_with_options(builtin_rebase_helper_usage, options);\n }\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex 299ded2137..94c23a7af2 100644\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -39,38 +39,6 @@ comment_for_reflog () {\n \tesac\n }\n \n-append_todo_help () {\n-\tgettext \"\n-Commands:\n-p, pick <commit> = use commit\n-r, reword <commit> = use commit, but edit the commit message\n-e, edit <commit> = use commit, but stop for amending\n-s, squash <commit> = use commit, but meld into previous commit\n-f, fixup <commit> = like \\\"squash\\\", but discard this commit's log message\n-x, exec <command> = run command (the rest of the line) using shell\n-d, drop <commit> = remove commit\n-l, label <label> = label current HEAD with a name\n-t, reset <label> = reset HEAD to a label\n-m, merge [-C <commit> | -c <commit>] <label> [# <oneline>]\n-.       create a merge commit using the original merge commit's\n-.       message (or the oneline, if no original merge commit was\n-.       specified). Use -c <commit> to reword the commit message.\n-\n-These lines can be re-ordered; they are executed from top to bottom.\n-\" | git stripspace --comment-lines >>\"$todo\"\n-\n-\tif test $(get_missing_commit_check_level) = error\n-\tthen\n-\t\tgettext \"\n-Do not remove any line. Use 'drop' explicitly to remove a commit.\n-\" | git stripspace --comment-lines >>\"$todo\"\n-\telse\n-\t\tgettext \"\n-If you remove a line here THAT COMMIT WILL BE LOST.\n-\" | git stripspace --comment-lines >>\"$todo\"\n-\tfi\n-}\n-\n die_abort () {\n \tapply_autostash\n \trm -rf \"$state_dir\"\n@@ -143,13 +111,7 @@ initiate_action () {\n \t\tgit stripspace --strip-comments <\"$todo\" >\"$todo\".new\n \t\tmv -f \"$todo\".new \"$todo\"\n \t\tcollapse_todo_ids\n-\t\tappend_todo_help\n-\t\tgettext \"\n-You are editing the todo file of an ongoing interactive rebase.\n-To continue rebase after editing, run:\n-    git rebase --continue\n-\n-\" | git stripspace --comment-lines >>\"$todo\"\n+\t\tgit rebase--helper --append-todo-help --write-edit-todo\n \n \t\tgit_sequence_editor \"$todo\" ||\n \t\t\tdie \"$(gettext \"Could not execute editor\")\"\n@@ -220,17 +182,7 @@ $comment_char $(eval_ngettext \\\n \t\"Rebase \\$shortrevisions onto \\$shortonto (\\$todocount commands)\" \\\n \t\"$todocount\")\n EOF\n-\tappend_todo_help\n-\tgettext \"\n-\tHowever, if you remove everything, the rebase will be aborted.\n-\n-\t\" | git stripspace --comment-lines >>\"$todo\"\n-\n-\tif test -z \"$keep_empty\"\n-\tthen\n-\t\tprintf '%s\\n' \"$comment_char $(gettext \"Note that empty commits are commented out\")\" >>\"$todo\"\n-\tfi\n-\n+\tgit rebase--helper --append-todo-help ${keep_empty:+--keep-empty}\n \n \thas_action \"$todo\" ||\n \t\treturn 2\ndiff --git a/rebase-interactive.c b/rebase-interactive.c\nnew file mode 100644\nindex 0000000000..d7996bc8d9\n--- /dev/null\n+++ b/rebase-interactive.c\n@@ -0,0 +1,68 @@\n+#include \"cache.h\"\n+#include \"commit.h\"\n+#include \"rebase-interactive.h\"\n+#include \"sequencer.h\"\n+#include \"strbuf.h\"\n+\n+int append_todo_help(unsigned edit_todo, unsigned keep_empty)\n+{\n+\tstruct strbuf buf = STRBUF_INIT;\n+\tFILE *todo;\n+\tint ret;\n+\tconst char *msg = _(\"\\nCommands:\\n\"\n+\"p, pick <commit> = use commit\\n\"\n+\"r, reword <commit> = use commit, but edit the commit message\\n\"\n+\"e, edit <commit> = use commit, but stop for amending\\n\"\n+\"s, squash <commit> = use commit, but meld into previous commit\\n\"\n+\"f, fixup <commit> = like \\\"squash\\\", but discard this commit's log message\\n\"\n+\"x, exec <command> = run command (the rest of the line) using shell\\n\"\n+\"d, drop <commit> = remove commit\\n\"\n+\"l, label <label> = label current HEAD with a name\\n\"\n+\"t, reset <label> = reset HEAD to a label\\n\"\n+\"m, merge [-C <commit> | -c <commit>] <label> [# <oneline>]\\n\"\n+\".       create a merge commit using the original merge commit's\\n\"\n+\".       message (or the oneline, if no original merge commit was\\n\"\n+\".       specified). Use -c <commit> to reword the commit message.\\n\"\n+\"\\n\"\n+\"These lines can be re-ordered; they are executed from top to bottom.\\n\");\n+\n+\ttodo = fopen_or_warn(rebase_path_todo(), \"a\");\n+\tif (!todo)\n+\t\treturn 1;\n+\n+\tstrbuf_add_commented_lines(&buf, msg, strlen(msg));\n+\n+\tif (get_missing_commit_check_level() == MISSING_COMMIT_CHECK_ERROR)\n+\t\tmsg = _(\"\\nDo not remove any line. Use 'drop' \"\n+\t\t\t \"explicitly to remove a commit.\\n\");\n+\telse\n+\t\tmsg = _(\"\\nIf you remove a line here \"\n+\t\t\t \"THAT COMMIT WILL BE LOST.\\n\");\n+\n+\tstrbuf_add_commented_lines(&buf, msg, strlen(msg));\n+\n+\tif (edit_todo)\n+\t\tmsg = _(\"\\nYou are editing the todo file \"\n+\t\t\t\"of an ongoing interactive rebase.\\n\"\n+\t\t\t\"To continue rebase after editing, run:\\n\"\n+\t\t\t\"    git rebase --continue\\n\\n\");\n+\telse\n+\t\tmsg = _(\"\\nHowever, if you remove everything, \"\n+\t\t\t\"the rebase will be aborted.\\n\\n\");\n+\n+\tstrbuf_add_commented_lines(&buf, msg, strlen(msg));\n+\n+\tif (!keep_empty) {\n+\t\tmsg = _(\"Note that empty commits are commented out\");\n+\t\tstrbuf_add_commented_lines(&buf, msg, strlen(msg));\n+\t}\n+\n+\tret = fputs(buf.buf, todo);\n+\tif (ret < 0)\n+\t\terror_errno(_(\"could not append help text to '%s'\"), rebase_path_todo());\n+\n+\tfclose(todo);\n+\tstrbuf_release(&buf);\n+\n+\treturn ret;\n+}\ndiff --git a/rebase-interactive.h b/rebase-interactive.h\nnew file mode 100644\nindex 0000000000..47372624e0\n--- /dev/null\n+++ b/rebase-interactive.h\n@@ -0,0 +1,6 @@\n+#ifndef REBASE_INTERACTIVE_H\n+#define REBASE_INTERACTIVE_H\n+\n+int append_todo_help(unsigned edit_todo, unsigned keep_empty);\n+\n+#endif\n-- \n2.18.0\n\n"},{"id":"355097","messageId":"20180810165147.4779-4-alban.gruin@gmail.com","threadId":"48814","inReplyTo":"20180810165147.4779-1-alban.gruin@gmail.com","subject":"[GSoC][PATCH v6 03/20] editor: add a function to launch the sequence editor","fromName":"Alban Gruin","fromEmail":"alban.gruin@gmail.com","sentAt":"2018-08-10T16:51:30Z","receivedAt":"2018-08-10T16:52:22Z","isPatch":true,"sender":{"key":"alban.gruin@gmail.com","avatar":"https://avatars.githubusercontent.com/u/6310153?v=4"},"body":"As part of the rewrite of interactive rebase, the sequencer will need to\nopen the sequence editor to allow the user to edit the todo list.\nInstead of duplicating the existing launch_editor() function, this\nrefactors it to a new function, launch_specified_editor(), which takes\nthe editor as a parameter, in addition to the path, the buffer and the\nenvironment variables.  launch_sequence_editor() is then added to launch\nthe sequence editor.\n\nSigned-off-by: Alban Gruin <alban.gruin@gmail.com>\n---\nNo changes since v5.\n\n cache.h  |  1 +\n editor.c | 27 +++++++++++++++++++++++++--\n strbuf.h |  2 ++\n 3 files changed, 28 insertions(+), 2 deletions(-)\n\ndiff --git a/cache.h b/cache.h\nindex 8b447652a7..d70ae49ca2 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -1409,6 +1409,7 @@ extern const char *fmt_name(const char *name, const char *email);\n extern const char *ident_default_name(void);\n extern const char *ident_default_email(void);\n extern const char *git_editor(void);\n+extern const char *git_sequence_editor(void);\n extern const char *git_pager(int stdout_is_tty);\n extern int is_terminal_dumb(void);\n extern int git_ident_config(const char *, const char *, void *);\ndiff --git a/editor.c b/editor.c\nindex 9a9b4e12d1..c985eee1f9 100644\n--- a/editor.c\n+++ b/editor.c\n@@ -1,4 +1,5 @@\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"strbuf.h\"\n #include \"run-command.h\"\n #include \"sigchain.h\"\n@@ -34,10 +35,21 @@ const char *git_editor(void)\n \treturn editor;\n }\n \n-int launch_editor(const char *path, struct strbuf *buffer, const char *const *env)\n+const char *git_sequence_editor(void)\n {\n-\tconst char *editor = git_editor();\n+\tconst char *editor = getenv(\"GIT_SEQUENCE_EDITOR\");\n+\n+\tif (!editor)\n+\t\tgit_config_get_string_const(\"sequence.editor\", &editor);\n+\tif (!editor)\n+\t\teditor = git_editor();\n \n+\treturn editor;\n+}\n+\n+static int launch_specified_editor(const char *editor, const char *path,\n+\t\t\t\t   struct strbuf *buffer, const char *const *env)\n+{\n \tif (!editor)\n \t\treturn error(\"Terminal is dumb, but EDITOR unset\");\n \n@@ -95,3 +107,14 @@ int launch_editor(const char *path, struct strbuf *buffer, const char *const *en\n \t\treturn error_errno(\"could not read file '%s'\", path);\n \treturn 0;\n }\n+\n+int launch_editor(const char *path, struct strbuf *buffer, const char *const *env)\n+{\n+\treturn launch_specified_editor(git_editor(), path, buffer, env);\n+}\n+\n+int launch_sequence_editor(const char *path, struct strbuf *buffer,\n+\t\t\t   const char *const *env)\n+{\n+\treturn launch_specified_editor(git_sequence_editor(), path, buffer, env);\n+}\ndiff --git a/strbuf.h b/strbuf.h\nindex 60a35aef16..66da9822fd 100644\n--- a/strbuf.h\n+++ b/strbuf.h\n@@ -575,6 +575,8 @@ extern void strbuf_add_unique_abbrev(struct strbuf *sb,\n  * file's contents are not read into the buffer upon completion.\n  */\n extern int launch_editor(const char *path, struct strbuf *buffer, const char *const *env);\n+extern int launch_sequence_editor(const char *path, struct strbuf *buffer,\n+\t\t\t\t  const char *const *env);\n \n extern void strbuf_add_lines(struct strbuf *sb, const char *prefix, const char *buf, size_t size);\n \n-- \n2.18.0\n\n"},{"id":"355098","messageId":"20180810165147.4779-5-alban.gruin@gmail.com","threadId":"48814","inReplyTo":"20180810165147.4779-1-alban.gruin@gmail.com","subject":"[GSoC][PATCH v6 04/20] rebase -i: rewrite the edit-todo functionality in C","fromName":"Alban Gruin","fromEmail":"alban.gruin@gmail.com","sentAt":"2018-08-10T16:51:31Z","receivedAt":"2018-08-10T16:52:24Z","isPatch":true,"sender":{"key":"alban.gruin@gmail.com","avatar":"https://avatars.githubusercontent.com/u/6310153?v=4"},"body":"This rewrites the edit-todo functionality from shell to C.\n\nTo achieve that, a new command mode, `edit-todo`, is added, and the\n`write-edit-todo` flag is removed, as the shell script does not need to\nwrite the edit todo help message to the todo list anymore.\n\nThe shell version is then stripped in favour of a call to the helper.\n\nSigned-off-by: Alban Gruin <alban.gruin@gmail.com>\n---\n builtin/rebase--helper.c   | 13 ++++++++-----\n git-rebase--interactive.sh | 11 +----------\n rebase-interactive.c       | 27 +++++++++++++++++++++++++++\n rebase-interactive.h       |  1 +\n 4 files changed, 37 insertions(+), 15 deletions(-)\n\ndiff --git a/builtin/rebase--helper.c b/builtin/rebase--helper.c\nindex 05e73e71d4..731a64971d 100644\n--- a/builtin/rebase--helper.c\n+++ b/builtin/rebase--helper.c\n@@ -13,12 +13,12 @@ static const char * const builtin_rebase_helper_usage[] = {\n int cmd_rebase__helper(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, write_edit_todo = 0;\n+\tunsigned flags = 0, keep_empty = 0, rebase_merges = 0;\n \tint abbreviate_commands = 0, rebase_cousins = -1;\n \tenum {\n \t\tCONTINUE = 1, ABORT, MAKE_SCRIPT, SHORTEN_OIDS, EXPAND_OIDS,\n \t\tCHECK_TODO_LIST, SKIP_UNNECESSARY_PICKS, REARRANGE_SQUASH,\n-\t\tADD_EXEC, APPEND_TODO_HELP\n+\t\tADD_EXEC, APPEND_TODO_HELP, EDIT_TODO\n \t} command = 0;\n \tstruct option options[] = {\n \t\tOPT_BOOL(0, \"ff\", &opts.allow_ff, N_(\"allow fast-forward\")),\n@@ -28,8 +28,6 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\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, \"write-edit-todo\", &write_edit_todo,\n-\t\t\t N_(\"append the edit-todo message to the todo-list\")),\n \t\tOPT_CMDMODE(0, \"continue\", &command, N_(\"continue rebase\"),\n \t\t\t\tCONTINUE),\n \t\tOPT_CMDMODE(0, \"abort\", &command, N_(\"abort rebase\"),\n@@ -50,6 +48,9 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\n \t\t\tN_(\"insert exec commands in todo list\"), ADD_EXEC),\n \t\tOPT_CMDMODE(0, \"append-todo-help\", &command,\n \t\t\t    N_(\"insert the help in the todo list\"), APPEND_TODO_HELP),\n+\t\tOPT_CMDMODE(0, \"edit-todo\", &command,\n+\t\t\t    N_(\"edit the todo list during an interactive rebase\"),\n+\t\t\t    EDIT_TODO),\n \t\tOPT_END()\n \t};\n \n@@ -90,6 +91,8 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\n \tif (command == ADD_EXEC && argc == 2)\n \t\treturn !!sequencer_add_exec_commands(argv[1]);\n \tif (command == APPEND_TODO_HELP && argc == 1)\n-\t\treturn !!append_todo_help(write_edit_todo, keep_empty);\n+\t\treturn !!append_todo_help(0, keep_empty);\n+\tif (command == EDIT_TODO && argc == 1)\n+\t\treturn !!edit_todo_list(flags);\n \tusage_with_options(builtin_rebase_helper_usage, options);\n }\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex 94c23a7af2..2defe607f4 100644\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -108,16 +108,7 @@ initiate_action () {\n \t\t     --continue\n \t\t;;\n \tedit-todo)\n-\t\tgit stripspace --strip-comments <\"$todo\" >\"$todo\".new\n-\t\tmv -f \"$todo\".new \"$todo\"\n-\t\tcollapse_todo_ids\n-\t\tgit rebase--helper --append-todo-help --write-edit-todo\n-\n-\t\tgit_sequence_editor \"$todo\" ||\n-\t\t\tdie \"$(gettext \"Could not execute editor\")\"\n-\t\texpand_todo_ids\n-\n-\t\texit\n+\t\texec git rebase--helper --edit-todo\n \t\t;;\n \tshow-current-patch)\n \t\texec git show REBASE_HEAD --\ndiff --git a/rebase-interactive.c b/rebase-interactive.c\nindex d7996bc8d9..3f9468fc69 100644\n--- a/rebase-interactive.c\n+++ b/rebase-interactive.c\n@@ -66,3 +66,30 @@ int append_todo_help(unsigned edit_todo, unsigned keep_empty)\n \n \treturn ret;\n }\n+\n+int edit_todo_list(unsigned flags)\n+{\n+\tstruct strbuf buf = STRBUF_INIT;\n+\tconst char *todo_file = rebase_path_todo();\n+\n+\tif (strbuf_read_file(&buf, todo_file, 0) < 0)\n+\t\treturn error_errno(_(\"could not read '%s'.\"), todo_file);\n+\n+\tstrbuf_stripspace(&buf, 1);\n+\tif (write_message(buf.buf, buf.len, todo_file, 0)) {\n+\t\tstrbuf_release(&buf);\n+\t\treturn -1;\n+\t}\n+\n+\tstrbuf_release(&buf);\n+\n+\ttransform_todos(flags | TODO_LIST_SHORTEN_IDS);\n+\tappend_todo_help(1, 0);\n+\n+\tif (launch_sequence_editor(todo_file, NULL, NULL))\n+\t\treturn -1;\n+\n+\ttransform_todos(flags & ~(TODO_LIST_SHORTEN_IDS));\n+\n+\treturn 0;\n+}\ndiff --git a/rebase-interactive.h b/rebase-interactive.h\nindex 47372624e0..155219e742 100644\n--- a/rebase-interactive.h\n+++ b/rebase-interactive.h\n@@ -2,5 +2,6 @@\n #define REBASE_INTERACTIVE_H\n \n int append_todo_help(unsigned edit_todo, unsigned keep_empty);\n+int edit_todo_list(unsigned flags);\n \n #endif\n-- \n2.18.0\n\n"},{"id":"355099","messageId":"20180810165147.4779-6-alban.gruin@gmail.com","threadId":"48814","inReplyTo":"20180810165147.4779-1-alban.gruin@gmail.com","subject":"[GSoC][PATCH v6 05/20] sequencer: add a new function to silence a command, except if it fails","fromName":"Alban Gruin","fromEmail":"alban.gruin@gmail.com","sentAt":"2018-08-10T16:51:32Z","receivedAt":"2018-08-10T16:52:25Z","isPatch":true,"sender":{"key":"alban.gruin@gmail.com","avatar":"https://avatars.githubusercontent.com/u/6310153?v=4"},"body":"This adds a new function, run_command_silent_on_success(), to\nredirect the stdout and stderr of a command to a strbuf, and then to run\nthat command. This strbuf is printed only if the command fails. It is\nfunctionnaly similar to output() from git-rebase.sh.\n\nrun_git_commit() is then refactored to use of\nrun_command_silent_on_success().\n\nSigned-off-by: Alban Gruin <alban.gruin@gmail.com>\n---\nNo changes since v5.\n\n sequencer.c | 51 +++++++++++++++++++++++++--------------------------\n 1 file changed, 25 insertions(+), 26 deletions(-)\n\ndiff --git a/sequencer.c b/sequencer.c\nindex dd1b060863..eaa1aa7deb 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -769,6 +769,23 @@ N_(\"you have staged changes in your working tree\\n\"\n #define VERIFY_MSG  (1<<4)\n #define CREATE_ROOT_COMMIT (1<<5)\n \n+static int run_command_silent_on_success(struct child_process *cmd)\n+{\n+\tstruct strbuf buf = STRBUF_INIT;\n+\tint rc;\n+\n+\tcmd->stdout_to_stderr = 1;\n+\trc = pipe_command(cmd,\n+\t\t\t  NULL, 0,\n+\t\t\t  NULL, 0,\n+\t\t\t  &buf, 0);\n+\n+\tif (rc)\n+\t\tfputs(buf.buf, stderr);\n+\tstrbuf_release(&buf);\n+\treturn rc;\n+}\n+\n /*\n  * If we are cherry-pick, and if the merge did not result in\n  * hand-editing, we will hit this commit and inherit the original\n@@ -823,18 +840,11 @@ static int run_git_commit(const char *defmsg, struct replay_opts *opts,\n \n \tcmd.git_cmd = 1;\n \n-\tif (is_rebase_i(opts)) {\n-\t\tif (!(flags & EDIT_MSG)) {\n-\t\t\tcmd.stdout_to_stderr = 1;\n-\t\t\tcmd.err = -1;\n-\t\t}\n-\n-\t\tif (read_env_script(&cmd.env_array)) {\n-\t\t\tconst char *gpg_opt = gpg_sign_opt_quoted(opts);\n+\tif (is_rebase_i(opts) && read_env_script(&cmd.env_array)) {\n+\t\tconst char *gpg_opt = gpg_sign_opt_quoted(opts);\n \n-\t\t\treturn error(_(staged_changes_advice),\n-\t\t\t\t     gpg_opt, gpg_opt);\n-\t\t}\n+\t\treturn error(_(staged_changes_advice),\n+\t\t\t     gpg_opt, gpg_opt);\n \t}\n \n \targv_array_push(&cmd.args, \"commit\");\n@@ -864,21 +874,10 @@ static int run_git_commit(const char *defmsg, struct replay_opts *opts,\n \tif (opts->allow_empty_message)\n \t\targv_array_push(&cmd.args, \"--allow-empty-message\");\n \n-\tif (cmd.err == -1) {\n-\t\t/* hide stderr on success */\n-\t\tstruct strbuf buf = STRBUF_INIT;\n-\t\tint rc = pipe_command(&cmd,\n-\t\t\t\t      NULL, 0,\n-\t\t\t\t      /* stdout is already redirected */\n-\t\t\t\t      NULL, 0,\n-\t\t\t\t      &buf, 0);\n-\t\tif (rc)\n-\t\t\tfputs(buf.buf, stderr);\n-\t\tstrbuf_release(&buf);\n-\t\treturn rc;\n-\t}\n-\n-\treturn run_command(&cmd);\n+\tif (is_rebase_i(opts) && !(flags & EDIT_MSG))\n+\t\treturn run_command_silent_on_success(&cmd);\n+\telse\n+\t\treturn run_command(&cmd);\n }\n \n static int rest_is_empty(const struct strbuf *sb, int start)\n-- \n2.18.0\n\n"},{"id":"355100","messageId":"20180810165147.4779-7-alban.gruin@gmail.com","threadId":"48814","inReplyTo":"20180810165147.4779-1-alban.gruin@gmail.com","subject":"[GSoC][PATCH v6 06/20] rebase -i: rewrite setup_reflog_action() in C","fromName":"Alban Gruin","fromEmail":"alban.gruin@gmail.com","sentAt":"2018-08-10T16:51:33Z","receivedAt":"2018-08-10T16:52:27Z","isPatch":true,"sender":{"key":"alban.gruin@gmail.com","avatar":"https://avatars.githubusercontent.com/u/6310153?v=4"},"body":"This rewrites (the misnamed) setup_reflog_action() from shell to C. The\nnew version is called prepare_branch_to_be_rebased().\n\nA new command is added to rebase--helper.c, “checkout-base”, as well as\na new flag, “verbose”, to avoid silencing the output of the checkout\noperation called by checkout_base_commit().\n\nThe function `run_git_checkout()` will also be used in the next commit,\ntherefore its code is not part of `checkout_base_commit()`.\n\nThe shell version is then stripped in favour of a call to the helper.\n\nAs $GIT_REFLOG_ACTION is no longer set at the first call of\ncheckout_onto(), a call to comment_for_reflog() is added at the\nbeginning of this function.\n\nSigned-off-by: Alban Gruin <alban.gruin@gmail.com>\n---\nNo changes since v5.\n\n builtin/rebase--helper.c   |  7 ++++++-\n git-rebase--interactive.sh | 16 ++--------------\n sequencer.c                | 30 ++++++++++++++++++++++++++++++\n sequencer.h                |  2 ++\n 4 files changed, 40 insertions(+), 15 deletions(-)\n\ndiff --git a/builtin/rebase--helper.c b/builtin/rebase--helper.c\nindex 731a64971d..0e76dadba6 100644\n--- a/builtin/rebase--helper.c\n+++ b/builtin/rebase--helper.c\n@@ -18,7 +18,7 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\n \tenum {\n \t\tCONTINUE = 1, ABORT, MAKE_SCRIPT, SHORTEN_OIDS, EXPAND_OIDS,\n \t\tCHECK_TODO_LIST, SKIP_UNNECESSARY_PICKS, REARRANGE_SQUASH,\n-\t\tADD_EXEC, APPEND_TODO_HELP, EDIT_TODO\n+\t\tADD_EXEC, APPEND_TODO_HELP, EDIT_TODO, PREPARE_BRANCH\n \t} command = 0;\n \tstruct option options[] = {\n \t\tOPT_BOOL(0, \"ff\", &opts.allow_ff, N_(\"allow fast-forward\")),\n@@ -28,6 +28,7 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\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__VERBOSE(&opts.verbose, N_(\"be verbose\")),\n \t\tOPT_CMDMODE(0, \"continue\", &command, N_(\"continue rebase\"),\n \t\t\t\tCONTINUE),\n \t\tOPT_CMDMODE(0, \"abort\", &command, N_(\"abort rebase\"),\n@@ -51,6 +52,8 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\n \t\tOPT_CMDMODE(0, \"edit-todo\", &command,\n \t\t\t    N_(\"edit the todo list during an interactive rebase\"),\n \t\t\t    EDIT_TODO),\n+\t\tOPT_CMDMODE(0, \"prepare-branch\", &command,\n+\t\t\t    N_(\"prepare the branch to be rebased\"), PREPARE_BRANCH),\n \t\tOPT_END()\n \t};\n \n@@ -94,5 +97,7 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\n \t\treturn !!append_todo_help(0, keep_empty);\n \tif (command == EDIT_TODO && argc == 1)\n \t\treturn !!edit_todo_list(flags);\n+\tif (command == PREPARE_BRANCH && argc == 2)\n+\t\treturn !!prepare_branch_to_be_rebased(&opts, argv[1]);\n \tusage_with_options(builtin_rebase_helper_usage, options);\n }\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex 2defe607f4..77e972bb6c 100644\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -72,6 +72,7 @@ collapse_todo_ids() {\n \n # Switch to the branch in $into and notify it in the reflog\n checkout_onto () {\n+\tcomment_for_reflog start\n \tGIT_REFLOG_ACTION=\"$GIT_REFLOG_ACTION: checkout $onto_name\"\n \toutput git checkout $onto || die_abort \"$(gettext \"could not detach HEAD\")\"\n \tgit update-ref ORIG_HEAD $orig_head\n@@ -119,19 +120,6 @@ initiate_action () {\n \tesac\n }\n \n-setup_reflog_action () {\n-\tcomment_for_reflog start\n-\n-\tif test ! -z \"$switch_to\"\n-\tthen\n-\t\tGIT_REFLOG_ACTION=\"$GIT_REFLOG_ACTION: checkout $switch_to\"\n-\t\toutput git checkout \"$switch_to\" -- ||\n-\t\t\tdie \"$(eval_gettext \"Could not checkout \\$switch_to\")\"\n-\n-\t\tcomment_for_reflog start\n-\tfi\n-}\n-\n init_basic_state () {\n \torig_head=$(git rev-parse --verify HEAD) || die \"$(gettext \"No HEAD?\")\"\n \tmkdir -p \"$state_dir\" || die \"$(eval_gettext \"Could not create temporary \\$state_dir\")\"\n@@ -211,7 +199,7 @@ git_rebase__interactive () {\n \t\treturn 0\n \tfi\n \n-\tsetup_reflog_action\n+\tgit rebase--helper --prepare-branch \"$switch_to\" ${verbose:+--verbose}\n \tinit_basic_state\n \n \tinit_revisions_and_shortrevisions\ndiff --git a/sequencer.c b/sequencer.c\nindex eaa1aa7deb..c1cfa2ee5c 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -3141,6 +3141,36 @@ 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+{\n+\tstruct child_process cmd = CHILD_PROCESS_INIT;\n+\n+\tcmd.git_cmd = 1;\n+\n+\targv_array_push(&cmd.args, \"checkout\");\n+\targv_array_push(&cmd.args, 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+\telse\n+\t\treturn run_command_silent_on_success(&cmd);\n+}\n+\n+int prepare_branch_to_be_rebased(struct replay_opts *opts, 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\t\treturn error(_(\"could not checkout %s\"), commit);\n+\t}\n+\n+\treturn 0;\n+}\n+\n static const char rescheduled_advice[] =\n N_(\"Could not execute the todo command\\n\"\n \"\\n\"\ndiff --git a/sequencer.h b/sequencer.h\nindex 792e448b67..f619b02a13 100644\n--- a/sequencer.h\n+++ b/sequencer.h\n@@ -109,6 +109,8 @@ int update_head_with_reflog(const struct commit *old_head,\n void commit_post_rewrite(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+\n #define SUMMARY_INITIAL_COMMIT   (1 << 0)\n #define SUMMARY_SHOW_AUTHOR_DATE (1 << 1)\n void print_commit_summary(const char *prefix, const struct object_id *oid,\n-- \n2.18.0\n\n"},{"id":"355101","messageId":"20180810165147.4779-8-alban.gruin@gmail.com","threadId":"48814","inReplyTo":"20180810165147.4779-1-alban.gruin@gmail.com","subject":"[GSoC][PATCH v6 07/20] rebase -i: rewrite checkout_onto() in C","fromName":"Alban Gruin","fromEmail":"alban.gruin@gmail.com","sentAt":"2018-08-10T16:51:34Z","receivedAt":"2018-08-10T16:52:28Z","isPatch":true,"sender":{"key":"alban.gruin@gmail.com","avatar":"https://avatars.githubusercontent.com/u/6310153?v=4"},"body":"This rewrites checkout_onto() from shell to C.\n\nA new command (“checkout-onto”) is added to rebase--helper.c. The shell\nversion is then stripped.\n\nSigned-off-by: Alban Gruin <alban.gruin@gmail.com>\n---\nNo changes since v5.\n\n builtin/rebase--helper.c   |  7 ++++++-\n git-rebase--interactive.sh | 25 ++++---------------------\n sequencer.c                | 19 +++++++++++++++++++\n sequencer.h                |  3 +++\n 4 files changed, 32 insertions(+), 22 deletions(-)\n\ndiff --git a/builtin/rebase--helper.c b/builtin/rebase--helper.c\nindex 0e76dadba6..7d9426d23c 100644\n--- a/builtin/rebase--helper.c\n+++ b/builtin/rebase--helper.c\n@@ -18,7 +18,8 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\n \tenum {\n \t\tCONTINUE = 1, ABORT, MAKE_SCRIPT, SHORTEN_OIDS, EXPAND_OIDS,\n \t\tCHECK_TODO_LIST, SKIP_UNNECESSARY_PICKS, REARRANGE_SQUASH,\n-\t\tADD_EXEC, APPEND_TODO_HELP, EDIT_TODO, PREPARE_BRANCH\n+\t\tADD_EXEC, APPEND_TODO_HELP, EDIT_TODO, PREPARE_BRANCH,\n+\t\tCHECKOUT_ONTO\n \t} command = 0;\n \tstruct option options[] = {\n \t\tOPT_BOOL(0, \"ff\", &opts.allow_ff, N_(\"allow fast-forward\")),\n@@ -54,6 +55,8 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\n \t\t\t    EDIT_TODO),\n \t\tOPT_CMDMODE(0, \"prepare-branch\", &command,\n \t\t\t    N_(\"prepare the branch to be rebased\"), PREPARE_BRANCH),\n+\t\tOPT_CMDMODE(0, \"checkout-onto\", &command,\n+\t\t\t    N_(\"checkout a commit\"), CHECKOUT_ONTO),\n \t\tOPT_END()\n \t};\n \n@@ -99,5 +102,7 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\n \t\treturn !!edit_todo_list(flags);\n \tif (command == PREPARE_BRANCH && argc == 2)\n \t\treturn !!prepare_branch_to_be_rebased(&opts, argv[1]);\n+\tif (command == CHECKOUT_ONTO && argc == 4)\n+\t\treturn !!checkout_onto(&opts, argv[1], argv[2], argv[3]);\n \tusage_with_options(builtin_rebase_helper_usage, options);\n }\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex 77e972bb6c..b68f108f28 100644\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -28,17 +28,6 @@ case \"$comment_char\" in\n \t;;\n esac\n \n-orig_reflog_action=\"$GIT_REFLOG_ACTION\"\n-\n-comment_for_reflog () {\n-\tcase \"$orig_reflog_action\" in\n-\t''|rebase*)\n-\t\tGIT_REFLOG_ACTION=\"rebase -i ($1)\"\n-\t\texport GIT_REFLOG_ACTION\n-\t\t;;\n-\tesac\n-}\n-\n die_abort () {\n \tapply_autostash\n \trm -rf \"$state_dir\"\n@@ -70,14 +59,6 @@ collapse_todo_ids() {\n \tgit rebase--helper --shorten-ids\n }\n \n-# Switch to the branch in $into and notify it in the reflog\n-checkout_onto () {\n-\tcomment_for_reflog start\n-\tGIT_REFLOG_ACTION=\"$GIT_REFLOG_ACTION: checkout $onto_name\"\n-\toutput git checkout $onto || die_abort \"$(gettext \"could not detach HEAD\")\"\n-\tgit update-ref ORIG_HEAD $orig_head\n-}\n-\n get_missing_commit_check_level () {\n \tcheck_level=$(git config --get rebase.missingCommitsCheck)\n \tcheck_level=${check_level:-ignore}\n@@ -176,7 +157,8 @@ EOF\n \n \tgit rebase--helper --check-todo-list || {\n \t\tret=$?\n-\t\tcheckout_onto\n+\t\tgit rebase--helper --checkout-onto \"$onto_name\" \"$onto\" \\\n+\t\t    \"$orig_head\" ${verbose:+--verbose}\n \t\texit $ret\n \t}\n \n@@ -186,7 +168,8 @@ EOF\n \tonto=\"$(git rebase--helper --skip-unnecessary-picks)\" ||\n \tdie \"Could not skip unnecessary pick commands\"\n \n-\tcheckout_onto\n+\tgit rebase--helper --checkout-onto \"$onto_name\" \"$onto\" \"$orig_head\" \\\n+\t    ${verbose:+--verbose}\n \trequire_clean_work_tree \"rebase\"\n \texec git rebase--helper ${force_rebase:+--no-ff} $allow_empty_message \\\n \t     --continue\ndiff --git a/sequencer.c b/sequencer.c\nindex c1cfa2ee5c..48447d7f0e 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -3171,6 +3171,25 @@ int prepare_branch_to_be_rebased(struct replay_opts *opts, const char *commit)\n \treturn 0;\n }\n \n+int checkout_onto(struct replay_opts *opts,\n+\t\t  const char *onto_name, const char *onto,\n+\t\t  const char *orig_head)\n+{\n+\tstruct object_id oid;\n+\tconst char *action = reflog_message(opts, \"start\", \"checkout %s\", onto_name);\n+\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+\t\tapply_autostash(opts);\n+\t\tsequencer_remove_state(opts);\n+\t\treturn error(_(\"could not detach HEAD\"));\n+\t}\n+\n+\treturn update_ref(NULL, \"ORIG_HEAD\", &oid, NULL, 0, UPDATE_REFS_MSG_ON_ERR);\n+}\n+\n static const char rescheduled_advice[] =\n N_(\"Could not execute the todo command\\n\"\n \"\\n\"\ndiff --git a/sequencer.h b/sequencer.h\nindex f619b02a13..d2b54adf45 100644\n--- a/sequencer.h\n+++ b/sequencer.h\n@@ -110,6 +110,9 @@ void commit_post_rewrite(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 checkout_onto(struct replay_opts *opts,\n+\t\t  const char *onto_name, const char *onto,\n+\t\t  const char *orig_head);\n \n #define SUMMARY_INITIAL_COMMIT   (1 << 0)\n #define SUMMARY_SHOW_AUTHOR_DATE (1 << 1)\n-- \n2.18.0\n\n"},{"id":"355102","messageId":"20180810165147.4779-9-alban.gruin@gmail.com","threadId":"48814","inReplyTo":"20180810165147.4779-1-alban.gruin@gmail.com","subject":"[GSoC][PATCH v6 08/20] sequencer: refactor append_todo_help() to write its message to a buffer","fromName":"Alban Gruin","fromEmail":"alban.gruin@gmail.com","sentAt":"2018-08-10T16:51:35Z","receivedAt":"2018-08-10T16:52:31Z","isPatch":true,"sender":{"key":"alban.gruin@gmail.com","avatar":"https://avatars.githubusercontent.com/u/6310153?v=4"},"body":"This refactors append_todo_help() to write its message to a buffer\ninstead of the todo-list.  This is needed for the rewrite of\ncomplete_action(), which will come after the next commit.\n\nAs rebase--helper still needs the file manipulation part of\nappend_todo_help(), it is extracted to a temporary function,\nappend_todo_help_to_file().  This function will go away after the\nrewrite of complete_action().\n\nSigned-off-by: Alban Gruin <alban.gruin@gmail.com>\n---\n builtin/rebase--helper.c |  2 +-\n rebase-interactive.c     | 43 ++++++++++++++++++++++++++++------------\n rebase-interactive.h     |  4 +++-\n 3 files changed, 34 insertions(+), 15 deletions(-)\n\ndiff --git a/builtin/rebase--helper.c b/builtin/rebase--helper.c\nindex 7d9426d23c..313092c465 100644\n--- a/builtin/rebase--helper.c\n+++ b/builtin/rebase--helper.c\n@@ -97,7 +97,7 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\n \tif (command == ADD_EXEC && argc == 2)\n \t\treturn !!sequencer_add_exec_commands(argv[1]);\n \tif (command == APPEND_TODO_HELP && argc == 1)\n-\t\treturn !!append_todo_help(0, keep_empty);\n+\t\treturn !!append_todo_help_to_file(0, keep_empty);\n \tif (command == EDIT_TODO && argc == 1)\n \t\treturn !!edit_todo_list(flags);\n \tif (command == PREPARE_BRANCH && argc == 2)\ndiff --git a/rebase-interactive.c b/rebase-interactive.c\nindex 3f9468fc69..4a9a10eff4 100644\n--- a/rebase-interactive.c\n+++ b/rebase-interactive.c\n@@ -4,11 +4,9 @@\n #include \"sequencer.h\"\n #include \"strbuf.h\"\n \n-int append_todo_help(unsigned edit_todo, unsigned keep_empty)\n+void append_todo_help(unsigned edit_todo, unsigned keep_empty,\n+\t\t      struct strbuf *buf)\n {\n-\tstruct strbuf buf = STRBUF_INIT;\n-\tFILE *todo;\n-\tint ret;\n \tconst char *msg = _(\"\\nCommands:\\n\"\n \"p, pick <commit> = use commit\\n\"\n \"r, reword <commit> = use commit, but edit the commit message\\n\"\n@@ -26,11 +24,7 @@ int append_todo_help(unsigned edit_todo, unsigned keep_empty)\n \"\\n\"\n \"These lines can be re-ordered; they are executed from top to bottom.\\n\");\n \n-\ttodo = fopen_or_warn(rebase_path_todo(), \"a\");\n-\tif (!todo)\n-\t\treturn 1;\n-\n-\tstrbuf_add_commented_lines(&buf, msg, strlen(msg));\n+\tstrbuf_add_commented_lines(buf, msg, strlen(msg));\n \n \tif (get_missing_commit_check_level() == MISSING_COMMIT_CHECK_ERROR)\n \t\tmsg = _(\"\\nDo not remove any line. Use 'drop' \"\n@@ -39,7 +33,7 @@ int append_todo_help(unsigned edit_todo, unsigned keep_empty)\n \t\tmsg = _(\"\\nIf you remove a line here \"\n \t\t\t \"THAT COMMIT WILL BE LOST.\\n\");\n \n-\tstrbuf_add_commented_lines(&buf, msg, strlen(msg));\n+\tstrbuf_add_commented_lines(buf, msg, strlen(msg));\n \n \tif (edit_todo)\n \t\tmsg = _(\"\\nYou are editing the todo file \"\n@@ -50,12 +44,25 @@ int append_todo_help(unsigned edit_todo, unsigned keep_empty)\n \t\tmsg = _(\"\\nHowever, if you remove everything, \"\n \t\t\t\"the rebase will be aborted.\\n\\n\");\n \n-\tstrbuf_add_commented_lines(&buf, msg, strlen(msg));\n+\tstrbuf_add_commented_lines(buf, msg, strlen(msg));\n \n \tif (!keep_empty) {\n \t\tmsg = _(\"Note that empty commits are commented out\");\n-\t\tstrbuf_add_commented_lines(&buf, msg, strlen(msg));\n+\t\tstrbuf_add_commented_lines(buf, msg, strlen(msg));\n \t}\n+}\n+\n+int append_todo_help_to_file(unsigned edit_todo, unsigned keep_empty)\n+{\n+\tstruct strbuf buf = STRBUF_INIT;\n+\tFILE *todo;\n+\tint ret;\n+\n+\ttodo = fopen_or_warn(rebase_path_todo(), \"a\");\n+\tif (!todo)\n+\t\treturn -1;\n+\n+\tappend_todo_help(edit_todo, keep_empty, &buf);\n \n \tret = fputs(buf.buf, todo);\n \tif (ret < 0)\n@@ -84,7 +91,17 @@ int edit_todo_list(unsigned flags)\n \tstrbuf_release(&buf);\n \n \ttransform_todos(flags | TODO_LIST_SHORTEN_IDS);\n-\tappend_todo_help(1, 0);\n+\n+\tif (strbuf_read_file(&buf, todo_file, 0) < 0)\n+\t\treturn error_errno(_(\"could not read '%s'.\"), todo_file);\n+\n+\tappend_todo_help(1, 0, &buf);\n+\tif (write_message(buf.buf, buf.len, todo_file, 0)) {\n+\t\tstrbuf_release(&buf);\n+\t\treturn -1;\n+\t}\n+\n+\tstrbuf_release(&buf);\n \n \tif (launch_sequence_editor(todo_file, NULL, NULL))\n \t\treturn -1;\ndiff --git a/rebase-interactive.h b/rebase-interactive.h\nindex 155219e742..d33f3176b7 100644\n--- a/rebase-interactive.h\n+++ b/rebase-interactive.h\n@@ -1,7 +1,9 @@\n #ifndef REBASE_INTERACTIVE_H\n #define REBASE_INTERACTIVE_H\n \n-int append_todo_help(unsigned edit_todo, unsigned keep_empty);\n+void append_todo_help(unsigned edit_todo, unsigned keep_empty,\n+\t\t      struct strbuf *buf);\n+int append_todo_help_to_file(unsigned edit_todo, unsigned keep_empty);\n int edit_todo_list(unsigned flags);\n \n #endif\n-- \n2.18.0\n\n"},{"id":"355103","messageId":"20180810165147.4779-11-alban.gruin@gmail.com","threadId":"48814","inReplyTo":"20180810165147.4779-1-alban.gruin@gmail.com","subject":"[GSoC][PATCH v6 10/20] t3404: todo list with commented-out commands only aborts","fromName":"Alban Gruin","fromEmail":"alban.gruin@gmail.com","sentAt":"2018-08-10T16:51:37Z","receivedAt":"2018-08-10T16:52:33Z","isPatch":true,"sender":{"key":"alban.gruin@gmail.com","avatar":"https://avatars.githubusercontent.com/u/6310153?v=4"},"body":"If the todo list generated by `--make-script` is empty,\ncomplete_action() writes a noop, but if it has only commented-out\ncommands, it will abort with the message \"Nothing to do\", and does not\nlaunch the editor.  This adds a new test to ensure that\ncomplete_action() behaves this way.\n\nSigned-off-by: Alban Gruin <alban.gruin@gmail.com>\n---\nNo changes since v5.\n\n t/t3404-rebase-interactive.sh | 10 ++++++++++\n 1 file changed, 10 insertions(+)\n\ndiff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh\nindex 01616901bd..496d88d7d6 100755\n--- a/t/t3404-rebase-interactive.sh\n+++ b/t/t3404-rebase-interactive.sh\n@@ -75,6 +75,16 @@ test_expect_success 'rebase --keep-empty' '\n \ttest_line_count = 6 actual\n '\n \n+cat > expect <<EOF\n+Nothing to do\n+EOF\n+\n+test_expect_success 'rebase -i with empty HEAD' '\n+\tset_fake_editor &&\n+\ttest_must_fail env FAKE_LINES=\"1 exec_true\" git rebase -i HEAD^ >actual 2>&1 &&\n+\ttest_i18ncmp expect actual\n+'\n+\n test_expect_success 'rebase -i with the exec command' '\n \tgit checkout master &&\n \t(\n-- \n2.18.0\n\n"},{"id":"355104","messageId":"20180810165147.4779-10-alban.gruin@gmail.com","threadId":"48814","inReplyTo":"20180810165147.4779-1-alban.gruin@gmail.com","subject":"[GSoC][PATCH v6 09/20] sequencer: change the way skip_unnecessary_picks() returns its result","fromName":"Alban Gruin","fromEmail":"alban.gruin@gmail.com","sentAt":"2018-08-10T16:51:36Z","receivedAt":"2018-08-10T16:52:33Z","isPatch":true,"sender":{"key":"alban.gruin@gmail.com","avatar":"https://avatars.githubusercontent.com/u/6310153?v=4"},"body":"Instead of skip_unnecessary_picks() printing its result to stdout, it\nreturns it into a struct object_id, as the rewrite of complete_action()\n(to come in the next commit) will need it.\n\nrebase--helper then is modified to fit this change.\n\nSigned-off-by: Alban Gruin <alban.gruin@gmail.com>\n---\nNo changes since v5.\n\n builtin/rebase--helper.c | 10 ++++++++--\n sequencer.c              | 13 ++++++-------\n sequencer.h              |  2 +-\n 3 files changed, 15 insertions(+), 10 deletions(-)\n\ndiff --git a/builtin/rebase--helper.c b/builtin/rebase--helper.c\nindex 313092c465..bed3dd2b95 100644\n--- a/builtin/rebase--helper.c\n+++ b/builtin/rebase--helper.c\n@@ -90,8 +90,14 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\n \t\treturn !!transform_todos(flags);\n \tif (command == CHECK_TODO_LIST && argc == 1)\n \t\treturn !!check_todo_list();\n-\tif (command == SKIP_UNNECESSARY_PICKS && argc == 1)\n-\t\treturn !!skip_unnecessary_picks();\n+\tif (command == SKIP_UNNECESSARY_PICKS && argc == 1) {\n+\t\tstruct object_id oid;\n+\t\tint ret = skip_unnecessary_picks(&oid);\n+\n+\t\tif (!ret)\n+\t\t\tputs(oid_to_hex(&oid));\n+\t\treturn !!ret;\n+\t}\n \tif (command == REARRANGE_SQUASH && argc == 1)\n \t\treturn !!rearrange_squash();\n \tif (command == ADD_EXEC && argc == 2)\ndiff --git a/sequencer.c b/sequencer.c\nindex 48447d7f0e..a56a781539 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -4420,17 +4420,17 @@ static int rewrite_file(const char *path, const char *buf, size_t len)\n }\n \n /* skip picking commits whose parents are unchanged */\n-int skip_unnecessary_picks(void)\n+int skip_unnecessary_picks(struct object_id *output_oid)\n {\n \tconst char *todo_file = rebase_path_todo();\n \tstruct strbuf buf = STRBUF_INIT;\n \tstruct todo_list todo_list = TODO_LIST_INIT;\n-\tstruct object_id onto_oid, *oid = &onto_oid, *parent_oid;\n+\tstruct object_id *parent_oid;\n \tint fd, i;\n \n \tif (!read_oneliner(&buf, rebase_path_onto(), 0))\n \t\treturn error(_(\"could not read 'onto'\"));\n-\tif (get_oid(buf.buf, &onto_oid)) {\n+\tif (get_oid(buf.buf, output_oid)) {\n \t\tstrbuf_release(&buf);\n \t\treturn error(_(\"need a HEAD to fixup\"));\n \t}\n@@ -4460,9 +4460,9 @@ int skip_unnecessary_picks(void)\n \t\tif (item->commit->parents->next)\n \t\t\tbreak; /* merge commit */\n \t\tparent_oid = &item->commit->parents->item->object.oid;\n-\t\tif (hashcmp(parent_oid->hash, oid->hash))\n+\t\tif (hashcmp(parent_oid->hash, output_oid->hash))\n \t\t\tbreak;\n-\t\toid = &item->commit->object.oid;\n+\t\toidcpy(output_oid, &item->commit->object.oid);\n \t}\n \tif (i > 0) {\n \t\tint offset = get_item_line_offset(&todo_list, i);\n@@ -4491,11 +4491,10 @@ int skip_unnecessary_picks(void)\n \n \t\ttodo_list.current = i;\n \t\tif (is_fixup(peek_command(&todo_list, 0)))\n-\t\t\trecord_in_rewritten(oid, peek_command(&todo_list, 0));\n+\t\t\trecord_in_rewritten(output_oid, peek_command(&todo_list, 0));\n \t}\n \n \ttodo_list_release(&todo_list);\n-\tprintf(\"%s\\n\", oid_to_hex(oid));\n \n \treturn 0;\n }\ndiff --git a/sequencer.h b/sequencer.h\nindex d2b54adf45..fcbcd246c2 100644\n--- a/sequencer.h\n+++ b/sequencer.h\n@@ -91,7 +91,7 @@ int sequencer_add_exec_commands(const char *command);\n int transform_todos(unsigned flags);\n enum missing_commit_check_level get_missing_commit_check_level(void);\n int check_todo_list(void);\n-int skip_unnecessary_picks(void);\n+int skip_unnecessary_picks(struct object_id *output_oid);\n int rearrange_squash(void);\n \n extern const char sign_off_header[];\n-- \n2.18.0\n\n"},{"id":"355105","messageId":"20180810165147.4779-12-alban.gruin@gmail.com","threadId":"48814","inReplyTo":"20180810165147.4779-1-alban.gruin@gmail.com","subject":"[GSoC][PATCH v6 11/20] rebase -i: rewrite complete_action() in C","fromName":"Alban Gruin","fromEmail":"alban.gruin@gmail.com","sentAt":"2018-08-10T16:51:38Z","receivedAt":"2018-08-10T16:52:36Z","isPatch":true,"sender":{"key":"alban.gruin@gmail.com","avatar":"https://avatars.githubusercontent.com/u/6310153?v=4"},"body":"This rewrites complete_action() from shell to C.\n\nA new mode is added to rebase--helper (`--complete-action`), as well as\na new flag (`--autosquash`).\n\nFinally, complete_action() is stripped from git-rebase--interactive.sh.\n\nThe original complete_action() would return the code 2 when the todo\nlist contained no actions.  This was a special case for rebase -i and\n-p; git-rebase.sh would then apply the autostash, delete the state\ndirectory, and die with the message \"Nothing to do\".  This cleanup is\nrewritten in C instead of returning 2.  As rebase -i no longer returns\n2, the comment describing this behaviour in git-rebase.sh is updated to\nreflect this change.\n\nThe message \"Nothing to do\" is now printed with error(), and so becomes\n\"error: nothing to do\".  Some tests in t3404 check this value, so they\nare updated to fit this change.\n\nThe first check might seem useless as we write \"noop\" to the todo list\nif it is empty.  Actually, the todo list might contain commented\ncommands (ie. empty commits).  In this case, complete_action() won’t\nwrite \"noop\", and will abort without starting the editor.\n\nSigned-off-by: Alban Gruin <alban.gruin@gmail.com>\n---\n builtin/rebase--helper.c      |  12 +++-\n git-rebase--interactive.sh    |  53 ++----------------\n git-rebase.sh                 |   2 +-\n sequencer.c                   | 102 ++++++++++++++++++++++++++++++++++\n sequencer.h                   |   4 ++\n t/t3404-rebase-interactive.sh |   2 +-\n 6 files changed, 122 insertions(+), 53 deletions(-)\n\ndiff --git a/builtin/rebase--helper.c b/builtin/rebase--helper.c\nindex bed3dd2b95..01b3333958 100644\n--- a/builtin/rebase--helper.c\n+++ b/builtin/rebase--helper.c\n@@ -13,13 +13,13 @@ static const char * const builtin_rebase_helper_usage[] = {\n int cmd_rebase__helper(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;\n+\tunsigned flags = 0, keep_empty = 0, rebase_merges = 0, autosquash = 0;\n \tint abbreviate_commands = 0, rebase_cousins = -1;\n \tenum {\n \t\tCONTINUE = 1, ABORT, MAKE_SCRIPT, SHORTEN_OIDS, EXPAND_OIDS,\n \t\tCHECK_TODO_LIST, SKIP_UNNECESSARY_PICKS, REARRANGE_SQUASH,\n \t\tADD_EXEC, APPEND_TODO_HELP, EDIT_TODO, PREPARE_BRANCH,\n-\t\tCHECKOUT_ONTO\n+\t\tCHECKOUT_ONTO, COMPLETE_ACTION\n \t} command = 0;\n \tstruct option options[] = {\n \t\tOPT_BOOL(0, \"ff\", &opts.allow_ff, N_(\"allow fast-forward\")),\n@@ -29,6 +29,8 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\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__VERBOSE(&opts.verbose, N_(\"be verbose\")),\n \t\tOPT_CMDMODE(0, \"continue\", &command, N_(\"continue rebase\"),\n \t\t\t\tCONTINUE),\n@@ -57,6 +59,8 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\n \t\t\t    N_(\"prepare the branch to be rebased\"), PREPARE_BRANCH),\n \t\tOPT_CMDMODE(0, \"checkout-onto\", &command,\n \t\t\t    N_(\"checkout a commit\"), CHECKOUT_ONTO),\n+\t\tOPT_CMDMODE(0, \"complete-action\", &command,\n+\t\t\t    N_(\"complete the action\"), COMPLETE_ACTION),\n \t\tOPT_END()\n \t};\n \n@@ -110,5 +114,9 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\n \t\treturn !!prepare_branch_to_be_rebased(&opts, argv[1]);\n \tif (command == CHECKOUT_ONTO && argc == 4)\n \t\treturn !!checkout_onto(&opts, argv[1], argv[2], argv[3]);\n+\tif (command == COMPLETE_ACTION && argc == 6)\n+\t\treturn !!complete_action(&opts, flags, argv[1], argv[2], argv[3],\n+\t\t\t\t\t argv[4], argv[5], autosquash);\n+\n \tusage_with_options(builtin_rebase_helper_usage, options);\n }\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex b68f108f28..59dc4888a6 100644\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -127,54 +127,6 @@ init_revisions_and_shortrevisions () {\n \tfi\n }\n \n-complete_action() {\n-\ttest -s \"$todo\" || echo noop >> \"$todo\"\n-\ttest -z \"$autosquash\" || git rebase--helper --rearrange-squash || exit\n-\ttest -n \"$cmd\" && git rebase--helper --add-exec-commands \"$cmd\"\n-\n-\ttodocount=$(git stripspace --strip-comments <\"$todo\" | wc -l)\n-\ttodocount=${todocount##* }\n-\n-cat >>\"$todo\" <<EOF\n-\n-$comment_char $(eval_ngettext \\\n-\t\"Rebase \\$shortrevisions onto \\$shortonto (\\$todocount command)\" \\\n-\t\"Rebase \\$shortrevisions onto \\$shortonto (\\$todocount commands)\" \\\n-\t\"$todocount\")\n-EOF\n-\tgit rebase--helper --append-todo-help ${keep_empty:+--keep-empty}\n-\n-\thas_action \"$todo\" ||\n-\t\treturn 2\n-\n-\tcp \"$todo\" \"$todo\".backup\n-\tcollapse_todo_ids\n-\tgit_sequence_editor \"$todo\" ||\n-\t\tdie_abort \"$(gettext \"Could not execute editor\")\"\n-\n-\thas_action \"$todo\" ||\n-\t\treturn 2\n-\n-\tgit rebase--helper --check-todo-list || {\n-\t\tret=$?\n-\t\tgit rebase--helper --checkout-onto \"$onto_name\" \"$onto\" \\\n-\t\t    \"$orig_head\" ${verbose:+--verbose}\n-\t\texit $ret\n-\t}\n-\n-\texpand_todo_ids\n-\n-\ttest -n \"$force_rebase\" ||\n-\tonto=\"$(git rebase--helper --skip-unnecessary-picks)\" ||\n-\tdie \"Could not skip unnecessary pick commands\"\n-\n-\tgit rebase--helper --checkout-onto \"$onto_name\" \"$onto\" \"$orig_head\" \\\n-\t    ${verbose:+--verbose}\n-\trequire_clean_work_tree \"rebase\"\n-\texec git rebase--helper ${force_rebase:+--no-ff} $allow_empty_message \\\n-\t     --continue\n-}\n-\n git_rebase__interactive () {\n \tinitiate_action \"$action\"\n \tret=$?\n@@ -193,5 +145,8 @@ git_rebase__interactive () {\n \t\t$revisions ${restrict_revision+^$restrict_revision} >\"$todo\" ||\n \tdie \"$(gettext \"Could not generate todo list\")\"\n \n-\tcomplete_action\n+\texec git rebase--helper --complete-action \"$shortrevisions\" \"$onto_name\" \\\n+\t\t\"$shortonto\" \"$orig_head\" \"$cmd\" $allow_empty_message \\\n+\t\t${autosquash:+--autosquash} ${keep_empty:+--keep-empty} \\\n+\t\t${verbose:+--verbose} ${force_rebase:+--no-ff}\n }\ndiff --git a/git-rebase.sh b/git-rebase.sh\nindex 7973447645..51a6db7daa 100755\n--- a/git-rebase.sh\n+++ b/git-rebase.sh\n@@ -219,7 +219,7 @@ run_specific_rebase () {\n \tif test $ret -eq 0\n \tthen\n \t\tfinish_rebase\n-\telif test $ret -eq 2 # special exit status for rebase -i\n+\telif test $ret -eq 2 # special exit status for rebase -p\n \tthen\n \t\tapply_autostash &&\n \t\trm -rf \"$state_dir\" &&\ndiff --git a/sequencer.c b/sequencer.c\nindex a56a781539..ae1f44de2f 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -30,6 +30,7 @@\n #include \"oidset.h\"\n #include \"commit-slab.h\"\n #include \"alias.h\"\n+#include \"rebase-interactive.h\"\n \n #define GIT_REFLOG_ACTION \"GIT_REFLOG_ACTION\"\n \n@@ -53,6 +54,9 @@ static GIT_PATH_FUNC(rebase_path, \"rebase-merge\")\n  * file and written to the tail of 'done'.\n  */\n GIT_PATH_FUNC(rebase_path_todo, \"rebase-merge/git-rebase-todo\")\n+static GIT_PATH_FUNC(rebase_path_todo_backup,\n+\t\t     \"rebase-merge/git-rebase-todo.backup\")\n+\n /*\n  * The rebase command lines that have already been processed. A line\n  * is moved here when it is first handled, before any associated user\n@@ -4499,6 +4503,104 @@ int skip_unnecessary_picks(struct object_id *output_oid)\n \treturn 0;\n }\n \n+int complete_action(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, const char *cmd,\n+\t\t    unsigned autosquash)\n+{\n+\tconst char *shortonto, *todo_file = rebase_path_todo();\n+\tstruct todo_list todo_list = TODO_LIST_INIT;\n+\tstruct strbuf *buf = &(todo_list.buf);\n+\tstruct object_id oid;\n+\tstruct stat st;\n+\n+\tget_oid(onto, &oid);\n+\tshortonto = find_unique_abbrev(&oid, DEFAULT_ABBREV);\n+\n+\tif (!lstat(todo_file, &st) && st.st_size == 0 &&\n+\t    write_message(\"noop\\n\", 5, todo_file, 0))\n+\t\treturn error_errno(_(\"could not write '%s'\"), todo_file);\n+\n+\tif (autosquash && rearrange_squash())\n+\t\treturn -1;\n+\n+\tif (cmd && *cmd)\n+\t\tsequencer_add_exec_commands(cmd);\n+\n+\tif (strbuf_read_file(buf, todo_file, 0) < 0)\n+\t\treturn error_errno(_(\"could not read '%s'.\"), todo_file);\n+\n+\tif (parse_insn_buffer(buf->buf, &todo_list)) {\n+\t\ttodo_list_release(&todo_list);\n+\t\treturn error(_(\"unusable todo list: '%s'\"), todo_file);\n+\t}\n+\n+\tif (count_commands(&todo_list) == 0) {\n+\t\tapply_autostash(opts);\n+\t\tsequencer_remove_state(opts);\n+\t\ttodo_list_release(&todo_list);\n+\n+\t\treturn error(_(\"nothing to do\"));\n+\t}\n+\n+\tstrbuf_addch(buf, '\\n');\n+\tstrbuf_commented_addf(buf, Q_(\"Rebase %s onto %s (%d command)\",\n+\t\t\t\t      \"Rebase %s onto %s (%d commands)\",\n+\t\t\t\t      count_commands(&todo_list)),\n+\t\t\t      shortrevisions, shortonto, count_commands(&todo_list));\n+\tappend_todo_help(0, flags & TODO_LIST_KEEP_EMPTY, buf);\n+\n+\tif (write_message(buf->buf, buf->len, todo_file, 0)) {\n+\t\ttodo_list_release(&todo_list);\n+\t\treturn error_errno(_(\"could not write '%s'\"), todo_file);\n+\t}\n+\n+\tif (copy_file(rebase_path_todo_backup(), todo_file, 0666))\n+\t\treturn error(_(\"could not copy '%s' to '%s'.\"), todo_file,\n+\t\t\t     rebase_path_todo_backup());\n+\n+\tif (transform_todos(flags | TODO_LIST_SHORTEN_IDS))\n+\t\treturn error(_(\"could not transform the todo list\"));\n+\n+\tstrbuf_reset(buf);\n+\n+\tif (launch_sequence_editor(todo_file, buf, NULL)) {\n+\t\tapply_autostash(opts);\n+\t\tsequencer_remove_state(opts);\n+\t\ttodo_list_release(&todo_list);\n+\n+\t\treturn -1;\n+\t}\n+\n+\tstrbuf_stripspace(buf, 1);\n+\tif (buf->len == 0) {\n+\t\tapply_autostash(opts);\n+\t\tsequencer_remove_state(opts);\n+\t\ttodo_list_release(&todo_list);\n+\n+\t\treturn error(_(\"nothing to do\"));\n+\t}\n+\n+\ttodo_list_release(&todo_list);\n+\n+\tif (check_todo_list()) {\n+\t\tcheckout_onto(opts, onto_name, onto, orig_head);\n+\t\treturn -1;\n+\t}\n+\n+\tif (transform_todos(flags & ~(TODO_LIST_SHORTEN_IDS)))\n+\t\treturn error(_(\"could not transform the todo list\"));\n+\n+\tif (opts->allow_ff && skip_unnecessary_picks(&oid))\n+\t\treturn error(_(\"could not skip unnecessary pick commands\"));\n+\n+\tcheckout_onto(opts, onto_name, oid_to_hex(&oid), orig_head);\n+\tif (require_clean_work_tree(\"rebase\", \"\", 1, 1))\n+\t\treturn -1;\n+\n+\treturn sequencer_continue(opts);\n+}\n+\n struct subject2item_entry {\n \tstruct hashmap_entry entry;\n \tint i;\ndiff --git a/sequencer.h b/sequencer.h\nindex fcbcd246c2..d58766c6d7 100644\n--- a/sequencer.h\n+++ b/sequencer.h\n@@ -92,6 +92,10 @@ int transform_todos(unsigned flags);\n enum missing_commit_check_level get_missing_commit_check_level(void);\n int check_todo_list(void);\n int skip_unnecessary_picks(struct object_id *output_oid);\n+int complete_action(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, const char *cmd,\n+\t\t    unsigned autosquash);\n int rearrange_squash(void);\n \n extern const char sign_off_header[];\ndiff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh\nindex 496d88d7d6..12d3ed8396 100755\n--- a/t/t3404-rebase-interactive.sh\n+++ b/t/t3404-rebase-interactive.sh\n@@ -76,7 +76,7 @@ test_expect_success 'rebase --keep-empty' '\n '\n \n cat > expect <<EOF\n-Nothing to do\n+error: nothing to do\n EOF\n \n test_expect_success 'rebase -i with empty HEAD' '\n-- \n2.18.0\n\n"},{"id":"355106","messageId":"20180810165147.4779-13-alban.gruin@gmail.com","threadId":"48814","inReplyTo":"20180810165147.4779-1-alban.gruin@gmail.com","subject":"[GSoC][PATCH v6 12/20] rebase -i: remove unused modes and functions","fromName":"Alban Gruin","fromEmail":"alban.gruin@gmail.com","sentAt":"2018-08-10T16:51:39Z","receivedAt":"2018-08-10T16:52:37Z","isPatch":true,"sender":{"key":"alban.gruin@gmail.com","avatar":"https://avatars.githubusercontent.com/u/6310153?v=4"},"body":"This removes the modes `--skip-unnecessary-picks`, `--append-todo-help`,\nand `--checkout-onto` from rebase--helper.c, the functions of\ngit-rebase--interactive.sh that were rendered useless by the rewrite of\ncomplete_action(), and append_todo_help_to_file() from\nrebase-interactive.c.\n\nskip_unnecessary_picks() and checkout_onto() becomes static, as they are\nonly used inside of the sequencer.\n\nSigned-off-by: Alban Gruin <alban.gruin@gmail.com>\n---\nNo changes since v5.\n\n builtin/rebase--helper.c   | 23 ++----------------\n git-rebase--interactive.sh | 50 --------------------------------------\n rebase-interactive.c       | 22 -----------------\n rebase-interactive.h       |  1 -\n sequencer.c                |  8 +++---\n sequencer.h                |  4 ---\n 6 files changed, 6 insertions(+), 102 deletions(-)\n\ndiff --git a/builtin/rebase--helper.c b/builtin/rebase--helper.c\nindex 01b3333958..e1460136f5 100644\n--- a/builtin/rebase--helper.c\n+++ b/builtin/rebase--helper.c\n@@ -17,9 +17,8 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\n \tint abbreviate_commands = 0, rebase_cousins = -1;\n \tenum {\n \t\tCONTINUE = 1, ABORT, MAKE_SCRIPT, SHORTEN_OIDS, EXPAND_OIDS,\n-\t\tCHECK_TODO_LIST, SKIP_UNNECESSARY_PICKS, REARRANGE_SQUASH,\n-\t\tADD_EXEC, APPEND_TODO_HELP, EDIT_TODO, PREPARE_BRANCH,\n-\t\tCHECKOUT_ONTO, COMPLETE_ACTION\n+\t\tCHECK_TODO_LIST, REARRANGE_SQUASH, ADD_EXEC, EDIT_TODO, PREPARE_BRANCH,\n+\t\tCOMPLETE_ACTION\n \t} command = 0;\n \tstruct option options[] = {\n \t\tOPT_BOOL(0, \"ff\", &opts.allow_ff, N_(\"allow fast-forward\")),\n@@ -44,21 +43,15 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\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, \"skip-unnecessary-picks\", &command,\n-\t\t\tN_(\"skip unnecessary picks\"), SKIP_UNNECESSARY_PICKS),\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_CMDMODE(0, \"append-todo-help\", &command,\n-\t\t\t    N_(\"insert the help in the todo list\"), APPEND_TODO_HELP),\n \t\tOPT_CMDMODE(0, \"edit-todo\", &command,\n \t\t\t    N_(\"edit the todo list during an interactive rebase\"),\n \t\t\t    EDIT_TODO),\n \t\tOPT_CMDMODE(0, \"prepare-branch\", &command,\n \t\t\t    N_(\"prepare the branch to be rebased\"), PREPARE_BRANCH),\n-\t\tOPT_CMDMODE(0, \"checkout-onto\", &command,\n-\t\t\t    N_(\"checkout a commit\"), CHECKOUT_ONTO),\n \t\tOPT_CMDMODE(0, \"complete-action\", &command,\n \t\t\t    N_(\"complete the action\"), COMPLETE_ACTION),\n \t\tOPT_END()\n@@ -94,26 +87,14 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\n \t\treturn !!transform_todos(flags);\n \tif (command == CHECK_TODO_LIST && argc == 1)\n \t\treturn !!check_todo_list();\n-\tif (command == SKIP_UNNECESSARY_PICKS && argc == 1) {\n-\t\tstruct object_id oid;\n-\t\tint ret = skip_unnecessary_picks(&oid);\n-\n-\t\tif (!ret)\n-\t\t\tputs(oid_to_hex(&oid));\n-\t\treturn !!ret;\n-\t}\n \tif (command == REARRANGE_SQUASH && argc == 1)\n \t\treturn !!rearrange_squash();\n \tif (command == ADD_EXEC && argc == 2)\n \t\treturn !!sequencer_add_exec_commands(argv[1]);\n-\tif (command == APPEND_TODO_HELP && argc == 1)\n-\t\treturn !!append_todo_help_to_file(0, keep_empty);\n \tif (command == EDIT_TODO && argc == 1)\n \t\treturn !!edit_todo_list(flags);\n \tif (command == PREPARE_BRANCH && argc == 2)\n \t\treturn !!prepare_branch_to_be_rebased(&opts, argv[1]);\n-\tif (command == CHECKOUT_ONTO && argc == 4)\n-\t\treturn !!checkout_onto(&opts, argv[1], argv[2], argv[3]);\n \tif (command == COMPLETE_ACTION && argc == 6)\n \t\treturn !!complete_action(&opts, flags, argv[1], argv[2], argv[3],\n \t\t\t\t\t argv[4], argv[5], autosquash);\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex 59dc4888a6..0d66c0f8b8 100644\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -16,56 +16,6 @@ todo=\"$state_dir\"/git-rebase-todo\n GIT_CHERRY_PICK_HELP=\"$resolvemsg\"\n export GIT_CHERRY_PICK_HELP\n \n-comment_char=$(git config --get core.commentchar 2>/dev/null)\n-case \"$comment_char\" in\n-'' | auto)\n-\tcomment_char=\"#\"\n-\t;;\n-?)\n-\t;;\n-*)\n-\tcomment_char=$(echo \"$comment_char\" | cut -c1)\n-\t;;\n-esac\n-\n-die_abort () {\n-\tapply_autostash\n-\trm -rf \"$state_dir\"\n-\tdie \"$1\"\n-}\n-\n-has_action () {\n-\ttest -n \"$(git stripspace --strip-comments <\"$1\")\"\n-}\n-\n-git_sequence_editor () {\n-\tif test -z \"$GIT_SEQUENCE_EDITOR\"\n-\tthen\n-\t\tGIT_SEQUENCE_EDITOR=\"$(git config sequence.editor)\"\n-\t\tif [ -z \"$GIT_SEQUENCE_EDITOR\" ]\n-\t\tthen\n-\t\t\tGIT_SEQUENCE_EDITOR=\"$(git var GIT_EDITOR)\" || return $?\n-\t\tfi\n-\tfi\n-\n-\teval \"$GIT_SEQUENCE_EDITOR\" '\"$@\"'\n-}\n-\n-expand_todo_ids() {\n-\tgit rebase--helper --expand-ids\n-}\n-\n-collapse_todo_ids() {\n-\tgit rebase--helper --shorten-ids\n-}\n-\n-get_missing_commit_check_level () {\n-\tcheck_level=$(git config --get rebase.missingCommitsCheck)\n-\tcheck_level=${check_level:-ignore}\n-\t# Don't be case sensitive\n-\tprintf '%s' \"$check_level\" | tr 'A-Z' 'a-z'\n-}\n-\n # Initiate an action. If the cannot be any\n # further action it  may exec a command\n # or exit and not return.\ndiff --git a/rebase-interactive.c b/rebase-interactive.c\nindex 4a9a10eff4..0f4119cbae 100644\n--- a/rebase-interactive.c\n+++ b/rebase-interactive.c\n@@ -52,28 +52,6 @@ void append_todo_help(unsigned edit_todo, unsigned keep_empty,\n \t}\n }\n \n-int append_todo_help_to_file(unsigned edit_todo, unsigned keep_empty)\n-{\n-\tstruct strbuf buf = STRBUF_INIT;\n-\tFILE *todo;\n-\tint ret;\n-\n-\ttodo = fopen_or_warn(rebase_path_todo(), \"a\");\n-\tif (!todo)\n-\t\treturn -1;\n-\n-\tappend_todo_help(edit_todo, keep_empty, &buf);\n-\n-\tret = fputs(buf.buf, todo);\n-\tif (ret < 0)\n-\t\terror_errno(_(\"could not append help text to '%s'\"), rebase_path_todo());\n-\n-\tfclose(todo);\n-\tstrbuf_release(&buf);\n-\n-\treturn ret;\n-}\n-\n int edit_todo_list(unsigned flags)\n {\n \tstruct strbuf buf = STRBUF_INIT;\ndiff --git a/rebase-interactive.h b/rebase-interactive.h\nindex d33f3176b7..971da03776 100644\n--- a/rebase-interactive.h\n+++ b/rebase-interactive.h\n@@ -3,7 +3,6 @@\n \n void append_todo_help(unsigned edit_todo, unsigned keep_empty,\n \t\t      struct strbuf *buf);\n-int append_todo_help_to_file(unsigned edit_todo, unsigned keep_empty);\n int edit_todo_list(unsigned flags);\n \n #endif\ndiff --git a/sequencer.c b/sequencer.c\nindex ae1f44de2f..3800439c10 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -3175,9 +3175,9 @@ int prepare_branch_to_be_rebased(struct replay_opts *opts, const char *commit)\n \treturn 0;\n }\n \n-int checkout_onto(struct replay_opts *opts,\n-\t\t  const char *onto_name, const char *onto,\n-\t\t  const char *orig_head)\n+static int checkout_onto(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 \tstruct object_id oid;\n \tconst char *action = reflog_message(opts, \"start\", \"checkout %s\", onto_name);\n@@ -4424,7 +4424,7 @@ static int rewrite_file(const char *path, const char *buf, size_t len)\n }\n \n /* skip picking commits whose parents are unchanged */\n-int skip_unnecessary_picks(struct object_id *output_oid)\n+static int skip_unnecessary_picks(struct object_id *output_oid)\n {\n \tconst char *todo_file = rebase_path_todo();\n \tstruct strbuf buf = STRBUF_INIT;\ndiff --git a/sequencer.h b/sequencer.h\nindex d58766c6d7..02e3d7940e 100644\n--- a/sequencer.h\n+++ b/sequencer.h\n@@ -91,7 +91,6 @@ int sequencer_add_exec_commands(const char *command);\n int transform_todos(unsigned flags);\n enum missing_commit_check_level get_missing_commit_check_level(void);\n int check_todo_list(void);\n-int skip_unnecessary_picks(struct object_id *output_oid);\n int complete_action(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, const char *cmd,\n@@ -114,9 +113,6 @@ void commit_post_rewrite(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 checkout_onto(struct replay_opts *opts,\n-\t\t  const char *onto_name, const char *onto,\n-\t\t  const char *orig_head);\n \n #define SUMMARY_INITIAL_COMMIT   (1 << 0)\n #define SUMMARY_SHOW_AUTHOR_DATE (1 << 1)\n-- \n2.18.0\n\n"},{"id":"355107","messageId":"20180810165147.4779-14-alban.gruin@gmail.com","threadId":"48814","inReplyTo":"20180810165147.4779-1-alban.gruin@gmail.com","subject":"[GSoC][PATCH v6 13/20] rebase -i: implement the logic to initialize $revisions in C","fromName":"Alban Gruin","fromEmail":"alban.gruin@gmail.com","sentAt":"2018-08-10T16:51:40Z","receivedAt":"2018-08-10T16:52:39Z","isPatch":true,"sender":{"key":"alban.gruin@gmail.com","avatar":"https://avatars.githubusercontent.com/u/6310153?v=4"},"body":"This rewrites the part of init_revisions_and_shortrevisions() needed by\n`--make-script` from shell to C.  The new version is called\nget_revision_ranges(), and is a static function inside of\nrebase--helper.c.  As this does not initialize $shortrevision, the\noriginal shell version is not yet stripped.\n\nUnlike init_revisions_and_shortrevisions(), get_revision_ranges()\ndoesn’t write $squash_onto to the state directory, it’s done by the\nhandler of `--make-script` instead.\n\nFinally, this drops the $revision argument passed to `--make-script` in\ngit-rebase--interactive.sh, and rebase--helper is changed accordingly.\n\nSigned-off-by: Alban Gruin <alban.gruin@gmail.com>\n---\nNo changes since v5.\n\n builtin/rebase--helper.c   | 56 ++++++++++++++++++++++++++++++++++++--\n git-rebase--interactive.sh |  4 ++-\n 2 files changed, 56 insertions(+), 4 deletions(-)\n\ndiff --git a/builtin/rebase--helper.c b/builtin/rebase--helper.c\nindex e1460136f5..acc71a6f99 100644\n--- a/builtin/rebase--helper.c\n+++ b/builtin/rebase--helper.c\n@@ -4,6 +4,25 @@\n #include \"parse-options.h\"\n #include \"sequencer.h\"\n #include \"rebase-interactive.h\"\n+#include \"argv-array.h\"\n+\n+static GIT_PATH_FUNC(path_squash_onto, \"rebase-merge/squash-onto\")\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)\n+{\n+\tconst char *base_rev = upstream ? upstream : onto;\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+\treturn 0;\n+}\n \n static const char * const builtin_rebase_helper_usage[] = {\n \tN_(\"git rebase--helper [<options>]\"),\n@@ -14,7 +33,9 @@ int cmd_rebase__helper(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;\n+\tint abbreviate_commands = 0, rebase_cousins = -1, ret;\n+\tconst char *head_hash = NULL, *onto = NULL, *restrict_revision = NULL,\n+\t\t*squash_onto = NULL, *upstream = NULL;\n \tenum {\n \t\tCONTINUE = 1, ABORT, MAKE_SCRIPT, SHORTEN_OIDS, EXPAND_OIDS,\n \t\tCHECK_TODO_LIST, REARRANGE_SQUASH, ADD_EXEC, EDIT_TODO, PREPARE_BRANCH,\n@@ -54,6 +75,13 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\n \t\t\t    N_(\"prepare the branch to be rebased\"), PREPARE_BRANCH),\n \t\tOPT_CMDMODE(0, \"complete-action\", &command,\n \t\t\t    N_(\"complete the action\"), COMPLETE_ACTION),\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_END()\n \t};\n \n@@ -81,8 +109,30 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\n \t\treturn !!sequencer_continue(&opts);\n \tif (command == ABORT && argc == 1)\n \t\treturn !!sequencer_remove_state(&opts);\n-\tif (command == MAKE_SCRIPT && argc > 1)\n-\t\treturn !!sequencer_make_script(stdout, argc, argv, flags);\n+\tif (command == MAKE_SCRIPT && argc == 1) {\n+\t\tchar *revisions = NULL;\n+\t\tstruct argv_array make_script_args = ARGV_ARRAY_INIT;\n+\n+\t\tif (!upstream && squash_onto)\n+\t\t\twrite_file(path_squash_onto(), \"%s\\n\", squash_onto);\n+\n+\t\tret = get_revision_ranges(upstream, onto, &head_hash, &revisions);\n+\t\tif (ret)\n+\t\t\treturn ret;\n+\n+\t\targv_array_pushl(&make_script_args, \"\", revisions, NULL);\n+\t\tif (restrict_revision)\n+\t\t\targv_array_push(&make_script_args, restrict_revision);\n+\n+\t\tret = sequencer_make_script(stdout,\n+\t\t\t\t\t    make_script_args.argc, make_script_args.argv,\n+\t\t\t\t\t    flags);\n+\n+\t\tfree(revisions);\n+\t\targv_array_clear(&make_script_args);\n+\n+\t\treturn !!ret;\n+\t}\n \tif ((command == SHORTEN_OIDS || command == EXPAND_OIDS) && argc == 1)\n \t\treturn !!transform_todos(flags);\n \tif (command == CHECK_TODO_LIST && argc == 1)\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex 0d66c0f8b8..4ca47aed1e 100644\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -92,7 +92,9 @@ git_rebase__interactive () {\n \tgit rebase--helper --make-script ${keep_empty:+--keep-empty} \\\n \t\t${rebase_merges:+--rebase-merges} \\\n \t\t${rebase_cousins:+--rebase-cousins} \\\n-\t\t$revisions ${restrict_revision+^$restrict_revision} >\"$todo\" ||\n+\t\t${upstream:+--upstream \"$upstream\"} ${onto:+--onto \"$onto\"} \\\n+\t\t${squash_onto:+--squash-onto \"$squash_onto\"} \\\n+\t\t${restrict_revision:+--restrict-revision ^\"$restrict_revision\"} >\"$todo\" ||\n \tdie \"$(gettext \"Could not generate todo list\")\"\n \n \texec git rebase--helper --complete-action \"$shortrevisions\" \"$onto_name\" \\\n-- \n2.18.0\n\n"},{"id":"355108","messageId":"20180810165147.4779-15-alban.gruin@gmail.com","threadId":"48814","inReplyTo":"20180810165147.4779-1-alban.gruin@gmail.com","subject":"[GSoC][PATCH v6 14/20] rebase -i: rewrite the rest of init_revisions_and_shortrevisions() in C","fromName":"Alban Gruin","fromEmail":"alban.gruin@gmail.com","sentAt":"2018-08-10T16:51:41Z","receivedAt":"2018-08-10T16:52:41Z","isPatch":true,"sender":{"key":"alban.gruin@gmail.com","avatar":"https://avatars.githubusercontent.com/u/6310153?v=4"},"body":"This rewrites the part of init_revisions_and_shortrevisions() needed by\n`--complete-action` (which initialize $shortrevisions) from shell to C.\n\nWhen `upstream` is empty, it means that the user launched a `rebase\n--root`, and `onto` contains the ID of an empty commit.  As a range\nbetween an empty commit and `head` is not really meaningful, `onto` is\nnot used to initialize `shortrevisions` in this case.\n\nThe corresponding arguments passed to `--complete-action` are then\ndropped, and init_revisions_and_shortrevisions() is stripped from\ngit-rebase--interactive.sh\n\nSigned-off-by: Alban Gruin <alban.gruin@gmail.com>\n---\nNo changes since v5.\n\n builtin/rebase--helper.c   | 40 ++++++++++++++++++++++++++++++++------\n git-rebase--interactive.sh | 27 ++++---------------------\n 2 files changed, 38 insertions(+), 29 deletions(-)\n\ndiff --git a/builtin/rebase--helper.c b/builtin/rebase--helper.c\nindex acc71a6f99..0716bbfd78 100644\n--- a/builtin/rebase--helper.c\n+++ b/builtin/rebase--helper.c\n@@ -10,7 +10,7 @@ static GIT_PATH_FUNC(path_squash_onto, \"rebase-merge/squash-onto\")\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)\n+\t\t\t       char **revisions, char **shortrevisions)\n {\n \tconst char *base_rev = upstream ? upstream : onto;\n \tstruct object_id orig_head;\n@@ -19,7 +19,25 @@ static int get_revision_ranges(const char *upstream, const char *onto,\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+\tif (revisions)\n+\t\t*revisions = xstrfmt(\"%s...%s\", base_rev, *head_hash);\n+\tif (shortrevisions) {\n+\t\tconst char *shorthead;\n+\n+\t\tshorthead = find_unique_abbrev(&orig_head, DEFAULT_ABBREV);\n+\n+\t\tif (upstream) {\n+\t\t\tconst char *shortrev;\n+\t\t\tstruct object_id rev_oid;\n+\n+\t\t\tget_oid(base_rev, &rev_oid);\n+\t\t\tshortrev = find_unique_abbrev(&rev_oid, DEFAULT_ABBREV);\n+\n+\t\t\t*shortrevisions = xstrfmt(\"%s..%s\", shortrev, shorthead);\n+\t\t} else\n+\t\t\t*shortrevisions = xstrdup(shorthead);\n+\t}\n \n \treturn 0;\n }\n@@ -116,7 +134,7 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\n \t\tif (!upstream && squash_onto)\n \t\t\twrite_file(path_squash_onto(), \"%s\\n\", squash_onto);\n \n-\t\tret = get_revision_ranges(upstream, onto, &head_hash, &revisions);\n+\t\tret = get_revision_ranges(upstream, onto, &head_hash, &revisions, NULL);\n \t\tif (ret)\n \t\t\treturn ret;\n \n@@ -145,9 +163,19 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\n \t\treturn !!edit_todo_list(flags);\n \tif (command == PREPARE_BRANCH && argc == 2)\n \t\treturn !!prepare_branch_to_be_rebased(&opts, argv[1]);\n-\tif (command == COMPLETE_ACTION && argc == 6)\n-\t\treturn !!complete_action(&opts, flags, argv[1], argv[2], argv[3],\n-\t\t\t\t\t argv[4], argv[5], autosquash);\n+\tif (command == COMPLETE_ACTION && argc == 3) {\n+\t\tchar *shortrevisions = NULL;\n+\n+\t\tret = get_revision_ranges(upstream, onto, &head_hash, NULL, &shortrevisions);\n+\t\tif (ret)\n+\t\t\treturn ret;\n+\n+\t\tret = complete_action(&opts, flags, shortrevisions, argv[1], onto,\n+\t\t\t\t      head_hash, argv[2], autosquash);\n+\n+\t\tfree(shortrevisions);\n+\t\treturn !!ret;\n+\t}\n \n \tusage_with_options(builtin_rebase_helper_usage, options);\n }\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex 4ca47aed1e..08e9a21c2f 100644\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -60,23 +60,6 @@ init_basic_state () {\n \twrite_basic_state\n }\n \n-init_revisions_and_shortrevisions () {\n-\tshorthead=$(git rev-parse --short $orig_head)\n-\tshortonto=$(git rev-parse --short $onto)\n-\tif test -z \"$rebase_root\"\n-\t\t# this is now equivalent to ! -z \"$upstream\"\n-\tthen\n-\t\tshortupstream=$(git rev-parse --short $upstream)\n-\t\trevisions=$upstream...$orig_head\n-\t\tshortrevisions=$shortupstream..$shorthead\n-\telse\n-\t\trevisions=$onto...$orig_head\n-\t\tshortrevisions=$shorthead\n-\t\ttest -z \"$squash_onto\" ||\n-\t\techo \"$squash_onto\" >\"$state_dir\"/squash-onto\n-\tfi\n-}\n-\n git_rebase__interactive () {\n \tinitiate_action \"$action\"\n \tret=$?\n@@ -87,8 +70,6 @@ git_rebase__interactive () {\n \tgit rebase--helper --prepare-branch \"$switch_to\" ${verbose:+--verbose}\n \tinit_basic_state\n \n-\tinit_revisions_and_shortrevisions\n-\n \tgit rebase--helper --make-script ${keep_empty:+--keep-empty} \\\n \t\t${rebase_merges:+--rebase-merges} \\\n \t\t${rebase_cousins:+--rebase-cousins} \\\n@@ -97,8 +78,8 @@ git_rebase__interactive () {\n \t\t${restrict_revision:+--restrict-revision ^\"$restrict_revision\"} >\"$todo\" ||\n \tdie \"$(gettext \"Could not generate todo list\")\"\n \n-\texec git rebase--helper --complete-action \"$shortrevisions\" \"$onto_name\" \\\n-\t\t\"$shortonto\" \"$orig_head\" \"$cmd\" $allow_empty_message \\\n-\t\t${autosquash:+--autosquash} ${keep_empty:+--keep-empty} \\\n-\t\t${verbose:+--verbose} ${force_rebase:+--no-ff}\n+\texec git rebase--helper --complete-action \"$onto_name\" \"$cmd\" \\\n+\t\t$allow_empty_message ${autosquash:+--autosquash} ${verbose:+--verbose} \\\n+\t\t${keep_empty:+--keep-empty} ${force_rebase:+--no-ff} \\\n+\t\t${upstream:+--upstream \"$upstream\"} ${onto:+--onto \"$onto\"}\n }\n-- \n2.18.0\n\n"},{"id":"355109","messageId":"20180810165147.4779-16-alban.gruin@gmail.com","threadId":"48814","inReplyTo":"20180810165147.4779-1-alban.gruin@gmail.com","subject":"[GSoC][PATCH v6 15/20] rebase -i: rewrite write_basic_state() in C","fromName":"Alban Gruin","fromEmail":"alban.gruin@gmail.com","sentAt":"2018-08-10T16:51:42Z","receivedAt":"2018-08-10T16:52:43Z","isPatch":true,"sender":{"key":"alban.gruin@gmail.com","avatar":"https://avatars.githubusercontent.com/u/6310153?v=4"},"body":"This rewrites write_basic_state() from git-rebase.sh in C.  This is the\nfirst step in the conversion of init_basic_state(), hence the mode in\nrebase--helper.c is called INIT_BASIC_STATE.  init_basic_state() will be\nconverted in the next commit.\n\nThe part of read_strategy_opts() that parses the stategy options is\nmoved to a new function to allow its use in rebase--helper.c.\n\nFinally, the call to write_basic_state() is removed from\ngit-rebase--interactive.sh, replaced by a call to `--init-basic-state`.\n\nSigned-off-by: Alban Gruin <alban.gruin@gmail.com>\n---\nNo changes since v5.\n\n builtin/rebase--helper.c   | 28 +++++++++++++-\n git-rebase--interactive.sh |  7 +++-\n sequencer.c                | 77 ++++++++++++++++++++++++++++++++------\n sequencer.h                |  4 ++\n 4 files changed, 102 insertions(+), 14 deletions(-)\n\ndiff --git a/builtin/rebase--helper.c b/builtin/rebase--helper.c\nindex 0716bbfd78..63c5086e42 100644\n--- a/builtin/rebase--helper.c\n+++ b/builtin/rebase--helper.c\n@@ -5,6 +5,8 @@\n #include \"sequencer.h\"\n #include \"rebase-interactive.h\"\n #include \"argv-array.h\"\n+#include \"rerere.h\"\n+#include \"alias.h\"\n \n static GIT_PATH_FUNC(path_squash_onto, \"rebase-merge/squash-onto\")\n \n@@ -53,11 +55,12 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\n \tunsigned flags = 0, keep_empty = 0, rebase_merges = 0, autosquash = 0;\n \tint abbreviate_commands = 0, rebase_cousins = -1, ret;\n \tconst char *head_hash = NULL, *onto = NULL, *restrict_revision = NULL,\n-\t\t*squash_onto = NULL, *upstream = NULL;\n+\t\t*squash_onto = NULL, *upstream = NULL, *head_name = NULL;\n+\tchar *raw_strategies = NULL;\n \tenum {\n \t\tCONTINUE = 1, ABORT, MAKE_SCRIPT, SHORTEN_OIDS, EXPAND_OIDS,\n \t\tCHECK_TODO_LIST, REARRANGE_SQUASH, ADD_EXEC, EDIT_TODO, PREPARE_BRANCH,\n-\t\tCOMPLETE_ACTION\n+\t\tCOMPLETE_ACTION, INIT_BASIC_STATE\n \t} command = 0;\n \tstruct option options[] = {\n \t\tOPT_BOOL(0, \"ff\", &opts.allow_ff, N_(\"allow fast-forward\")),\n@@ -69,6 +72,7 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\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\tCONTINUE),\n@@ -93,6 +97,8 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\n \t\t\t    N_(\"prepare the branch to be rebased\"), PREPARE_BRANCH),\n \t\tOPT_CMDMODE(0, \"complete-action\", &command,\n \t\t\t    N_(\"complete the action\"), COMPLETE_ACTION),\n+\t\tOPT_CMDMODE(0, \"init-basic-state\", &command,\n+\t\t\t    N_(\"initialise the rebase state\"), INIT_BASIC_STATE),\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@@ -100,6 +106,14 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\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\tOPT_STRING('S', \"gpg-sign\", &opts.gpg_sign, N_(\"gpg-sign\"),\n+\t\t\t   N_(\"GPG-sign commits\")),\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_RERERE_AUTOUPDATE(&opts.allow_rerere_auto),\n \t\tOPT_END()\n \t};\n \n@@ -176,6 +190,16 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\n \t\tfree(shortrevisions);\n \t\treturn !!ret;\n \t}\n+\tif (command == INIT_BASIC_STATE) {\n+\t\tif (raw_strategies)\n+\t\t\tparse_strategy_opts(&opts, raw_strategies);\n+\n+\t\tret = get_revision_ranges(upstream, onto, &head_hash, NULL, NULL);\n+\t\tif (ret)\n+\t\t\treturn ret;\n+\n+\t\treturn !!write_basic_state(&opts, head_name, onto, head_hash);\n+\t}\n \n \tusage_with_options(builtin_rebase_helper_usage, options);\n }\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex 08e9a21c2f..6367da66e2 100644\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -57,7 +57,6 @@ init_basic_state () {\n \trm -f \"$(git rev-parse --git-path REBASE_HEAD)\"\n \n \t: > \"$state_dir\"/interactive || die \"$(gettext \"Could not mark as interactive\")\"\n-\twrite_basic_state\n }\n \n git_rebase__interactive () {\n@@ -70,6 +69,12 @@ git_rebase__interactive () {\n \tgit rebase--helper --prepare-branch \"$switch_to\" ${verbose:+--verbose}\n \tinit_basic_state\n \n+\tgit rebase--helper --init-basic-state ${upstream:+--upstream \"$upstream\"} \\\n+\t\t${onto:+--onto \"$onto\"} ${head_name:+--head-name \"$head_name\"} \\\n+\t\t${verbose:+--verbose} ${strategy:+--strategy \"$strategy\"} \\\n+\t\t${strategy_opts:+--strategy-opts=\"$strategy_opts\"} \\\n+\t\t\"$allow_rerere_autoupdate\" \"$gpg_sign_opt\" \"$signoff\" || exit\n+\n \tgit rebase--helper --make-script ${keep_empty:+--keep-empty} \\\n \t\t${rebase_merges:+--rebase-merges} \\\n \t\t${rebase_cousins:+--rebase-cousins} \\\ndiff --git a/sequencer.c b/sequencer.c\nindex 3800439c10..beff749904 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -144,7 +144,7 @@ static GIT_PATH_FUNC(rebase_path_refs_to_delete, \"rebase-merge/refs-to-delete\")\n \n /*\n  * The following files are written by git-rebase just after parsing the\n- * command-line (and are only consumed, not modified, by the sequencer).\n+ * command-line.\n  */\n static GIT_PATH_FUNC(rebase_path_gpg_sign_opt, \"rebase-merge/gpg_sign_opt\")\n static GIT_PATH_FUNC(rebase_path_orig_head, \"rebase-merge/orig-head\")\n@@ -156,6 +156,7 @@ static GIT_PATH_FUNC(rebase_path_autostash, \"rebase-merge/autostash\")\n static GIT_PATH_FUNC(rebase_path_strategy, \"rebase-merge/strategy\")\n static GIT_PATH_FUNC(rebase_path_strategy_opts, \"rebase-merge/strategy_opts\")\n static GIT_PATH_FUNC(rebase_path_allow_rerere_autoupdate, \"rebase-merge/allow_rerere_autoupdate\")\n+static GIT_PATH_FUNC(rebase_path_quiet, \"rebase-merge/quiet\")\n \n static int git_sequencer_config(const char *k, const char *v, void *cb)\n {\n@@ -2205,21 +2206,14 @@ static int populate_opts_cb(const char *key, const char *value, void *data)\n \treturn 0;\n }\n \n-static void read_strategy_opts(struct replay_opts *opts, struct strbuf *buf)\n+void parse_strategy_opts(struct replay_opts *opts, char *raw_opts)\n {\n \tint i;\n-\tchar *strategy_opts_string;\n+\tchar *strategy_opts_string = raw_opts;\n \n-\tstrbuf_reset(buf);\n-\tif (!read_oneliner(buf, rebase_path_strategy(), 0))\n-\t\treturn;\n-\topts->strategy = strbuf_detach(buf, NULL);\n-\tif (!read_oneliner(buf, rebase_path_strategy_opts(), 0))\n-\t\treturn;\n-\n-\tstrategy_opts_string = buf->buf;\n \tif (*strategy_opts_string == ' ')\n \t\tstrategy_opts_string++;\n+\n \topts->xopts_nr = split_cmdline(strategy_opts_string,\n \t\t\t\t       (const char ***)&opts->xopts);\n \tfor (i = 0; i < opts->xopts_nr; i++) {\n@@ -2230,6 +2224,18 @@ static void read_strategy_opts(struct replay_opts *opts, struct strbuf *buf)\n \t}\n }\n \n+static void read_strategy_opts(struct replay_opts *opts, struct strbuf *buf)\n+{\n+\tstrbuf_reset(buf);\n+\tif (!read_oneliner(buf, rebase_path_strategy(), 0))\n+\t\treturn;\n+\topts->strategy = strbuf_detach(buf, NULL);\n+\tif (!read_oneliner(buf, rebase_path_strategy_opts(), 0))\n+\t\treturn;\n+\n+\tparse_strategy_opts(opts, buf->buf);\n+}\n+\n static int read_populate_opts(struct replay_opts *opts)\n {\n \tif (is_rebase_i(opts)) {\n@@ -2297,6 +2303,55 @@ static int read_populate_opts(struct replay_opts *opts)\n \treturn 0;\n }\n \n+static void write_strategy_opts(struct replay_opts *opts)\n+{\n+\tint i;\n+\tstruct strbuf buf = STRBUF_INIT;\n+\n+\tfor (i = 0; i < opts->xopts_nr; ++i)\n+\t\tstrbuf_addf(&buf, \" --%s\", opts->xopts[i]);\n+\n+\twrite_file(rebase_path_strategy_opts(), \"%s\\n\", buf.buf);\n+\tstrbuf_release(&buf);\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+{\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+\tif (orig_head)\n+\t\twrite_file(rebase_path_orig_head(), \"%s\\n\", orig_head);\n+\n+\tif (quiet)\n+\t\twrite_file(rebase_path_quiet(), \"%s\\n\", quiet);\n+\telse\n+\t\twrite_file(rebase_path_quiet(), \"\\n\");\n+\n+\tif (opts->verbose)\n+\t\twrite_file(rebase_path_verbose(), \"\");\n+\tif (opts->strategy)\n+\t\twrite_file(rebase_path_strategy(), \"%s\\n\", opts->strategy);\n+\tif (opts->xopts_nr > 0)\n+\t\twrite_strategy_opts(opts);\n+\n+\tif (opts->allow_rerere_auto == RERERE_AUTOUPDATE)\n+\t\twrite_file(rebase_path_allow_rerere_autoupdate(), \"--rerere-autoupdate\\n\");\n+\telse if (opts->allow_rerere_auto == RERERE_NOAUTOUPDATE)\n+\t\twrite_file(rebase_path_allow_rerere_autoupdate(), \"--no-rerere-autoupdate\\n\");\n+\n+\tif (opts->gpg_sign)\n+\t\twrite_file(rebase_path_gpg_sign_opt(), \"-S%s\\n\", opts->gpg_sign);\n+\tif (opts->signoff)\n+\t\twrite_file(rebase_path_signoff(), \"--signoff\\n\");\n+\n+\treturn 0;\n+}\n+\n static int walk_revs_populate_todo(struct todo_list *todo_list,\n \t\t\t\tstruct replay_opts *opts)\n {\ndiff --git a/sequencer.h b/sequencer.h\nindex 02e3d7940e..aab280f276 100644\n--- a/sequencer.h\n+++ b/sequencer.h\n@@ -119,3 +119,7 @@ int prepare_branch_to_be_rebased(struct replay_opts *opts, const char *commit);\n void print_commit_summary(const char *prefix, const struct object_id *oid,\n \t\t\t  unsigned int flags);\n #endif\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-- \n2.18.0\n\n"},{"id":"355110","messageId":"20180810165147.4779-17-alban.gruin@gmail.com","threadId":"48814","inReplyTo":"20180810165147.4779-1-alban.gruin@gmail.com","subject":"[GSoC][PATCH v6 16/20] rebase -i: rewrite init_basic_state() in C","fromName":"Alban Gruin","fromEmail":"alban.gruin@gmail.com","sentAt":"2018-08-10T16:51:43Z","receivedAt":"2018-08-10T16:52:44Z","isPatch":true,"sender":{"key":"alban.gruin@gmail.com","avatar":"https://avatars.githubusercontent.com/u/6310153?v=4"},"body":"This rewrites init_basic_state() from shell to C.  The call to\nwrite_basic_state() in cmd_rebase__helper() is replaced by a call to the\nnew function.\n\nThe shell version is then stripped from git-rebase--interactive.sh.\n\nSigned-off-by: Alban Gruin <alban.gruin@gmail.com>\n---\nNo changes since v5.\n\n builtin/rebase--helper.c   | 23 ++++++++++++++++++++++-\n git-rebase--interactive.sh |  9 ---------\n 2 files changed, 22 insertions(+), 10 deletions(-)\n\ndiff --git a/builtin/rebase--helper.c b/builtin/rebase--helper.c\nindex 63c5086e42..f8128037d3 100644\n--- a/builtin/rebase--helper.c\n+++ b/builtin/rebase--helper.c\n@@ -5,10 +5,13 @@\n #include \"sequencer.h\"\n #include \"rebase-interactive.h\"\n #include \"argv-array.h\"\n+#include \"refs.h\"\n #include \"rerere.h\"\n #include \"alias.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 get_revision_ranges(const char *upstream, const char *onto,\n \t\t\t       const char **head_hash,\n@@ -44,6 +47,24 @@ static int get_revision_ranges(const char *upstream, const char *onto,\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 const char * const builtin_rebase_helper_usage[] = {\n \tN_(\"git rebase--helper [<options>]\"),\n \tNULL\n@@ -198,7 +219,7 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\n \t\tif (ret)\n \t\t\treturn ret;\n \n-\t\treturn !!write_basic_state(&opts, head_name, onto, head_hash);\n+\t\treturn !!init_basic_state(&opts, head_name, onto, head_hash);\n \t}\n \n \tusage_with_options(builtin_rebase_helper_usage, options);\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex 6367da66e2..761be95ed1 100644\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -51,14 +51,6 @@ initiate_action () {\n \tesac\n }\n \n-init_basic_state () {\n-\torig_head=$(git rev-parse --verify HEAD) || die \"$(gettext \"No HEAD?\")\"\n-\tmkdir -p \"$state_dir\" || die \"$(eval_gettext \"Could not create temporary \\$state_dir\")\"\n-\trm -f \"$(git rev-parse --git-path REBASE_HEAD)\"\n-\n-\t: > \"$state_dir\"/interactive || die \"$(gettext \"Could not mark as interactive\")\"\n-}\n-\n git_rebase__interactive () {\n \tinitiate_action \"$action\"\n \tret=$?\n@@ -67,7 +59,6 @@ git_rebase__interactive () {\n \tfi\n \n \tgit rebase--helper --prepare-branch \"$switch_to\" ${verbose:+--verbose}\n-\tinit_basic_state\n \n \tgit rebase--helper --init-basic-state ${upstream:+--upstream \"$upstream\"} \\\n \t\t${onto:+--onto \"$onto\"} ${head_name:+--head-name \"$head_name\"} \\\n-- \n2.18.0\n\n"},{"id":"355112","messageId":"20180810165147.4779-18-alban.gruin@gmail.com","threadId":"48814","inReplyTo":"20180810165147.4779-1-alban.gruin@gmail.com","subject":"[GSoC][PATCH v6 17/20] rebase -i: implement the main part of interactive rebase as a builtin","fromName":"Alban Gruin","fromEmail":"alban.gruin@gmail.com","sentAt":"2018-08-10T16:51:44Z","receivedAt":"2018-08-10T16:52:46Z","isPatch":true,"sender":{"key":"alban.gruin@gmail.com","avatar":"https://avatars.githubusercontent.com/u/6310153?v=4"},"body":"This rewrites the part of interactive rebase which initializes the\nbasic state, make the script and complete the action, as a buitin, named\ngit-rebase--interactive2 for now.  Others modes (`--continue`,\n`--edit-todo`, etc.) will be rewritten in the next commit.\n\ngit-rebase--interactive.sh is modified to call git-rebase--interactive2\ninstead of git-rebase--helper.\n\nSigned-off-by: Alban Gruin <alban.gruin@gmail.com>\n---\n .gitignore                     |   1 +\n Makefile                       |   1 +\n builtin.h                      |   1 +\n builtin/rebase--interactive2.c | 200 +++++++++++++++++++++++++++++++++\n git-rebase--interactive.sh     |  41 +++----\n git.c                          |   1 +\n 6 files changed, 226 insertions(+), 19 deletions(-)\n create mode 100644 builtin/rebase--interactive2.c\n\ndiff --git a/.gitignore b/.gitignore\nindex 3284a1e9b1..404c9a8472 100644\n--- a/.gitignore\n+++ b/.gitignore\n@@ -118,6 +118,7 @@\n /git-rebase--am\n /git-rebase--helper\n /git-rebase--interactive\n+/git-rebase--interactive2\n /git-rebase--merge\n /git-rebase--preserve-merges\n /git-receive-pack\ndiff --git a/Makefile b/Makefile\nindex 909a687857..71f8f45fe5 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -1060,6 +1060,7 @@ BUILTIN_OBJS += builtin/prune.o\n BUILTIN_OBJS += builtin/pull.o\n BUILTIN_OBJS += builtin/push.o\n BUILTIN_OBJS += builtin/read-tree.o\n+BUILTIN_OBJS += builtin/rebase--interactive2.o\n BUILTIN_OBJS += builtin/rebase--helper.o\n BUILTIN_OBJS += builtin/receive-pack.o\n BUILTIN_OBJS += builtin/reflog.o\ndiff --git a/builtin.h b/builtin.h\nindex 0362f1ce25..ed89b4f495 100644\n--- a/builtin.h\n+++ b/builtin.h\n@@ -202,6 +202,7 @@ extern int cmd_prune_packed(int argc, const char **argv, const char *prefix);\n extern int cmd_pull(int argc, const char **argv, const char *prefix);\n extern int cmd_push(int argc, const char **argv, const char *prefix);\n extern int cmd_read_tree(int argc, const char **argv, const char *prefix);\n+extern int cmd_rebase__interactive(int argc, const char **argv, const char *prefix);\n extern int cmd_rebase__helper(int argc, const char **argv, const char *prefix);\n extern int cmd_receive_pack(int argc, const char **argv, const char *prefix);\n extern int cmd_reflog(int argc, const char **argv, const char *prefix);\ndiff --git a/builtin/rebase--interactive2.c b/builtin/rebase--interactive2.c\nnew file mode 100644\nindex 0000000000..b0a1ca25fe\n--- /dev/null\n+++ b/builtin/rebase--interactive2.c\n@@ -0,0 +1,200 @@\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 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 const char *cmd, 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+\tFILE *todo_list;\n+\n+\tif (prepare_branch_to_be_rebased(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+\ttodo_list = fopen(rebase_path_todo(), \"w\");\n+\tif (!todo_list) {\n+\t\tfree(revisions);\n+\t\tfree(shortrevisions);\n+\n+\t\treturn error_errno(_(\"could not open %s\"), rebase_path_todo());\n+\t}\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(todo_list,\n+\t\t\t\t    make_script_args.argc, make_script_args.argv,\n+\t\t\t\t    flags);\n+\tfclose(todo_list);\n+\n+\tif (ret)\n+\t\terror(_(\"could not generate todo list\"));\n+\telse {\n+\t\tdiscard_cache();\n+\t\tret = complete_action(opts, flags, shortrevisions, onto_name, onto,\n+\t\t\t\t      head_hash, cmd, autosquash);\n+\t}\n+\n+\tfree(revisions);\n+\tfree(shortrevisions);\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;\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+\tchar *raw_strategies = NULL;\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_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\tOPT_STRING('S', \"gpg-sign\", &opts.gpg_sign, N_(\"gpg-sign\"),\n+\t\t\t   N_(\"GPG-sign commits\")),\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_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+\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+\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+\treturn !!do_interactive_rebase(&opts, flags, switch_to, upstream, onto,\n+\t\t\t\t       onto_name, squash_onto, head_name, restrict_revision,\n+\t\t\t\t       raw_strategies, cmd, autosquash);\n+}\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex 761be95ed1..e87d708a4d 100644\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -58,24 +58,27 @@ git_rebase__interactive () {\n \t\treturn 0\n \tfi\n \n-\tgit rebase--helper --prepare-branch \"$switch_to\" ${verbose:+--verbose}\n+\ttest -n \"$keep_empty\" && keep_empty=\"--keep-empty\"\n+\ttest -n \"$rebase_merges\" && rebase_merges=\"--rebase-merges\"\n+\ttest -n \"$rebase_cousins\" && rebase_cousins=\"--rebase-cousins\"\n+\ttest -n \"$autosquash\" && autosquash=\"--autosquash\"\n+\ttest -n \"$verbose\" && verbose=\"--verbose\"\n+\ttest -n \"$force_rebase\" && force_rebase=\"--no-ff\"\n+\ttest -n \"$restrict_revisions\" && restrict_revisions=\"--restrict-revisions=^$restrict_revisions\"\n+\ttest -n \"$upstream\" && upstream=\"--upstream=$upstream\"\n+\ttest -n \"$onto\" && onto=\"--onto=$onto\"\n+\ttest -n \"$squash_onto\" && squash_onto=\"--squash-onto=$squash_onto\"\n+\ttest -n \"$onto_name\" && onto_name=\"--onto-name=$onto_name\"\n+\ttest -n \"$head_name\" && head_name=\"--head-name=$head_name\"\n+\ttest -n \"$strategy\" && strategy=\"--strategy=$strategy\"\n+\ttest -n \"$strategy_opts\" && strategy_opts=\"--strategy-opts=$strategy_opts\"\n+\ttest -n \"$switch_to\" && switch_to=\"--switch-to=$switch_to\"\n+\ttest -n \"$cmd\" && cmd=\"--cmd=$cmd\"\n \n-\tgit rebase--helper --init-basic-state ${upstream:+--upstream \"$upstream\"} \\\n-\t\t${onto:+--onto \"$onto\"} ${head_name:+--head-name \"$head_name\"} \\\n-\t\t${verbose:+--verbose} ${strategy:+--strategy \"$strategy\"} \\\n-\t\t${strategy_opts:+--strategy-opts=\"$strategy_opts\"} \\\n-\t\t\"$allow_rerere_autoupdate\" \"$gpg_sign_opt\" \"$signoff\" || exit\n-\n-\tgit rebase--helper --make-script ${keep_empty:+--keep-empty} \\\n-\t\t${rebase_merges:+--rebase-merges} \\\n-\t\t${rebase_cousins:+--rebase-cousins} \\\n-\t\t${upstream:+--upstream \"$upstream\"} ${onto:+--onto \"$onto\"} \\\n-\t\t${squash_onto:+--squash-onto \"$squash_onto\"} \\\n-\t\t${restrict_revision:+--restrict-revision ^\"$restrict_revision\"} >\"$todo\" ||\n-\tdie \"$(gettext \"Could not generate todo list\")\"\n-\n-\texec git rebase--helper --complete-action \"$onto_name\" \"$cmd\" \\\n-\t\t$allow_empty_message ${autosquash:+--autosquash} ${verbose:+--verbose} \\\n-\t\t${keep_empty:+--keep-empty} ${force_rebase:+--no-ff} \\\n-\t\t${upstream:+--upstream \"$upstream\"} ${onto:+--onto \"$onto\"}\n+\texec git rebase--interactive2 \"$keep_empty\" \"$rebase_merges\" \"$rebase_cousins\" \\\n+\t\t\"$upstream\" \"$onto\" \"$squash_onto\" \"$restrict_revision\" \\\n+\t\t\"$allow_empty_message\" \"$autosquash\" \"$verbose\" \\\n+\t\t\"$force_rebase\" \"$onto_name\" \"$head_name\" \"$strategy\" \\\n+\t\t\"$strategy_opts\" \"$cmd\" \"$switch_to\" \\\n+\t\t\"$allow_rerere_autoupdate\" \"$gpg_sign_opt\" \"$signoff\"\n }\ndiff --git a/git.c b/git.c\nindex 3fded74519..8309fb24a6 100644\n--- a/git.c\n+++ b/git.c\n@@ -518,6 +518,7 @@ static struct cmd_struct commands[] = {\n \t{ \"pull\", cmd_pull, RUN_SETUP | NEED_WORK_TREE },\n \t{ \"push\", cmd_push, RUN_SETUP },\n \t{ \"read-tree\", cmd_read_tree, RUN_SETUP | SUPPORT_SUPER_PREFIX},\n+\t{ \"rebase--interactive2\", cmd_rebase__interactive, RUN_SETUP | NEED_WORK_TREE },\n \t{ \"rebase--helper\", cmd_rebase__helper, RUN_SETUP | NEED_WORK_TREE },\n \t{ \"receive-pack\", cmd_receive_pack },\n \t{ \"reflog\", cmd_reflog, RUN_SETUP },\n-- \n2.18.0\n\n"},{"id":"355111","messageId":"20180810165147.4779-19-alban.gruin@gmail.com","threadId":"48814","inReplyTo":"20180810165147.4779-1-alban.gruin@gmail.com","subject":"[GSoC][PATCH v6 18/20] rebase--interactive2: rewrite the submodes of interactive rebase in C","fromName":"Alban Gruin","fromEmail":"alban.gruin@gmail.com","sentAt":"2018-08-10T16:51:45Z","receivedAt":"2018-08-10T16:52:47Z","isPatch":true,"sender":{"key":"alban.gruin@gmail.com","avatar":"https://avatars.githubusercontent.com/u/6310153?v=4"},"body":"This rewrites the submodes of interactive rebase (`--continue`,\n`--skip`, `--edit-todo`, and `--show-current-patch`) in C.\n\ngit-rebase.sh is then modified to call directly git-rebase--interactive2\ninstead of git-rebase--interactive.sh.\n\nSigned-off-by: Alban Gruin <alban.gruin@gmail.com>\n---\nNo changes since v5.\n\n builtin/rebase--interactive2.c | 47 +++++++++++++++++++++++++++++++---\n git-rebase.sh                  | 45 +++++++++++++++++++++++++++++---\n 2 files changed, 84 insertions(+), 8 deletions(-)\n\ndiff --git a/builtin/rebase--interactive2.c b/builtin/rebase--interactive2.c\nindex b0a1ca25fe..9a21855ede 100644\n--- a/builtin/rebase--interactive2.c\n+++ b/builtin/rebase--interactive2.c\n@@ -134,11 +134,14 @@ 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;\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 \tchar *raw_strategies = NULL;\n+\tenum {\n+\t\tNONE = 0, CONTINUE, SKIP, EDIT_TODO, SHOW_CURRENT_PATCH\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@@ -151,6 +154,13 @@ int cmd_rebase__interactive(int argc, const char **argv, const char *prefix)\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_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@@ -194,7 +204,36 @@ 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-\treturn !!do_interactive_rebase(&opts, flags, switch_to, upstream, onto,\n-\t\t\t\t       onto_name, squash_onto, head_name, restrict_revision,\n-\t\t\t\t       raw_strategies, cmd, autosquash);\n+\tswitch (command) {\n+\tcase NONE:\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, cmd, autosquash);\n+\t\tbreak;\n+\tcase SKIP: {\n+\t\tstruct string_list merge_rr = STRING_LIST_INIT_DUP;\n+\n+\t\trerere_clear(&merge_rr);\n+\t\t/* fallthrough */\n+\tcase CONTINUE:\n+\t\tret = sequencer_continue(&opts);\n+\t\tbreak;\n+\t}\n+\tcase EDIT_TODO:\n+\t\tret = edit_todo_list(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+\tdefault:\n+\t\tBUG(\"invalid command '%d'\", command);\n+\t}\n+\n+\treturn !!ret;\n }\ndiff --git a/git-rebase.sh b/git-rebase.sh\nindex 51a6db7daa..d5950a3012 100755\n--- a/git-rebase.sh\n+++ b/git-rebase.sh\n@@ -200,19 +200,56 @@ finish_rebase () {\n \trm -rf \"$state_dir\"\n }\n \n+run_interactive () {\n+\tGIT_CHERRY_PICK_HELP=\"$resolvemsg\"\n+\texport GIT_CHERRY_PICK_HELP\n+\n+\ttest -n \"$keep_empty\" && keep_empty=\"--keep-empty\"\n+\ttest -n \"$rebase_merges\" && rebase_merges=\"--rebase-merges\"\n+\ttest -n \"$rebase_cousins\" && rebase_cousins=\"--rebase-cousins\"\n+\ttest -n \"$autosquash\" && autosquash=\"--autosquash\"\n+\ttest -n \"$verbose\" && verbose=\"--verbose\"\n+\ttest -n \"$force_rebase\" && force_rebase=\"--no-ff\"\n+\ttest -n \"$restrict_revisions\" && \\\n+\t\trestrict_revisions=\"--restrict-revisions=^$restrict_revisions\"\n+\ttest -n \"$upstream\" && upstream=\"--upstream=$upstream\"\n+\ttest -n \"$onto\" && onto=\"--onto=$onto\"\n+\ttest -n \"$squash_onto\" && squash_onto=\"--squash-onto=$squash_onto\"\n+\ttest -n \"$onto_name\" && onto_name=\"--onto-name=$onto_name\"\n+\ttest -n \"$head_name\" && head_name=\"--head-name=$head_name\"\n+\ttest -n \"$strategy\" && strategy=\"--strategy=$strategy\"\n+\ttest -n \"$strategy_opts\" && strategy_opts=\"--strategy-opts=$strategy_opts\"\n+\ttest -n \"$switch_to\" && switch_to=\"--switch-to=$switch_to\"\n+\ttest -n \"$cmd\" && cmd=\"--cmd=$cmd\"\n+\ttest -n \"$action\" && action=\"--$action\"\n+\n+\texec git rebase--interactive2 \"$action\" \"$keep_empty\" \"$rebase_merges\" \"$rebase_cousins\" \\\n+\t\t\"$upstream\" \"$onto\" \"$squash_onto\" \"$restrict_revision\" \\\n+\t\t\"$allow_empty_message\" \"$autosquash\" \"$verbose\" \\\n+\t\t\"$force_rebase\" \"$onto_name\" \"$head_name\" \"$strategy\" \\\n+\t\t\"$strategy_opts\" \"$cmd\" \"$switch_to\" \\\n+\t\t\"$allow_rerere_autoupdate\" \"$gpg_sign_opt\" \"$signoff\"\n+}\n+\n run_specific_rebase () {\n \tif [ \"$interactive_rebase\" = implied ]; then\n \t\tGIT_EDITOR=:\n \t\texport GIT_EDITOR\n \t\tautosquash=\n \tfi\n-\t. git-rebase--$type\n \n-\tif test -z \"$preserve_merges\"\n+\tif test -n \"$interactive_rebase\" -a -z \"$preserve_merges\"\n \tthen\n-\t\tgit_rebase__$type\n+\t\trun_interactive\n \telse\n-\t\tgit_rebase__preserve_merges\n+\t\t. git-rebase--$type\n+\n+\t\tif test -z \"$preserve_merges\"\n+\t\tthen\n+\t\t\tgit_rebase__$type\n+\t\telse\n+\t\t\tgit_rebase__preserve_merges\n+\t\tfi\n \tfi\n \n \tret=$?\n-- \n2.18.0\n\n"},{"id":"355113","messageId":"20180810165147.4779-20-alban.gruin@gmail.com","threadId":"48814","inReplyTo":"20180810165147.4779-1-alban.gruin@gmail.com","subject":"[GSoC][PATCH v6 19/20] rebase -i: remove git-rebase--interactive.sh","fromName":"Alban Gruin","fromEmail":"alban.gruin@gmail.com","sentAt":"2018-08-10T16:51:46Z","receivedAt":"2018-08-10T16:52:48Z","isPatch":true,"sender":{"key":"alban.gruin@gmail.com","avatar":"https://avatars.githubusercontent.com/u/6310153?v=4"},"body":"This removes git-rebase--interactive.sh, as its functionnality has been\nreplaced by git-rebase--interactive2.\n\ngit-rebase--interactive2.c is then renamed to git-rebase--interactive.c.\n\nSigned-off-by: Alban Gruin <alban.gruin@gmail.com>\n---\nNo changes since v5.\n\n .gitignore                                    |  1 -\n Makefile                                      |  4 +-\n ...--interactive2.c => rebase--interactive.c} |  0\n git-rebase--interactive.sh                    | 84 -------------------\n git-rebase.sh                                 |  2 +-\n git.c                                         |  2 +-\n 6 files changed, 3 insertions(+), 90 deletions(-)\n rename builtin/{rebase--interactive2.c => rebase--interactive.c} (100%)\n delete mode 100644 git-rebase--interactive.sh\n\ndiff --git a/.gitignore b/.gitignore\nindex 404c9a8472..3284a1e9b1 100644\n--- a/.gitignore\n+++ b/.gitignore\n@@ -118,7 +118,6 @@\n /git-rebase--am\n /git-rebase--helper\n /git-rebase--interactive\n-/git-rebase--interactive2\n /git-rebase--merge\n /git-rebase--preserve-merges\n /git-receive-pack\ndiff --git a/Makefile b/Makefile\nindex 71f8f45fe5..584834726d 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -619,7 +619,6 @@ SCRIPT_SH += git-web--browse.sh\n SCRIPT_LIB += git-mergetool--lib\n SCRIPT_LIB += git-parse-remote\n SCRIPT_LIB += git-rebase--am\n-SCRIPT_LIB += git-rebase--interactive\n SCRIPT_LIB += git-rebase--preserve-merges\n SCRIPT_LIB += git-rebase--merge\n SCRIPT_LIB += git-sh-setup\n@@ -1060,8 +1059,8 @@ BUILTIN_OBJS += builtin/prune.o\n BUILTIN_OBJS += builtin/pull.o\n BUILTIN_OBJS += builtin/push.o\n BUILTIN_OBJS += builtin/read-tree.o\n-BUILTIN_OBJS += builtin/rebase--interactive2.o\n BUILTIN_OBJS += builtin/rebase--helper.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\n@@ -2400,7 +2399,6 @@ XGETTEXT_FLAGS_PERL = $(XGETTEXT_FLAGS) --language=Perl \\\n LOCALIZED_C = $(C_OBJ:o=c) $(LIB_H) $(GENERATED_H)\n LOCALIZED_SH = $(SCRIPT_SH)\n LOCALIZED_SH += git-parse-remote.sh\n-LOCALIZED_SH += git-rebase--interactive.sh\n LOCALIZED_SH += git-rebase--preserve-merges.sh\n LOCALIZED_SH += git-sh-setup.sh\n LOCALIZED_PERL = $(SCRIPT_PERL)\ndiff --git a/builtin/rebase--interactive2.c b/builtin/rebase--interactive.c\nsimilarity index 100%\nrename from builtin/rebase--interactive2.c\nrename to builtin/rebase--interactive.c\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\ndeleted file mode 100644\nindex e87d708a4d..0000000000\n--- a/git-rebase--interactive.sh\n+++ /dev/null\n@@ -1,84 +0,0 @@\n-# This shell script fragment is sourced by git-rebase to implement\n-# its interactive mode.  \"git rebase --interactive\" makes it easy\n-# to fix up commits in the middle of a series and rearrange commits.\n-#\n-# Copyright (c) 2006 Johannes E. Schindelin\n-#\n-# The original idea comes from Eric W. Biederman, in\n-# https://public-inbox.org/git/m1odwkyuf5.fsf_-_@ebiederm.dsl.xmission.com/\n-#\n-# The file containing rebase commands, comments, and empty lines.\n-# This file is created by \"git rebase -i\" then edited by the user.  As\n-# the lines are processed, they are removed from the front of this\n-# file and written to the tail of $done.\n-todo=\"$state_dir\"/git-rebase-todo\n-\n-GIT_CHERRY_PICK_HELP=\"$resolvemsg\"\n-export GIT_CHERRY_PICK_HELP\n-\n-# Initiate an action. If the cannot be any\n-# further action it  may exec a command\n-# or exit and not return.\n-#\n-# TODO: Consider a cleaner return model so it\n-# never exits and always return 0 if process\n-# is complete.\n-#\n-# Parameter 1 is the action to initiate.\n-#\n-# Returns 0 if the action was able to complete\n-# and if 1 if further processing is required.\n-initiate_action () {\n-\tcase \"$1\" in\n-\tcontinue)\n-\t\texec git rebase--helper ${force_rebase:+--no-ff} $allow_empty_message \\\n-\t\t     --continue\n-\t\t;;\n-\tskip)\n-\t\tgit rerere clear\n-\t\texec git rebase--helper ${force_rebase:+--no-ff} $allow_empty_message \\\n-\t\t     --continue\n-\t\t;;\n-\tedit-todo)\n-\t\texec git rebase--helper --edit-todo\n-\t\t;;\n-\tshow-current-patch)\n-\t\texec git show REBASE_HEAD --\n-\t\t;;\n-\t*)\n-\t\treturn 1 # continue\n-\t\t;;\n-\tesac\n-}\n-\n-git_rebase__interactive () {\n-\tinitiate_action \"$action\"\n-\tret=$?\n-\tif test $ret = 0; then\n-\t\treturn 0\n-\tfi\n-\n-\ttest -n \"$keep_empty\" && keep_empty=\"--keep-empty\"\n-\ttest -n \"$rebase_merges\" && rebase_merges=\"--rebase-merges\"\n-\ttest -n \"$rebase_cousins\" && rebase_cousins=\"--rebase-cousins\"\n-\ttest -n \"$autosquash\" && autosquash=\"--autosquash\"\n-\ttest -n \"$verbose\" && verbose=\"--verbose\"\n-\ttest -n \"$force_rebase\" && force_rebase=\"--no-ff\"\n-\ttest -n \"$restrict_revisions\" && restrict_revisions=\"--restrict-revisions=^$restrict_revisions\"\n-\ttest -n \"$upstream\" && upstream=\"--upstream=$upstream\"\n-\ttest -n \"$onto\" && onto=\"--onto=$onto\"\n-\ttest -n \"$squash_onto\" && squash_onto=\"--squash-onto=$squash_onto\"\n-\ttest -n \"$onto_name\" && onto_name=\"--onto-name=$onto_name\"\n-\ttest -n \"$head_name\" && head_name=\"--head-name=$head_name\"\n-\ttest -n \"$strategy\" && strategy=\"--strategy=$strategy\"\n-\ttest -n \"$strategy_opts\" && strategy_opts=\"--strategy-opts=$strategy_opts\"\n-\ttest -n \"$switch_to\" && switch_to=\"--switch-to=$switch_to\"\n-\ttest -n \"$cmd\" && cmd=\"--cmd=$cmd\"\n-\n-\texec git rebase--interactive2 \"$keep_empty\" \"$rebase_merges\" \"$rebase_cousins\" \\\n-\t\t\"$upstream\" \"$onto\" \"$squash_onto\" \"$restrict_revision\" \\\n-\t\t\"$allow_empty_message\" \"$autosquash\" \"$verbose\" \\\n-\t\t\"$force_rebase\" \"$onto_name\" \"$head_name\" \"$strategy\" \\\n-\t\t\"$strategy_opts\" \"$cmd\" \"$switch_to\" \\\n-\t\t\"$allow_rerere_autoupdate\" \"$gpg_sign_opt\" \"$signoff\"\n-}\ndiff --git a/git-rebase.sh b/git-rebase.sh\nindex d5950a3012..a707d59412 100755\n--- a/git-rebase.sh\n+++ b/git-rebase.sh\n@@ -223,7 +223,7 @@ run_interactive () {\n \ttest -n \"$cmd\" && cmd=\"--cmd=$cmd\"\n \ttest -n \"$action\" && action=\"--$action\"\n \n-\texec git rebase--interactive2 \"$action\" \"$keep_empty\" \"$rebase_merges\" \"$rebase_cousins\" \\\n+\texec git rebase--interactive \"$action\" \"$keep_empty\" \"$rebase_merges\" \"$rebase_cousins\" \\\n \t\t\"$upstream\" \"$onto\" \"$squash_onto\" \"$restrict_revision\" \\\n \t\t\"$allow_empty_message\" \"$autosquash\" \"$verbose\" \\\n \t\t\"$force_rebase\" \"$onto_name\" \"$head_name\" \"$strategy\" \\\ndiff --git a/git.c b/git.c\nindex 8309fb24a6..19d0b6e3b8 100644\n--- a/git.c\n+++ b/git.c\n@@ -518,7 +518,7 @@ static struct cmd_struct commands[] = {\n \t{ \"pull\", cmd_pull, RUN_SETUP | NEED_WORK_TREE },\n \t{ \"push\", cmd_push, RUN_SETUP },\n \t{ \"read-tree\", cmd_read_tree, RUN_SETUP | SUPPORT_SUPER_PREFIX},\n-\t{ \"rebase--interactive2\", cmd_rebase__interactive, RUN_SETUP | NEED_WORK_TREE },\n+\t{ \"rebase--interactive\", cmd_rebase__interactive, RUN_SETUP | NEED_WORK_TREE },\n \t{ \"rebase--helper\", cmd_rebase__helper, RUN_SETUP | NEED_WORK_TREE },\n \t{ \"receive-pack\", cmd_receive_pack },\n \t{ \"reflog\", cmd_reflog, RUN_SETUP },\n-- \n2.18.0\n\n"},{"id":"355114","messageId":"20180810165147.4779-21-alban.gruin@gmail.com","threadId":"48814","inReplyTo":"20180810165147.4779-1-alban.gruin@gmail.com","subject":"[GSoC][PATCH v6 20/20] rebase -i: move rebase--helper modes to rebase--interactive","fromName":"Alban Gruin","fromEmail":"alban.gruin@gmail.com","sentAt":"2018-08-10T16:51:47Z","receivedAt":"2018-08-10T16:52:52Z","isPatch":true,"sender":{"key":"alban.gruin@gmail.com","avatar":"https://avatars.githubusercontent.com/u/6310153?v=4"},"body":"This moves the rebase--helper modes still used by\ngit-rebase--preserve-merges.sh (`--shorten-ids`, `--expand-ids`,\n`--check-todo-list`, `--rearrange-squash` and `--add-exec-commands`) to\nrebase--interactive.c.\n\ngit-rebase--preserve-merges.sh is modified accordingly, and\nrebase--helper.c is removed as it is useless now.\n\nSigned-off-by: Alban Gruin <alban.gruin@gmail.com>\n---\nNo changes since v5.\n\n .gitignore                     |   1 -\n Makefile                       |   1 -\n builtin.h                      |   1 -\n builtin/rebase--helper.c       | 226 ---------------------------------\n builtin/rebase--interactive.c  |  27 +++-\n git-rebase--preserve-merges.sh |  10 +-\n git.c                          |   1 -\n 7 files changed, 31 insertions(+), 236 deletions(-)\n delete mode 100644 builtin/rebase--helper.c\n\ndiff --git a/.gitignore b/.gitignore\nindex 3284a1e9b1..406f26d050 100644\n--- a/.gitignore\n+++ b/.gitignore\n@@ -116,7 +116,6 @@\n /git-read-tree\n /git-rebase\n /git-rebase--am\n-/git-rebase--helper\n /git-rebase--interactive\n /git-rebase--merge\n /git-rebase--preserve-merges\ndiff --git a/Makefile b/Makefile\nindex 584834726d..ca3a0888dd 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -1059,7 +1059,6 @@ BUILTIN_OBJS += builtin/prune.o\n BUILTIN_OBJS += builtin/pull.o\n BUILTIN_OBJS += builtin/push.o\n BUILTIN_OBJS += builtin/read-tree.o\n-BUILTIN_OBJS += builtin/rebase--helper.o\n BUILTIN_OBJS += builtin/rebase--interactive.o\n BUILTIN_OBJS += builtin/receive-pack.o\n BUILTIN_OBJS += builtin/reflog.o\ndiff --git a/builtin.h b/builtin.h\nindex ed89b4f495..7feb689d87 100644\n--- a/builtin.h\n+++ b/builtin.h\n@@ -203,7 +203,6 @@ extern int cmd_pull(int argc, const char **argv, const char *prefix);\n extern int cmd_push(int argc, const char **argv, const char *prefix);\n extern int cmd_read_tree(int argc, const char **argv, const char *prefix);\n extern int cmd_rebase__interactive(int argc, const char **argv, const char *prefix);\n-extern int cmd_rebase__helper(int argc, const char **argv, const char *prefix);\n extern int cmd_receive_pack(int argc, const char **argv, const char *prefix);\n extern int cmd_reflog(int argc, const char **argv, const char *prefix);\n extern int cmd_remote(int argc, const char **argv, const char *prefix);\ndiff --git a/builtin/rebase--helper.c b/builtin/rebase--helper.c\ndeleted file mode 100644\nindex f8128037d3..0000000000\n--- a/builtin/rebase--helper.c\n+++ /dev/null\n@@ -1,226 +0,0 @@\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 \"alias.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 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;\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-\n-\tif (revisions)\n-\t\t*revisions = xstrfmt(\"%s...%s\", base_rev, *head_hash);\n-\tif (shortrevisions) {\n-\t\tconst char *shorthead;\n-\n-\t\tshorthead = find_unique_abbrev(&orig_head, DEFAULT_ABBREV);\n-\n-\t\tif (upstream) {\n-\t\t\tconst char *shortrev;\n-\t\t\tstruct object_id rev_oid;\n-\n-\t\t\tget_oid(base_rev, &rev_oid);\n-\t\t\tshortrev = find_unique_abbrev(&rev_oid, DEFAULT_ABBREV);\n-\n-\t\t\t*shortrevisions = xstrfmt(\"%s..%s\", shortrev, shorthead);\n-\t\t} else\n-\t\t\t*shortrevisions = xstrdup(shorthead);\n-\t}\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 const char * const builtin_rebase_helper_usage[] = {\n-\tN_(\"git rebase--helper [<options>]\"),\n-\tNULL\n-};\n-\n-int cmd_rebase__helper(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;\n-\tconst char *head_hash = NULL, *onto = NULL, *restrict_revision = NULL,\n-\t\t*squash_onto = NULL, *upstream = NULL, *head_name = NULL;\n-\tchar *raw_strategies = NULL;\n-\tenum {\n-\t\tCONTINUE = 1, ABORT, MAKE_SCRIPT, SHORTEN_OIDS, EXPAND_OIDS,\n-\t\tCHECK_TODO_LIST, REARRANGE_SQUASH, ADD_EXEC, EDIT_TODO, PREPARE_BRANCH,\n-\t\tCOMPLETE_ACTION, INIT_BASIC_STATE\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\tN_(\"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\tCONTINUE),\n-\t\tOPT_CMDMODE(0, \"abort\", &command, N_(\"abort rebase\"),\n-\t\t\t\tABORT),\n-\t\tOPT_CMDMODE(0, \"make-script\", &command,\n-\t\t\tN_(\"make rebase script\"), MAKE_SCRIPT),\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_CMDMODE(0, \"edit-todo\", &command,\n-\t\t\t    N_(\"edit the todo list during an interactive rebase\"),\n-\t\t\t    EDIT_TODO),\n-\t\tOPT_CMDMODE(0, \"prepare-branch\", &command,\n-\t\t\t    N_(\"prepare the branch to be rebased\"), PREPARE_BRANCH),\n-\t\tOPT_CMDMODE(0, \"complete-action\", &command,\n-\t\t\t    N_(\"complete the action\"), COMPLETE_ACTION),\n-\t\tOPT_CMDMODE(0, \"init-basic-state\", &command,\n-\t\t\t    N_(\"initialise the rebase state\"), INIT_BASIC_STATE),\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\tOPT_STRING('S', \"gpg-sign\", &opts.gpg_sign, N_(\"gpg-sign\"),\n-\t\t\t   N_(\"GPG-sign commits\")),\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_RERERE_AUTOUPDATE(&opts.allow_rerere_auto),\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-\targc = parse_options(argc, argv, NULL, options,\n-\t\t\tbuiltin_rebase_helper_usage, PARSE_OPT_KEEP_ARGV0);\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 (command == CONTINUE && argc == 1)\n-\t\treturn !!sequencer_continue(&opts);\n-\tif (command == ABORT && argc == 1)\n-\t\treturn !!sequencer_remove_state(&opts);\n-\tif (command == MAKE_SCRIPT && argc == 1) {\n-\t\tchar *revisions = NULL;\n-\t\tstruct argv_array make_script_args = ARGV_ARRAY_INIT;\n-\n-\t\tif (!upstream && squash_onto)\n-\t\t\twrite_file(path_squash_onto(), \"%s\\n\", squash_onto);\n-\n-\t\tret = get_revision_ranges(upstream, onto, &head_hash, &revisions, NULL);\n-\t\tif (ret)\n-\t\t\treturn ret;\n-\n-\t\targv_array_pushl(&make_script_args, \"\", revisions, NULL);\n-\t\tif (restrict_revision)\n-\t\t\targv_array_push(&make_script_args, restrict_revision);\n-\n-\t\tret = sequencer_make_script(stdout,\n-\t\t\t\t\t    make_script_args.argc, make_script_args.argv,\n-\t\t\t\t\t    flags);\n-\n-\t\tfree(revisions);\n-\t\targv_array_clear(&make_script_args);\n-\n-\t\treturn !!ret;\n-\t}\n-\tif ((command == SHORTEN_OIDS || command == EXPAND_OIDS) && argc == 1)\n-\t\treturn !!transform_todos(flags);\n-\tif (command == CHECK_TODO_LIST && argc == 1)\n-\t\treturn !!check_todo_list();\n-\tif (command == REARRANGE_SQUASH && argc == 1)\n-\t\treturn !!rearrange_squash();\n-\tif (command == ADD_EXEC && argc == 2)\n-\t\treturn !!sequencer_add_exec_commands(argv[1]);\n-\tif (command == EDIT_TODO && argc == 1)\n-\t\treturn !!edit_todo_list(flags);\n-\tif (command == PREPARE_BRANCH && argc == 2)\n-\t\treturn !!prepare_branch_to_be_rebased(&opts, argv[1]);\n-\tif (command == COMPLETE_ACTION && argc == 3) {\n-\t\tchar *shortrevisions = NULL;\n-\n-\t\tret = get_revision_ranges(upstream, onto, &head_hash, NULL, &shortrevisions);\n-\t\tif (ret)\n-\t\t\treturn ret;\n-\n-\t\tret = complete_action(&opts, flags, shortrevisions, argv[1], onto,\n-\t\t\t\t      head_hash, argv[2], autosquash);\n-\n-\t\tfree(shortrevisions);\n-\t\treturn !!ret;\n-\t}\n-\tif (command == INIT_BASIC_STATE) {\n-\t\tif (raw_strategies)\n-\t\t\tparse_strategy_opts(&opts, raw_strategies);\n-\n-\t\tret = get_revision_ranges(upstream, onto, &head_hash, NULL, NULL);\n-\t\tif (ret)\n-\t\t\treturn ret;\n-\n-\t\treturn !!init_basic_state(&opts, head_name, onto, head_hash);\n-\t}\n-\n-\tusage_with_options(builtin_rebase_helper_usage, options);\n-}\ndiff --git a/builtin/rebase--interactive.c b/builtin/rebase--interactive.c\nindex 9a21855ede..3ed88ac6f7 100644\n--- a/builtin/rebase--interactive.c\n+++ b/builtin/rebase--interactive.c\n@@ -140,7 +140,8 @@ int cmd_rebase__interactive(int argc, const char **argv, const char *prefix)\n \t\t*switch_to = NULL, *cmd = NULL;\n \tchar *raw_strategies = NULL;\n \tenum {\n-\t\tNONE = 0, CONTINUE, SKIP, EDIT_TODO, SHOW_CURRENT_PATCH\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@@ -161,6 +162,16 @@ int cmd_rebase__interactive(int argc, const char **argv, const char *prefix)\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@@ -199,6 +210,7 @@ int cmd_rebase__interactive(int argc, const char **argv, const char *prefix)\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@@ -231,6 +243,19 @@ 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+\t\tret = transform_todos(flags);\n+\t\tbreak;\n+\tcase CHECK_TODO_LIST:\n+\t\tret = check_todo_list();\n+\t\tbreak;\n+\tcase REARRANGE_SQUASH:\n+\t\tret = rearrange_squash();\n+\t\tbreak;\n+\tcase ADD_EXEC:\n+\t\tret = sequencer_add_exec_commands(cmd);\n+\t\tbreak;\n \tdefault:\n \t\tBUG(\"invalid command '%d'\", command);\n \t}\ndiff --git a/git-rebase--preserve-merges.sh b/git-rebase--preserve-merges.sh\nindex c214c5e4d6..afbb65765d 100644\n--- a/git-rebase--preserve-merges.sh\n+++ b/git-rebase--preserve-merges.sh\n@@ -711,11 +711,11 @@ do_rest () {\n }\n \n expand_todo_ids() {\n-\tgit rebase--helper --expand-ids\n+\tgit rebase--interactive --expand-ids\n }\n \n collapse_todo_ids() {\n-\tgit rebase--helper --shorten-ids\n+\tgit rebase--interactive --shorten-ids\n }\n \n # Switch to the branch in $into and notify it in the reflog\n@@ -876,8 +876,8 @@ init_revisions_and_shortrevisions () {\n \n complete_action() {\n \ttest -s \"$todo\" || echo noop >> \"$todo\"\n-\ttest -z \"$autosquash\" || git rebase--helper --rearrange-squash || exit\n-\ttest -n \"$cmd\" && git rebase--helper --add-exec-commands \"$cmd\"\n+\ttest -z \"$autosquash\" || git rebase--interactive --rearrange-squash || exit\n+\ttest -n \"$cmd\" && git rebase--interactive --add-exec-commands --cmd \"$cmd\"\n \n \ttodocount=$(git stripspace --strip-comments <\"$todo\" | wc -l)\n \ttodocount=${todocount##* }\n@@ -912,7 +912,7 @@ However, if you remove everything, the rebase will be aborted.\n \thas_action \"$todo\" ||\n \t\treturn 2\n \n-\tgit rebase--helper --check-todo-list || {\n+\tgit rebase--interactive --check-todo-list || {\n \t\tret=$?\n \t\tcheckout_onto\n \t\texit $ret\ndiff --git a/git.c b/git.c\nindex 19d0b6e3b8..81aabd1423 100644\n--- a/git.c\n+++ b/git.c\n@@ -519,7 +519,6 @@ static struct cmd_struct commands[] = {\n \t{ \"push\", cmd_push, RUN_SETUP },\n \t{ \"read-tree\", cmd_read_tree, RUN_SETUP | SUPPORT_SUPER_PREFIX},\n \t{ \"rebase--interactive\", cmd_rebase__interactive, RUN_SETUP | NEED_WORK_TREE },\n-\t{ \"rebase--helper\", cmd_rebase__helper, RUN_SETUP | NEED_WORK_TREE },\n \t{ \"receive-pack\", cmd_receive_pack },\n \t{ \"reflog\", cmd_reflog, RUN_SETUP },\n \t{ \"remote\", cmd_remote, RUN_SETUP },\n-- \n2.18.0\n\n"},{"id":"355136","messageId":"xmqq4lg281ms.fsf@gitster-ct.c.googlers.com","threadId":"48814","inReplyTo":"20180810165147.4779-12-alban.gruin@gmail.com","subject":"Re: [GSoC][PATCH v6 11/20] rebase -i: rewrite complete_action() in C","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2018-08-10T19:25:47Z","receivedAt":"2018-08-10T19:25:53Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Alban Gruin <alban.gruin@gmail.com> writes:\n\n> This rewrites complete_action() from shell to C.\n>\n> A new mode is added to rebase--helper (`--complete-action`), as well as\n> a new flag (`--autosquash`).\n>\n> Finally, complete_action() is stripped from git-rebase--interactive.sh.\n>\n> The original complete_action() would return the code 2 when the todo\n> list contained no actions.  This was a special case for rebase -i and\n> -p; git-rebase.sh would then apply the autostash, delete the state\n> directory, and die with the message \"Nothing to do\".  This cleanup is\n> rewritten in C instead of returning 2.  As rebase -i no longer returns\n> 2, the comment describing this behaviour in git-rebase.sh is updated to\n> reflect this change.\n\nHmph.  It is easy enough to do the clean-up ourselves in this code,\ninstead of asking the caller to do so.  On the other hand, stashing\nof local changes is done by the caller, so it feels a bit strange\nway to divide the labor between the two parts.\n\nOther than that design choice, the patch itself looks reasonable and\na fairly faithful reimplementation of what the scripted one did.\n\n"},{"id":"355139","messageId":"453e3f0c-6c68-71e1-0338-185f129bb778@gmail.com","threadId":"48814","inReplyTo":"xmqq4lg281ms.fsf@gitster-ct.c.googlers.com","subject":"Re: [GSoC][PATCH v6 11/20] rebase -i: rewrite complete_action() in C","fromName":"Alban Gruin","fromEmail":"alban.gruin@gmail.com","sentAt":"2018-08-10T19:36:48Z","receivedAt":"2018-08-10T19:36:53Z","isPatch":true,"sender":{"key":"alban.gruin@gmail.com","avatar":"https://avatars.githubusercontent.com/u/6310153?v=4"},"body":"Hi Junio,\n\nLe 10/08/2018 à 21:25, Junio C Hamano a écrit :\n> Alban Gruin <alban.gruin@gmail.com> writes:\n> \n>> This rewrites complete_action() from shell to C.\n>>\n>> A new mode is added to rebase--helper (`--complete-action`), as well as\n>> a new flag (`--autosquash`).\n>>\n>> Finally, complete_action() is stripped from git-rebase--interactive.sh.\n>>\n>> The original complete_action() would return the code 2 when the todo\n>> list contained no actions.  This was a special case for rebase -i and\n>> -p; git-rebase.sh would then apply the autostash, delete the state\n>> directory, and die with the message \"Nothing to do\".  This cleanup is\n>> rewritten in C instead of returning 2.  As rebase -i no longer returns\n>> 2, the comment describing this behaviour in git-rebase.sh is updated to\n>> reflect this change.\n> \n> Hmph.  It is easy enough to do the clean-up ourselves in this code,\n> instead of asking the caller to do so.  On the other hand, stashing\n> of local changes is done by the caller, so it feels a bit strange\n> way to divide the labor between the two parts.\n> \n> Other than that design choice, the patch itself looks reasonable and\n> a fairly faithful reimplementation of what the scripted one did.\n> \n\nThis was the behaviour of the old complete_action().  The new one cleans\nup by itself; this is the\napply_autostash()/sequencer_remove_state()/todo_list_release() dance\ndone at three places inside complete_action(), and has not changed since\nv3[0].\n\nMaybe I misunderstood what you said?\n\n[0]\nhttps://public-inbox.org/git/20180710121557.6698-11-alban.gruin@gmail.com/\n\nCheers,\nAlban\n\n"},{"id":"355149","messageId":"xmqqva8i6k7b.fsf@gitster-ct.c.googlers.com","threadId":"48814","inReplyTo":"453e3f0c-6c68-71e1-0338-185f129bb778@gmail.com","subject":"Re: [GSoC][PATCH v6 11/20] rebase -i: rewrite complete_action() in C","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2018-08-10T20:27:36Z","receivedAt":"2018-08-10T20:27:42Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Alban Gruin <alban.gruin@gmail.com> writes:\n\n>> Hmph.  It is easy enough to do the clean-up ourselves in this code,\n>> instead of asking the caller to do so.  On the other hand, stashing\n>> of local changes is done by the caller, so it feels a bit strange\n>> way to divide the labor between the two parts.\n>> \n>> Other than that design choice, the patch itself looks reasonable and\n>> a fairly faithful reimplementation of what the scripted one did.\n>> \n>\n> This was the behaviour of the old complete_action().  The new one cleans\n> up by itself; this is the\n> apply_autostash()/sequencer_remove_state()/todo_list_release() dance\n> done at three places inside complete_action(), and has not changed since\n> v3[0].\n>\n> Maybe I misunderstood what you said?\n\nI am not all that interested in comparing your previous attempts; I\nam more focused on the end result of applying these proposed\nchanges.\n\nIn the end result, IIUC, stashing away the local modification before\nrebasing happens is done in the caller (i.e. \"git rebase\" proper)\nand the caller is still prepared to do the clean-up of applying that\nlocal modification back.  If \"rebase -i\" did the stashing away at\nthe beginning, and cleaning up before it gives back control, that\nwould have been one coherent division of labor.  Or if \"rebase -i\"\ndid neither and let \"rebase\" proper do both, that also would have\nbeen another coherent division of labor.  Making the caller,\n\"rebase\" proper, responsible for preparing the data necessary to\nlater come back (i.e. stashing away the local mods) while letting\nthe callee, \"rebase -i\", consume that data by applying the stash,\nfelt a strange way to divide the labor between the two parts.\n\nThat is what I meant.\n\nIf we are planning to make all the backend responsible for stashing\naway before they run and applying the stash after they are done,\nthen it might make sense to have the application side on the backend\nas the first step.  But if what you need to do to stash away local\nchanges and what you need to do to reapply the stash is the same for\nall backends, wouldn't it make more sense to have the logic in the\ncaller side?\n\n\n"},{"id":"355158","messageId":"d26636f9-8cf9-3bfd-0fd5-1ab9ea3da169@gmail.com","threadId":"48814","inReplyTo":"xmqqva8i6k7b.fsf@gitster-ct.c.googlers.com","subject":"Re: [GSoC][PATCH v6 11/20] rebase -i: rewrite complete_action() in C","fromName":"Alban Gruin","fromEmail":"alban.gruin@gmail.com","sentAt":"2018-08-10T21:15:47Z","receivedAt":"2018-08-10T21:15:52Z","isPatch":true,"sender":{"key":"alban.gruin@gmail.com","avatar":"https://avatars.githubusercontent.com/u/6310153?v=4"},"body":"Le 10/08/2018 à 22:27, Junio C Hamano a écrit :\n> If we are planning to make all the backend responsible for stashing\n> away before they run and applying the stash after they are done,\n> then it might make sense to have the application side on the backend\n> as the first step.  But if what you need to do to stash away local\n> changes and what you need to do to reapply the stash is the same for\n> all backends, wouldn't it make more sense to have the logic in the\n> caller side?\n> \n> \n\nYes.\n\n"},{"id":"355368","messageId":"CACsJy8B=4kKa5ZjQ6dL2H9LToOGdu2OzmexwpWkS+Tayphv1XA@mail.gmail.com","threadId":"48814","inReplyTo":"20180810165147.4779-1-alban.gruin@gmail.com","subject":"Re: [GSoC][PATCH v6 00/20] rebase -i: rewrite in C","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2018-08-13T16:06:43Z","receivedAt":"2018-08-13T16:07:12Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Fri, Aug 10, 2018 at 6:54 PM Alban Gruin <alban.gruin@gmail.com> wrote:\n>\n> This patch series rewrite the interactive rebase from shell to C.\n\nI was running some tests on 'pu' and ran git-rebase--interactive\nwithout arguments because a test failed and I was wondering if it was\nme. It showed this\n\n> ~/w/ztemp $ ./git-rebase--interactive\nfatal: ambiguous argument\n'(null)...97004f10c7e6d1e784eb8a62bebdf529cd3b81f5': unknown revision\nor path not in the working tree.\nfatal: Use '--' to separate paths from revisions, like this:\nfatal: 'git <command> [<revision>...] -- [<file>...]'\n\nThe \"(null)\" should not be printed out because it could actually\nsegfault on some other platforms. Just wanted to let you know.\nApologies if it's already reported and fixed, I didn't really read\nthis series.\n-- \nDuy\n"},{"id":"355478","messageId":"2126644.CIUTlRnjVv@andromeda","threadId":"48814","inReplyTo":"CACsJy8B=4kKa5ZjQ6dL2H9LToOGdu2OzmexwpWkS+Tayphv1XA@mail.gmail.com","subject":"Re: [GSoC][PATCH v6 00/20] rebase -i: rewrite in C","fromName":"Alban Gruin","fromEmail":"alban.gruin@gmail.com","sentAt":"2018-08-13T20:47:07Z","receivedAt":"2018-08-13T20:47:20Z","isPatch":true,"sender":{"key":"alban.gruin@gmail.com","avatar":"https://avatars.githubusercontent.com/u/6310153?v=4"},"body":"Hi Duy,\n\nLe 13/08/2018 à 18:06, Duy Nguyen a écrit :\n> On Fri, Aug 10, 2018 at 6:54 PM Alban Gruin <alban.gruin@gmail.com> wrote:\n> > This patch series rewrite the interactive rebase from shell to C.\n> \n> I was running some tests on 'pu' and ran git-rebase--interactive\n> without arguments because a test failed and I was wondering if it was\n> me. It showed this\n> \n> > ~/w/ztemp $ ./git-rebase--interactive\n> \n> fatal: ambiguous argument\n> '(null)...97004f10c7e6d1e784eb8a62bebdf529cd3b81f5': unknown revision\n> or path not in the working tree.\n> fatal: Use '--' to separate paths from revisions, like this:\n> fatal: 'git <command> [<revision>...] -- [<file>...]'\n> \n> The \"(null)\" should not be printed out because it could actually\n> segfault on some other platforms. Just wanted to let you know.\n> Apologies if it's already reported and fixed, I didn't really read\n> this series.\n\nThanks for the heads up, I will send a fix soon.\n\nI don’t know what you were trying to do with git-rebase--interactive, but it \nshould not be called directly.  Instead, you should call git-rebase -i.\n\nCheers,\nAlban\n\n\n\n\n"},{"id":"355902","messageId":"330b949f-f4ce-5e61-b1f6-4dc0c83a7d1a@talktalk.net","threadId":"48814","inReplyTo":"20180810165147.4779-12-alban.gruin@gmail.com","subject":"Re: [GSoC][PATCH v6 11/20] rebase -i: rewrite complete_action() in C","fromName":"Phillip Wood","fromEmail":"phillip.wood@talktalk.net","sentAt":"2018-08-17T13:16:32Z","receivedAt":"2018-08-17T13:16:37Z","isPatch":true,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"Hi Alban\n\nThe interdiff from v5 to v6 looks good, I think the changes you have\nmade the the other patches in this series are fine, I've just got a\ncouple of small comments below about this one.\n\nBest Wishes\n\nPhillip\n\nOn 10/08/2018 17:51, Alban Gruin wrote:\n> \n> This rewrites complete_action() from shell to C.\n> \n> A new mode is added to rebase--helper (`--complete-action`), as well as\n> a new flag (`--autosquash`).\n> \n> Finally, complete_action() is stripped from git-rebase--interactive.sh.\n> \n> The original complete_action() would return the code 2 when the todo\n> list contained no actions.  This was a special case for rebase -i and\n> -p; git-rebase.sh would then apply the autostash, delete the state\n> directory, and die with the message \"Nothing to do\".  This cleanup is\n> rewritten in C instead of returning 2.  As rebase -i no longer returns\n> 2, the comment describing this behaviour in git-rebase.sh is updated to\n> reflect this change.\n> \n> The message \"Nothing to do\" is now printed with error(), and so becomes\n> \"error: nothing to do\".  Some tests in t3404 check this value, so they\n> are updated to fit this change.\n> \n> The first check might seem useless as we write \"noop\" to the todo list\n> if it is empty.  Actually, the todo list might contain commented\n> commands (ie. empty commits).  In this case, complete_action() won’t\n> write \"noop\", and will abort without starting the editor.\n> \n> Signed-off-by: Alban Gruin <alban.gruin@gmail.com>\n> ---\n>  builtin/rebase--helper.c      |  12 +++-\n>  git-rebase--interactive.sh    |  53 ++----------------\n>  git-rebase.sh                 |   2 +-\n>  sequencer.c                   | 102 ++++++++++++++++++++++++++++++++++\n>  sequencer.h                   |   4 ++\n>  t/t3404-rebase-interactive.sh |   2 +-\n>  6 files changed, 122 insertions(+), 53 deletions(-)\n> \n> diff --git a/builtin/rebase--helper.c b/builtin/rebase--helper.c\n> index bed3dd2b95..01b3333958 100644\n> --- a/builtin/rebase--helper.c\n> +++ b/builtin/rebase--helper.c\n> @@ -13,13 +13,13 @@ static const char * const builtin_rebase_helper_usage[] = {\n>  int cmd_rebase__helper(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;\n> +\tunsigned flags = 0, keep_empty = 0, rebase_merges = 0, autosquash = 0;\n>  \tint abbreviate_commands = 0, rebase_cousins = -1;\n>  \tenum {\n>  \t\tCONTINUE = 1, ABORT, MAKE_SCRIPT, SHORTEN_OIDS, EXPAND_OIDS,\n>  \t\tCHECK_TODO_LIST, SKIP_UNNECESSARY_PICKS, REARRANGE_SQUASH,\n>  \t\tADD_EXEC, APPEND_TODO_HELP, EDIT_TODO, PREPARE_BRANCH,\n> -\t\tCHECKOUT_ONTO\n> +\t\tCHECKOUT_ONTO, COMPLETE_ACTION\n>  \t} command = 0;\n>  \tstruct option options[] = {\n>  \t\tOPT_BOOL(0, \"ff\", &opts.allow_ff, N_(\"allow fast-forward\")),\n> @@ -29,6 +29,8 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\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__VERBOSE(&opts.verbose, N_(\"be verbose\")),\n>  \t\tOPT_CMDMODE(0, \"continue\", &command, N_(\"continue rebase\"),\n>  \t\t\t\tCONTINUE),\n> @@ -57,6 +59,8 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\n>  \t\t\t    N_(\"prepare the branch to be rebased\"), PREPARE_BRANCH),\n>  \t\tOPT_CMDMODE(0, \"checkout-onto\", &command,\n>  \t\t\t    N_(\"checkout a commit\"), CHECKOUT_ONTO),\n> +\t\tOPT_CMDMODE(0, \"complete-action\", &command,\n> +\t\t\t    N_(\"complete the action\"), COMPLETE_ACTION),\n>  \t\tOPT_END()\n>  \t};\n>  \n> @@ -110,5 +114,9 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\n>  \t\treturn !!prepare_branch_to_be_rebased(&opts, argv[1]);\n>  \tif (command == CHECKOUT_ONTO && argc == 4)\n>  \t\treturn !!checkout_onto(&opts, argv[1], argv[2], argv[3]);\n> +\tif (command == COMPLETE_ACTION && argc == 6)\n> +\t\treturn !!complete_action(&opts, flags, argv[1], argv[2], argv[3],\n> +\t\t\t\t\t argv[4], argv[5], autosquash);\n> +\n>  \tusage_with_options(builtin_rebase_helper_usage, options);\n>  }\n> diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\n> index b68f108f28..59dc4888a6 100644\n> --- a/git-rebase--interactive.sh\n> +++ b/git-rebase--interactive.sh\n> @@ -127,54 +127,6 @@ init_revisions_and_shortrevisions () {\n>  \tfi\n>  }\n>  \n> -complete_action() {\n> -\ttest -s \"$todo\" || echo noop >> \"$todo\"\n> -\ttest -z \"$autosquash\" || git rebase--helper --rearrange-squash || exit\n> -\ttest -n \"$cmd\" && git rebase--helper --add-exec-commands \"$cmd\"\n> -\n> -\ttodocount=$(git stripspace --strip-comments <\"$todo\" | wc -l)\n> -\ttodocount=${todocount##* }\n> -\n> -cat >>\"$todo\" <<EOF\n> -\n> -$comment_char $(eval_ngettext \\\n> -\t\"Rebase \\$shortrevisions onto \\$shortonto (\\$todocount command)\" \\\n> -\t\"Rebase \\$shortrevisions onto \\$shortonto (\\$todocount commands)\" \\\n> -\t\"$todocount\")\n> -EOF\n> -\tgit rebase--helper --append-todo-help ${keep_empty:+--keep-empty}\n> -\n> -\thas_action \"$todo\" ||\n> -\t\treturn 2\n> -\n> -\tcp \"$todo\" \"$todo\".backup\n> -\tcollapse_todo_ids\n> -\tgit_sequence_editor \"$todo\" ||\n> -\t\tdie_abort \"$(gettext \"Could not execute editor\")\"\n> -\n> -\thas_action \"$todo\" ||\n> -\t\treturn 2\n> -\n> -\tgit rebase--helper --check-todo-list || {\n> -\t\tret=$?\n> -\t\tgit rebase--helper --checkout-onto \"$onto_name\" \"$onto\" \\\n> -\t\t    \"$orig_head\" ${verbose:+--verbose}\n> -\t\texit $ret\n> -\t}\n> -\n> -\texpand_todo_ids\n> -\n> -\ttest -n \"$force_rebase\" ||\n> -\tonto=\"$(git rebase--helper --skip-unnecessary-picks)\" ||\n> -\tdie \"Could not skip unnecessary pick commands\"\n> -\n> -\tgit rebase--helper --checkout-onto \"$onto_name\" \"$onto\" \"$orig_head\" \\\n> -\t    ${verbose:+--verbose}\n> -\trequire_clean_work_tree \"rebase\"\n> -\texec git rebase--helper ${force_rebase:+--no-ff} $allow_empty_message \\\n> -\t     --continue\n> -}\n> -\n>  git_rebase__interactive () {\n>  \tinitiate_action \"$action\"\n>  \tret=$?\n> @@ -193,5 +145,8 @@ git_rebase__interactive () {\n>  \t\t$revisions ${restrict_revision+^$restrict_revision} >\"$todo\" ||\n>  \tdie \"$(gettext \"Could not generate todo list\")\"\n>  \n> -\tcomplete_action\n> +\texec git rebase--helper --complete-action \"$shortrevisions\" \"$onto_name\" \\\n> +\t\t\"$shortonto\" \"$orig_head\" \"$cmd\" $allow_empty_message \\\n> +\t\t${autosquash:+--autosquash} ${keep_empty:+--keep-empty} \\\n> +\t\t${verbose:+--verbose} ${force_rebase:+--no-ff}\n>  }\n> diff --git a/git-rebase.sh b/git-rebase.sh\n> index 7973447645..51a6db7daa 100755\n> --- a/git-rebase.sh\n> +++ b/git-rebase.sh\n> @@ -219,7 +219,7 @@ run_specific_rebase () {\n>  \tif test $ret -eq 0\n>  \tthen\n>  \t\tfinish_rebase\n> -\telif test $ret -eq 2 # special exit status for rebase -i\n> +\telif test $ret -eq 2 # special exit status for rebase -p\n>  \tthen\n>  \t\tapply_autostash &&\n>  \t\trm -rf \"$state_dir\" &&\n> diff --git a/sequencer.c b/sequencer.c\n> index a56a781539..ae1f44de2f 100644\n> --- a/sequencer.c\n> +++ b/sequencer.c\n> @@ -30,6 +30,7 @@\n>  #include \"oidset.h\"\n>  #include \"commit-slab.h\"\n>  #include \"alias.h\"\n> +#include \"rebase-interactive.h\"\n>  \n>  #define GIT_REFLOG_ACTION \"GIT_REFLOG_ACTION\"\n>  \n> @@ -53,6 +54,9 @@ static GIT_PATH_FUNC(rebase_path, \"rebase-merge\")\n>   * file and written to the tail of 'done'.\n>   */\n>  GIT_PATH_FUNC(rebase_path_todo, \"rebase-merge/git-rebase-todo\")\n> +static GIT_PATH_FUNC(rebase_path_todo_backup,\n> +\t\t     \"rebase-merge/git-rebase-todo.backup\")\n> +\n>  /*\n>   * The rebase command lines that have already been processed. A line\n>   * is moved here when it is first handled, before any associated user\n> @@ -4499,6 +4503,104 @@ int skip_unnecessary_picks(struct object_id *output_oid)\n>  \treturn 0;\n>  }\n>  \n> +int complete_action(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, const char *cmd,\n> +\t\t    unsigned autosquash)\n> +{\n> +\tconst char *shortonto, *todo_file = rebase_path_todo();\n> +\tstruct todo_list todo_list = TODO_LIST_INIT;\n> +\tstruct strbuf *buf = &(todo_list.buf);\n> +\tstruct object_id oid;\n> +\tstruct stat st;\n> +\n> +\tget_oid(onto, &oid);\n> +\tshortonto = find_unique_abbrev(&oid, DEFAULT_ABBREV);\n> +\n> +\tif (!lstat(todo_file, &st) && st.st_size == 0 &&\n> +\t    write_message(\"noop\\n\", 5, todo_file, 0))\n> +\t\treturn error_errno(_(\"could not write '%s'\"), todo_file);\n> +\n> +\tif (autosquash && rearrange_squash())\n> +\t\treturn -1;\n> +\n> +\tif (cmd && *cmd)\n> +\t\tsequencer_add_exec_commands(cmd);\n> +\n> +\tif (strbuf_read_file(buf, todo_file, 0) < 0)\n> +\t\treturn error_errno(_(\"could not read '%s'.\"), todo_file);\n> +\n> +\tif (parse_insn_buffer(buf->buf, &todo_list)) {\n> +\t\ttodo_list_release(&todo_list);\n> +\t\treturn error(_(\"unusable todo list: '%s'\"), todo_file);\n> +\t}\n> +\n> +\tif (count_commands(&todo_list) == 0) {\n> +\t\tapply_autostash(opts);\n> +\t\tsequencer_remove_state(opts);\n> +\t\ttodo_list_release(&todo_list);\n> +\n> +\t\treturn error(_(\"nothing to do\"));\n> +\t}\n> +\n> +\tstrbuf_addch(buf, '\\n');\n> +\tstrbuf_commented_addf(buf, Q_(\"Rebase %s onto %s (%d command)\",\n> +\t\t\t\t      \"Rebase %s onto %s (%d commands)\",\n> +\t\t\t\t      count_commands(&todo_list)),\n> +\t\t\t      shortrevisions, shortonto, count_commands(&todo_list));\n> +\tappend_todo_help(0, flags & TODO_LIST_KEEP_EMPTY, buf);\n> +\n> +\tif (write_message(buf->buf, buf->len, todo_file, 0)) {\n> +\t\ttodo_list_release(&todo_list);\n> +\t\treturn error_errno(_(\"could not write '%s'\"), todo_file);\n> +\t}\n\nwrite_message() prints an error message if it fails so I think this call\nto error_errno() is not needed\n\n> +\n> +\tif (copy_file(rebase_path_todo_backup(), todo_file, 0666))\n> +\t\treturn error(_(\"could not copy '%s' to '%s'.\"), todo_file,\n> +\t\t\t     rebase_path_todo_backup());\n> +\n> +\tif (transform_todos(flags | TODO_LIST_SHORTEN_IDS))\n> +\t\treturn error(_(\"could not transform the todo list\"));\n> +\n> +\tstrbuf_reset(buf);\n> +\n> +\tif (launch_sequence_editor(todo_file, buf, NULL)) {\n> +\t\tapply_autostash(opts);\n> +\t\tsequencer_remove_state(opts);\n> +\t\ttodo_list_release(&todo_list);\n> +\n> +\t\treturn -1;\n> +\t}\n> +\n> +\tstrbuf_stripspace(buf, 1);\n> +\tif (buf->len == 0) {\n> +\t\tapply_autostash(opts);\n> +\t\tsequencer_remove_state(opts);\n> +\t\ttodo_list_release(&todo_list);\n> +\n> +\t\treturn error(_(\"nothing to do\"));\n> +\t}\n> +\n> +\ttodo_list_release(&todo_list);\n> +\n> +\tif (check_todo_list()) {\n> +\t\tcheckout_onto(opts, onto_name, onto, orig_head);\n> +\t\treturn -1;\n> +\t}\n> +\n> +\tif (transform_todos(flags & ~(TODO_LIST_SHORTEN_IDS)))\n> +\t\treturn error(_(\"could not transform the todo list\"));\n> +\n> +\tif (opts->allow_ff && skip_unnecessary_picks(&oid))\n> +\t\treturn error(_(\"could not skip unnecessary pick commands\"));\n> +\n> +\tcheckout_onto(opts, onto_name, oid_to_hex(&oid), orig_head);\n\ncheckout_onto() can fail if it would overwrite untracked files, so do we\nneed to check its return value here?\n\n> +\tif (require_clean_work_tree(\"rebase\", \"\", 1, 1))\n> +\t\treturn -1;\n> +\n> +\treturn sequencer_continue(opts);\n> +}\n> +\n>  struct subject2item_entry {\n>  \tstruct hashmap_entry entry;\n>  \tint i;\n> diff --git a/sequencer.h b/sequencer.h\n> index fcbcd246c2..d58766c6d7 100644\n> --- a/sequencer.h\n> +++ b/sequencer.h\n> @@ -92,6 +92,10 @@ int transform_todos(unsigned flags);\n>  enum missing_commit_check_level get_missing_commit_check_level(void);\n>  int check_todo_list(void);\n>  int skip_unnecessary_picks(struct object_id *output_oid);\n> +int complete_action(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, const char *cmd,\n> +\t\t    unsigned autosquash);\n>  int rearrange_squash(void);\n>  \n>  extern const char sign_off_header[];\n> diff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh\n> index 496d88d7d6..12d3ed8396 100755\n> --- a/t/t3404-rebase-interactive.sh\n> +++ b/t/t3404-rebase-interactive.sh\n> @@ -76,7 +76,7 @@ test_expect_success 'rebase --keep-empty' '\n>  '\n>  \n>  cat > expect <<EOF\n> -Nothing to do\n> +error: nothing to do\n>  EOF\n>  \n>  test_expect_success 'rebase -i with empty HEAD' '\n> \n\n"},{"id":"355904","messageId":"3da3ce19-38f8-0c46-47a1-9510f203b65f@talktalk.net","threadId":"48814","inReplyTo":"20180810165147.4779-16-alban.gruin@gmail.com","subject":"Re: [GSoC][PATCH v6 15/20] rebase -i: rewrite write_basic_state() in C","fromName":"Phillip Wood","fromEmail":"phillip.wood@talktalk.net","sentAt":"2018-08-17T13:27:01Z","receivedAt":"2018-08-17T13:27:09Z","isPatch":true,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"On 10/08/2018 17:51, Alban Gruin wrote:\n> This rewrites write_basic_state() from git-rebase.sh in C.  This is the\n> first step in the conversion of init_basic_state(), hence the mode in\n> rebase--helper.c is called INIT_BASIC_STATE.  init_basic_state() will be\n> converted in the next commit.\n> \n> The part of read_strategy_opts() that parses the stategy options is\n> moved to a new function to allow its use in rebase--helper.c.\n> \n> Finally, the call to write_basic_state() is removed from\n> git-rebase--interactive.sh, replaced by a call to `--init-basic-state`.\n> \n> Signed-off-by: Alban Gruin <alban.gruin@gmail.com>\n> ---\n> No changes since v5.\n> \n>  builtin/rebase--helper.c   | 28 +++++++++++++-\n>  git-rebase--interactive.sh |  7 +++-\n>  sequencer.c                | 77 ++++++++++++++++++++++++++++++++------\n>  sequencer.h                |  4 ++\n>  4 files changed, 102 insertions(+), 14 deletions(-)\n> \n> diff --git a/builtin/rebase--helper.c b/builtin/rebase--helper.c\n> index 0716bbfd78..63c5086e42 100644\n> --- a/builtin/rebase--helper.c\n> +++ b/builtin/rebase--helper.c\n> @@ -5,6 +5,8 @@\n>  #include \"sequencer.h\"\n>  #include \"rebase-interactive.h\"\n>  #include \"argv-array.h\"\n> +#include \"rerere.h\"\n> +#include \"alias.h\"\n>  \n>  static GIT_PATH_FUNC(path_squash_onto, \"rebase-merge/squash-onto\")\n>  \n> @@ -53,11 +55,12 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\n>  \tunsigned flags = 0, keep_empty = 0, rebase_merges = 0, autosquash = 0;\n>  \tint abbreviate_commands = 0, rebase_cousins = -1, ret;\n>  \tconst char *head_hash = NULL, *onto = NULL, *restrict_revision = NULL,\n> -\t\t*squash_onto = NULL, *upstream = NULL;\n> +\t\t*squash_onto = NULL, *upstream = NULL, *head_name = NULL;\n> +\tchar *raw_strategies = NULL;\n>  \tenum {\n>  \t\tCONTINUE = 1, ABORT, MAKE_SCRIPT, SHORTEN_OIDS, EXPAND_OIDS,\n>  \t\tCHECK_TODO_LIST, REARRANGE_SQUASH, ADD_EXEC, EDIT_TODO, PREPARE_BRANCH,\n> -\t\tCOMPLETE_ACTION\n> +\t\tCOMPLETE_ACTION, INIT_BASIC_STATE\n>  \t} command = 0;\n>  \tstruct option options[] = {\n>  \t\tOPT_BOOL(0, \"ff\", &opts.allow_ff, N_(\"allow fast-forward\")),\n> @@ -69,6 +72,7 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\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\tCONTINUE),\n> @@ -93,6 +97,8 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\n>  \t\t\t    N_(\"prepare the branch to be rebased\"), PREPARE_BRANCH),\n>  \t\tOPT_CMDMODE(0, \"complete-action\", &command,\n>  \t\t\t    N_(\"complete the action\"), COMPLETE_ACTION),\n> +\t\tOPT_CMDMODE(0, \"init-basic-state\", &command,\n> +\t\t\t    N_(\"initialise the rebase state\"), INIT_BASIC_STATE),\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> @@ -100,6 +106,14 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\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\tOPT_STRING('S', \"gpg-sign\", &opts.gpg_sign, N_(\"gpg-sign\"),\n> +\t\t\t   N_(\"GPG-sign commits\")),\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_RERERE_AUTOUPDATE(&opts.allow_rerere_auto),\n>  \t\tOPT_END()\n>  \t};\n>  \n> @@ -176,6 +190,16 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\n>  \t\tfree(shortrevisions);\n>  \t\treturn !!ret;\n>  \t}\n> +\tif (command == INIT_BASIC_STATE) {\n> +\t\tif (raw_strategies)\n> +\t\t\tparse_strategy_opts(&opts, raw_strategies);\n> +\n> +\t\tret = get_revision_ranges(upstream, onto, &head_hash, NULL, NULL);\n> +\t\tif (ret)\n> +\t\t\treturn ret;\n> +\n> +\t\treturn !!write_basic_state(&opts, head_name, onto, head_hash);\n> +\t}\n>  \n>  \tusage_with_options(builtin_rebase_helper_usage, options);\n>  }\n> diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\n> index 08e9a21c2f..6367da66e2 100644\n> --- a/git-rebase--interactive.sh\n> +++ b/git-rebase--interactive.sh\n> @@ -57,7 +57,6 @@ init_basic_state () {\n>  \trm -f \"$(git rev-parse --git-path REBASE_HEAD)\"\n>  \n>  \t: > \"$state_dir\"/interactive || die \"$(gettext \"Could not mark as interactive\")\"\n> -\twrite_basic_state\n>  }\n>  \n>  git_rebase__interactive () {\n> @@ -70,6 +69,12 @@ git_rebase__interactive () {\n>  \tgit rebase--helper --prepare-branch \"$switch_to\" ${verbose:+--verbose}\n>  \tinit_basic_state\n>  \n> +\tgit rebase--helper --init-basic-state ${upstream:+--upstream \"$upstream\"} \\\n> +\t\t${onto:+--onto \"$onto\"} ${head_name:+--head-name \"$head_name\"} \\\n> +\t\t${verbose:+--verbose} ${strategy:+--strategy \"$strategy\"} \\\n> +\t\t${strategy_opts:+--strategy-opts=\"$strategy_opts\"} \\\n> +\t\t\"$allow_rerere_autoupdate\" \"$gpg_sign_opt\" \"$signoff\" || exit\n> +\n>  \tgit rebase--helper --make-script ${keep_empty:+--keep-empty} \\\n>  \t\t${rebase_merges:+--rebase-merges} \\\n>  \t\t${rebase_cousins:+--rebase-cousins} \\\n> diff --git a/sequencer.c b/sequencer.c\n> index 3800439c10..beff749904 100644\n> --- a/sequencer.c\n> +++ b/sequencer.c\n> @@ -144,7 +144,7 @@ static GIT_PATH_FUNC(rebase_path_refs_to_delete, \"rebase-merge/refs-to-delete\")\n>  \n>  /*\n>   * The following files are written by git-rebase just after parsing the\n> - * command-line (and are only consumed, not modified, by the sequencer).\n> + * command-line.\n>   */\n>  static GIT_PATH_FUNC(rebase_path_gpg_sign_opt, \"rebase-merge/gpg_sign_opt\")\n>  static GIT_PATH_FUNC(rebase_path_orig_head, \"rebase-merge/orig-head\")\n> @@ -156,6 +156,7 @@ static GIT_PATH_FUNC(rebase_path_autostash, \"rebase-merge/autostash\")\n>  static GIT_PATH_FUNC(rebase_path_strategy, \"rebase-merge/strategy\")\n>  static GIT_PATH_FUNC(rebase_path_strategy_opts, \"rebase-merge/strategy_opts\")\n>  static GIT_PATH_FUNC(rebase_path_allow_rerere_autoupdate, \"rebase-merge/allow_rerere_autoupdate\")\n> +static GIT_PATH_FUNC(rebase_path_quiet, \"rebase-merge/quiet\")\n>  \n>  static int git_sequencer_config(const char *k, const char *v, void *cb)\n>  {\n> @@ -2205,21 +2206,14 @@ static int populate_opts_cb(const char *key, const char *value, void *data)\n>  \treturn 0;\n>  }\n>  \n> -static void read_strategy_opts(struct replay_opts *opts, struct strbuf *buf)\n> +void parse_strategy_opts(struct replay_opts *opts, char *raw_opts)\n>  {\n>  \tint i;\n> -\tchar *strategy_opts_string;\n> +\tchar *strategy_opts_string = raw_opts;\n>  \n> -\tstrbuf_reset(buf);\n> -\tif (!read_oneliner(buf, rebase_path_strategy(), 0))\n> -\t\treturn;\n> -\topts->strategy = strbuf_detach(buf, NULL);\n> -\tif (!read_oneliner(buf, rebase_path_strategy_opts(), 0))\n> -\t\treturn;\n> -\n> -\tstrategy_opts_string = buf->buf;\n>  \tif (*strategy_opts_string == ' ')\n>  \t\tstrategy_opts_string++;\n> +\n>  \topts->xopts_nr = split_cmdline(strategy_opts_string,\n>  \t\t\t\t       (const char ***)&opts->xopts);\n>  \tfor (i = 0; i < opts->xopts_nr; i++) {\n> @@ -2230,6 +2224,18 @@ static void read_strategy_opts(struct replay_opts *opts, struct strbuf *buf)\n>  \t}\n>  }\n>  \n> +static void read_strategy_opts(struct replay_opts *opts, struct strbuf *buf)\n> +{\n> +\tstrbuf_reset(buf);\n> +\tif (!read_oneliner(buf, rebase_path_strategy(), 0))\n> +\t\treturn;\n> +\topts->strategy = strbuf_detach(buf, NULL);\n> +\tif (!read_oneliner(buf, rebase_path_strategy_opts(), 0))\n> +\t\treturn;\n> +\n> +\tparse_strategy_opts(opts, buf->buf);\n> +}\n> +\n>  static int read_populate_opts(struct replay_opts *opts)\n>  {\n>  \tif (is_rebase_i(opts)) {\n> @@ -2297,6 +2303,55 @@ static int read_populate_opts(struct replay_opts *opts)\n>  \treturn 0;\n>  }\n>  \n> +static void write_strategy_opts(struct replay_opts *opts)\n> +{\n> +\tint i;\n> +\tstruct strbuf buf = STRBUF_INIT;\n> +\n> +\tfor (i = 0; i < opts->xopts_nr; ++i)\n> +\t\tstrbuf_addf(&buf, \" --%s\", opts->xopts[i]);\n> +\n> +\twrite_file(rebase_path_strategy_opts(), \"%s\\n\", buf.buf);\n> +\tstrbuf_release(&buf);\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\nIf this is going to live in libgit then I think it could do with a less\ngeneric name such as write_rebase_state() so it is clear which command\nthe function is writing the state for.\n\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\nwrite_file() can call die() which isn't encouraged for code in libgit.\nI'm not sure how much it matters in this case. Rewriting all these as\n\n\tif (head_name && write_message(onto, strlen(onto), rebase_path_onto(), 1))\n\t\treturn -1;\n\nis a bit tedious. An alternative would be it leave it for now and in the\nlonger term move this function (and the ones above which I've just\nnoticed also call write_file()) to in builtin/rebase.c (assuming that\nbuiltin/rebase--interactive.c and builtin/rebase.c get merged once\nthey're finalized - I'm not sure if there is a plan for that or not.)\n\nBest Wishes\n\nPhillip\n\n> +\tif (onto)\n> +\t\twrite_file(rebase_path_onto(), \"%s\\n\", onto);\n> +\tif (orig_head)\n> +\t\twrite_file(rebase_path_orig_head(), \"%s\\n\", orig_head);\n> +\n> +\tif (quiet)\n> +\t\twrite_file(rebase_path_quiet(), \"%s\\n\", quiet);\n> +\telse\n> +\t\twrite_file(rebase_path_quiet(), \"\\n\");\n> +\n> +\tif (opts->verbose)\n> +\t\twrite_file(rebase_path_verbose(), \"\");\n> +\tif (opts->strategy)\n> +\t\twrite_file(rebase_path_strategy(), \"%s\\n\", opts->strategy);\n> +\tif (opts->xopts_nr > 0)\n> +\t\twrite_strategy_opts(opts);\n> +\n> +\tif (opts->allow_rerere_auto == RERERE_AUTOUPDATE)\n> +\t\twrite_file(rebase_path_allow_rerere_autoupdate(), \"--rerere-autoupdate\\n\");\n> +\telse if (opts->allow_rerere_auto == RERERE_NOAUTOUPDATE)\n> +\t\twrite_file(rebase_path_allow_rerere_autoupdate(), \"--no-rerere-autoupdate\\n\");\n> +\n> +\tif (opts->gpg_sign)\n> +\t\twrite_file(rebase_path_gpg_sign_opt(), \"-S%s\\n\", opts->gpg_sign);\n> +\tif (opts->signoff)\n> +\t\twrite_file(rebase_path_signoff(), \"--signoff\\n\");\n> +\n> +\treturn 0;\n> +}\n> +\n>  static int walk_revs_populate_todo(struct todo_list *todo_list,\n>  \t\t\t\tstruct replay_opts *opts)\n>  {\n> diff --git a/sequencer.h b/sequencer.h\n> index 02e3d7940e..aab280f276 100644\n> --- a/sequencer.h\n> +++ b/sequencer.h\n> @@ -119,3 +119,7 @@ int prepare_branch_to_be_rebased(struct replay_opts *opts, const char *commit);\n>  void print_commit_summary(const char *prefix, const struct object_id *oid,\n>  \t\t\t  unsigned int flags);\n>  #endif\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> \n\n"},{"id":"356306","messageId":"nycvar.QRO.7.76.6.1808222310220.73@tvgsbejvaqbjf.bet","threadId":"48814","inReplyTo":"20180810165147.4779-19-alban.gruin@gmail.com","subject":"Re: [GSoC][PATCH v6 18/20] rebase--interactive2: rewrite the submodes of interactive rebase in C","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2018-08-22T21:14:43Z","receivedAt":"2018-08-22T21:14:58Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Alban,\n\nthank you for your tireless work on this!\n\nOne thing that needs to be fixed, though:\n\nOn Fri, 10 Aug 2018, Alban Gruin wrote:\n\n> +run_interactive () {\n> +\tGIT_CHERRY_PICK_HELP=\"$resolvemsg\"\n> +\texport GIT_CHERRY_PICK_HELP\n> +\n> +\ttest -n \"$keep_empty\" && keep_empty=\"--keep-empty\"\n> +\ttest -n \"$rebase_merges\" && rebase_merges=\"--rebase-merges\"\n> +\ttest -n \"$rebase_cousins\" && rebase_cousins=\"--rebase-cousins\"\n> +\ttest -n \"$autosquash\" && autosquash=\"--autosquash\"\n> +\ttest -n \"$verbose\" && verbose=\"--verbose\"\n> +\ttest -n \"$force_rebase\" && force_rebase=\"--no-ff\"\n> +\ttest -n \"$restrict_revisions\" && \\\n> +\t\trestrict_revisions=\"--restrict-revisions=^$restrict_revisions\"\n\nI made this same mistake over and over again, myself. For some reason,\nJohn Keeping decided to use the singular form \"revision\" in 1e0dacdbdb75\n(rebase: omit patch-identical commits with --fork-point, 2014-07-16), not\nthe plural.\n\nSo you will need to squash this in:\n\n-- snipsnap --\ndiff --git a/git-legacy-rebase.sh b/git-legacy-rebase.sh\nindex fb0395af5b1..7600765f541 100755\n--- a/git-legacy-rebase.sh\n+++ b/git-legacy-rebase.sh\n@@ -145,8 +145,8 @@ run_interactive () {\n \ttest -n \"$autosquash\" && autosquash=\"--autosquash\"\n \ttest -n \"$verbose\" && verbose=\"--verbose\"\n \ttest -n \"$force_rebase\" && force_rebase=\"--no-ff\"\n-\ttest -n \"$restrict_revisions\" && \\\n-\t\trestrict_revisions=\"--restrict-revisions=^$restrict_revisions\"\n+\ttest -n \"$restrict_revision\" && \\\n+\t\trestrict_revision=\"--restrict-revision=^$restrict_revision\"\n \ttest -n \"$upstream\" && upstream=\"--upstream=$upstream\"\n \ttest -n \"$onto\" && onto=\"--onto=$onto\"\n \ttest -n \"$squash_onto\" && squash_onto=\"--squash-onto=$squash_onto\"\n"},{"id":"356307","messageId":"xmqqzhxeks2g.fsf@gitster-ct.c.googlers.com","threadId":"48814","inReplyTo":"nycvar.QRO.7.76.6.1808222310220.73@tvgsbejvaqbjf.bet","subject":"Re: [GSoC][PATCH v6 18/20] rebase--interactive2: rewrite the submodes of interactive rebase in C","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2018-08-22T21:30:15Z","receivedAt":"2018-08-22T21:30:20Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n\n> I made this same mistake over and over again, myself. For some reason,\n> John Keeping decided to use the singular form \"revision\" in 1e0dacdbdb75\n> (rebase: omit patch-identical commits with --fork-point, 2014-07-16), not\n> the plural.\n\nPerhaps we should give a synonym to the option?  Renaming it to the\nplural form may keep the existing usage working as it would be the\nunique abbreviation, which may be a way to reduce the mistake.\n\n>\n> So you will need to squash this in:\n>\n> -- snipsnap --\n> diff --git a/git-legacy-rebase.sh b/git-legacy-rebase.sh\n> index fb0395af5b1..7600765f541 100755\n> --- a/git-legacy-rebase.sh\n> +++ b/git-legacy-rebase.sh\n> @@ -145,8 +145,8 @@ run_interactive () {\n>  \ttest -n \"$autosquash\" && autosquash=\"--autosquash\"\n>  \ttest -n \"$verbose\" && verbose=\"--verbose\"\n>  \ttest -n \"$force_rebase\" && force_rebase=\"--no-ff\"\n> -\ttest -n \"$restrict_revisions\" && \\\n> -\t\trestrict_revisions=\"--restrict-revisions=^$restrict_revisions\"\n> +\ttest -n \"$restrict_revision\" && \\\n> +\t\trestrict_revision=\"--restrict-revision=^$restrict_revision\"\n>  \ttest -n \"$upstream\" && upstream=\"--upstream=$upstream\"\n>  \ttest -n \"$onto\" && onto=\"--onto=$onto\"\n>  \ttest -n \"$squash_onto\" && squash_onto=\"--squash-onto=$squash_onto\"\n"},{"id":"356410","messageId":"nycvar.QRO.7.76.6.1808232306010.73@tvgsbejvaqbjf.bet","threadId":"48814","inReplyTo":"xmqqzhxeks2g.fsf@gitster-ct.c.googlers.com","subject":"Re: [GSoC][PATCH v6 18/20] rebase--interactive2: rewrite the submodes of interactive rebase in C","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2018-08-23T21:08:45Z","receivedAt":"2018-08-23T21:08:57Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Junio,\n\nOn Wed, 22 Aug 2018, Junio C Hamano wrote:\n\n> Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n> \n> > I made this same mistake over and over again, myself. For some reason,\n> > John Keeping decided to use the singular form \"revision\" in 1e0dacdbdb75\n> > (rebase: omit patch-identical commits with --fork-point, 2014-07-16), not\n> > the plural.\n> \n> Perhaps we should give a synonym to the option?  Renaming it to the\n> plural form may keep the existing usage working as it would be the\n> unique abbreviation, which may be a way to reduce the mistake.\n\nThe obvious plan is to switch from spawning a separate process after\nparsing the `git rebase` options just to execute the interactive rebase to\nperforming both parts in the same process.\n\nIn other words: this option will simply go away.\n\nI'd much rather spend time and effort on designing a nice API for calling\nthe rebase backends in-process than on adding code that adds some plural\nform (which might not even be appropriate, given that you really can only\npass one single negative revision to restrict the commit range).\n\nCiao,\nDscho\n\n> \n> >\n> > So you will need to squash this in:\n> >\n> > -- snipsnap --\n> > diff --git a/git-legacy-rebase.sh b/git-legacy-rebase.sh\n> > index fb0395af5b1..7600765f541 100755\n> > --- a/git-legacy-rebase.sh\n> > +++ b/git-legacy-rebase.sh\n> > @@ -145,8 +145,8 @@ run_interactive () {\n> >  \ttest -n \"$autosquash\" && autosquash=\"--autosquash\"\n> >  \ttest -n \"$verbose\" && verbose=\"--verbose\"\n> >  \ttest -n \"$force_rebase\" && force_rebase=\"--no-ff\"\n> > -\ttest -n \"$restrict_revisions\" && \\\n> > -\t\trestrict_revisions=\"--restrict-revisions=^$restrict_revisions\"\n> > +\ttest -n \"$restrict_revision\" && \\\n> > +\t\trestrict_revision=\"--restrict-revision=^$restrict_revision\"\n> >  \ttest -n \"$upstream\" && upstream=\"--upstream=$upstream\"\n> >  \ttest -n \"$onto\" && onto=\"--onto=$onto\"\n> >  \ttest -n \"$squash_onto\" && squash_onto=\"--squash-onto=$squash_onto\"\n> \n"},{"id":"356414","messageId":"nycvar.QRO.7.76.6.1808232309570.73@tvgsbejvaqbjf.bet","threadId":"48814","inReplyTo":"3da3ce19-38f8-0c46-47a1-9510f203b65f@talktalk.net","subject":"Re: [GSoC][PATCH v6 15/20] rebase -i: rewrite write_basic_state() in C","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2018-08-23T21:27:30Z","receivedAt":"2018-08-23T21:27:43Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Phillip,\n\nOn Fri, 17 Aug 2018, Phillip Wood wrote:\n\n> On 10/08/2018 17:51, Alban Gruin wrote:\n> \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> \n> write_file() can call die() which isn't encouraged for code in libgit.\n> I'm not sure how much it matters in this case. Rewriting all these as\n> \n> \tif (head_name && write_message(onto, strlen(onto), rebase_path_onto(), 1))\n> \t\treturn -1;\n> \n> is a bit tedious. An alternative would be it leave it for now and in the\n> longer term move this function (and the ones above which I've just\n> noticed also call write_file()) to in builtin/rebase.c (assuming that\n> builtin/rebase--interactive.c and builtin/rebase.c get merged once\n> they're finalized - I'm not sure if there is a plan for that or not.)\n\nThis came up in the review, and Alban said exactly what you did.\n\nI then even dragged Peff into the discussion, as it was his idea to change\n`write_file()` from returning an `int` to returning a `void` (instead of\nlibifying the function so that it would not `die()` in error cases and\n`return 0` otherwise):\n\n\thttps://github.com/git/git/pull/518#discussion_r200606997\n\nChristian Couder (one of Alban's mentors) then even jumped in and *agreed*\nthat libifying code \"could be seen as unnecessary code churn and\nrejected.\"\n\nIn light of these two respected community members suggesting to Alban to\ngo and not give a flying fish about proper error handling, I have to admit\nthat I am sympathetic to Alban simply using `write_file()` as-is.\n\nI do agree with you, of course, that the over-use of `die()` in our code\nbase is a pretty bad thing.\n\nBut that's neither Alban's fault, nor should he be punished for the advice\nhe has been given.\n\nIn short: I agree with you that `write_file()` should be libified\nproperly, and I would suggest not to burden Alban with this (Alban, of\ncourse you should feel free to work on this if this is something you care\nabout, too).\n\nCiao,\nDscho\n"},{"id":"356661","messageId":"20180828121045.14933-1-alban.gruin@gmail.com","threadId":"48814","inReplyTo":"20180810165147.4779-1-alban.gruin@gmail.com","subject":"[GSoC][PATCH v7 00/20] rebase -i: rewrite in C","fromName":"Alban Gruin","fromEmail":"alban.gruin@gmail.com","sentAt":"2018-08-28T12:10:25Z","receivedAt":"2018-08-28T12:11:04Z","isPatch":true,"sender":{"key":"alban.gruin@gmail.com","avatar":"https://avatars.githubusercontent.com/u/6310153?v=4"},"body":"This patch series rewrite the interactive rebase from shell to C.\n\nIt is based on ffc6fa0e39 (\"Fourth batch for 2.19 cycle\", 2018-07-24).\nThis conflicts a bit with b9dfa238d5 (\"Getting ready for -rc1\",\n2017-08-27) because of the range-diff, but a 3-way merge can solve these\nconflicts cleanly.\n\nChanges since v6:\n\n - [11/20] Handle errors from checkout_onto().\n\n - [11/20] Remove useless calls to error_errno().\n\n - [17/20] Die with an help message if no parameters were given to\n   rebase--interactive2.\n\n - [17/20 & 18/20] Die if no commit was provided with `--upstream` or\n   `--onto` to rebase--interactive2.\n\n - [18/20] Replace \"restrict_revisions\" by \"restrict_revision\" in\n   git-rebase.sh.\n\nAlban Gruin (20):\n  sequencer: make three functions and an enum from sequencer.c public\n  rebase -i: rewrite append_todo_help() in C\n  editor: add a function to launch the sequence editor\n  rebase -i: rewrite the edit-todo functionality in C\n  sequencer: add a new function to silence a command, except if it fails\n  rebase -i: rewrite setup_reflog_action() in C\n  rebase -i: rewrite checkout_onto() in C\n  sequencer: refactor append_todo_help() to write its message to a\n    buffer\n  sequencer: change the way skip_unnecessary_picks() returns its result\n  t3404: todo list with commented-out commands only aborts\n  rebase -i: rewrite complete_action() in C\n  rebase -i: remove unused modes and functions\n  rebase -i: implement the logic to initialize $revisions in C\n  rebase -i: rewrite the rest of init_revisions_and_shortrevisions() in\n    C\n  rebase -i: rewrite write_basic_state() in C\n  rebase -i: rewrite init_basic_state() in C\n  rebase -i: implement the main part of interactive rebase as a builtin\n  rebase--interactive2: rewrite the submodes of interactive rebase in C\n  rebase -i: remove git-rebase--interactive.sh\n  rebase -i: move rebase--helper modes to rebase--interactive\n\n .gitignore                     |   1 -\n Makefile                       |   5 +-\n builtin.h                      |   2 +-\n builtin/rebase--helper.c       |  88 ---------\n builtin/rebase--interactive.c  | 270 ++++++++++++++++++++++++++++\n cache.h                        |   1 +\n editor.c                       |  27 ++-\n git-rebase--interactive.sh     | 283 -----------------------------\n git-rebase--preserve-merges.sh |  10 +-\n git-rebase.sh                  |  47 ++++-\n git.c                          |   2 +-\n rebase-interactive.c           |  90 ++++++++++\n rebase-interactive.h           |   8 +\n sequencer.c                    | 320 +++++++++++++++++++++++++++------\n sequencer.h                    |  22 ++-\n strbuf.h                       |   2 +\n t/t3404-rebase-interactive.sh  |  10 ++\n 17 files changed, 739 insertions(+), 449 deletions(-)\n delete mode 100644 builtin/rebase--helper.c\n create mode 100644 builtin/rebase--interactive.c\n delete mode 100644 git-rebase--interactive.sh\n create mode 100644 rebase-interactive.c\n create mode 100644 rebase-interactive.h\n\n-- \n2.18.0\n\n"},{"id":"356662","messageId":"20180828121045.14933-2-alban.gruin@gmail.com","threadId":"48814","inReplyTo":"20180828121045.14933-1-alban.gruin@gmail.com","subject":"[GSoC][PATCH v7 01/20] sequencer: make three functions and an enum from sequencer.c public","fromName":"Alban Gruin","fromEmail":"alban.gruin@gmail.com","sentAt":"2018-08-28T12:10:26Z","receivedAt":"2018-08-28T12:11:05Z","isPatch":true,"sender":{"key":"alban.gruin@gmail.com","avatar":"https://avatars.githubusercontent.com/u/6310153?v=4"},"body":"This makes rebase_path_todo(), get_missing_commit_check_level(),\nwrite_message() and the enum check_level accessible outside sequencer.c,\nrenames check_level to missing_commit_check_level, and prefixes its\nvalue names by MISSING_COMMIT_ to avoid namespace pollution.\n\nThis function and this enum will eventually be moved to\nrebase-interactive.c and become static again, so no special attention\nwas given to the naming.\n\nThis will be needed for the rewrite of append_todo_help() from shell to\nC, as it will be in a new library source file, rebase-interactive.c.\n\nSigned-off-by: Alban Gruin <alban.gruin@gmail.com>\n---\nNo changes since v6.\n\n sequencer.c | 26 +++++++++++---------------\n sequencer.h | 11 +++++++++++\n 2 files changed, 22 insertions(+), 15 deletions(-)\n\ndiff --git a/sequencer.c b/sequencer.c\nindex 16c1411054..dd1b060863 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -52,7 +52,7 @@ static GIT_PATH_FUNC(rebase_path, \"rebase-merge\")\n  * the lines are processed, they are removed from the front of this\n  * file and written to the tail of 'done'.\n  */\n-static GIT_PATH_FUNC(rebase_path_todo, \"rebase-merge/git-rebase-todo\")\n+GIT_PATH_FUNC(rebase_path_todo, \"rebase-merge/git-rebase-todo\")\n /*\n  * The rebase command lines that have already been processed. A line\n  * is moved here when it is first handled, before any associated user\n@@ -373,8 +373,8 @@ static void print_advice(int show_hint, struct replay_opts *opts)\n \t}\n }\n \n-static int write_message(const void *buf, size_t len, const char *filename,\n-\t\t\t int append_eol)\n+int write_message(const void *buf, size_t len, const char *filename,\n+\t\t  int append_eol)\n {\n \tstruct lock_file msg_file = LOCK_INIT;\n \n@@ -4249,24 +4249,20 @@ int transform_todos(unsigned flags)\n \treturn i;\n }\n \n-enum check_level {\n-\tCHECK_IGNORE = 0, CHECK_WARN, CHECK_ERROR\n-};\n-\n-static enum check_level get_missing_commit_check_level(void)\n+enum missing_commit_check_level get_missing_commit_check_level(void)\n {\n \tconst char *value;\n \n \tif (git_config_get_value(\"rebase.missingcommitscheck\", &value) ||\n \t\t\t!strcasecmp(\"ignore\", value))\n-\t\treturn CHECK_IGNORE;\n+\t\treturn MISSING_COMMIT_CHECK_IGNORE;\n \tif (!strcasecmp(\"warn\", value))\n-\t\treturn CHECK_WARN;\n+\t\treturn MISSING_COMMIT_CHECK_WARN;\n \tif (!strcasecmp(\"error\", value))\n-\t\treturn CHECK_ERROR;\n+\t\treturn MISSING_COMMIT_CHECK_ERROR;\n \twarning(_(\"unrecognized setting %s for option \"\n \t\t  \"rebase.missingCommitsCheck. Ignoring.\"), value);\n-\treturn CHECK_IGNORE;\n+\treturn MISSING_COMMIT_CHECK_IGNORE;\n }\n \n define_commit_slab(commit_seen, unsigned char);\n@@ -4278,7 +4274,7 @@ define_commit_slab(commit_seen, unsigned char);\n  */\n int check_todo_list(void)\n {\n-\tenum check_level check_level = get_missing_commit_check_level();\n+\tenum missing_commit_check_level check_level = get_missing_commit_check_level();\n \tstruct strbuf todo_file = STRBUF_INIT;\n \tstruct todo_list todo_list = TODO_LIST_INIT;\n \tstruct strbuf missing = STRBUF_INIT;\n@@ -4295,7 +4291,7 @@ int check_todo_list(void)\n \tadvise_to_edit_todo = res =\n \t\tparse_insn_buffer(todo_list.buf.buf, &todo_list);\n \n-\tif (res || check_level == CHECK_IGNORE)\n+\tif (res || check_level == MISSING_COMMIT_CHECK_IGNORE)\n \t\tgoto leave_check;\n \n \t/* Mark the commits in git-rebase-todo as seen */\n@@ -4330,7 +4326,7 @@ int check_todo_list(void)\n \tif (!missing.len)\n \t\tgoto leave_check;\n \n-\tif (check_level == CHECK_ERROR)\n+\tif (check_level == MISSING_COMMIT_CHECK_ERROR)\n \t\tadvise_to_edit_todo = res = 1;\n \n \tfprintf(stderr,\ndiff --git a/sequencer.h b/sequencer.h\nindex c5787c6b56..792e448b67 100644\n--- a/sequencer.h\n+++ b/sequencer.h\n@@ -3,6 +3,7 @@\n \n const char *git_path_commit_editmsg(void);\n const char *git_path_seq_dir(void);\n+const char *rebase_path_todo(void);\n \n #define APPEND_SIGNOFF_DEDUP (1u << 0)\n \n@@ -57,6 +58,15 @@ struct replay_opts {\n };\n #define REPLAY_OPTS_INIT { .action = -1, .current_fixups = STRBUF_INIT }\n \n+enum missing_commit_check_level {\n+\tMISSING_COMMIT_CHECK_IGNORE = 0,\n+\tMISSING_COMMIT_CHECK_WARN,\n+\tMISSING_COMMIT_CHECK_ERROR\n+};\n+\n+int write_message(const void *buf, size_t len, const char *filename,\n+\t\t  int append_eol);\n+\n /* Call this to setup defaults before parsing command line options */\n void sequencer_init_config(struct replay_opts *opts);\n int sequencer_pick_revisions(struct replay_opts *opts);\n@@ -79,6 +89,7 @@ int sequencer_make_script(FILE *out, int argc, const char **argv,\n \n int sequencer_add_exec_commands(const char *command);\n int transform_todos(unsigned flags);\n+enum missing_commit_check_level get_missing_commit_check_level(void);\n int check_todo_list(void);\n int skip_unnecessary_picks(void);\n int rearrange_squash(void);\n-- \n2.18.0\n\n"},{"id":"356663","messageId":"20180828121045.14933-3-alban.gruin@gmail.com","threadId":"48814","inReplyTo":"20180828121045.14933-1-alban.gruin@gmail.com","subject":"[GSoC][PATCH v7 02/20] rebase -i: rewrite append_todo_help() in C","fromName":"Alban Gruin","fromEmail":"alban.gruin@gmail.com","sentAt":"2018-08-28T12:10:27Z","receivedAt":"2018-08-28T12:11:08Z","isPatch":true,"sender":{"key":"alban.gruin@gmail.com","avatar":"https://avatars.githubusercontent.com/u/6310153?v=4"},"body":"This rewrites append_todo_help() from shell to C. It also incorporates\nsome parts of initiate_action() and complete_action() that also write\nhelp texts to the todo file.\n\nThis also introduces the source file rebase-interactive.c. This file\nwill contain functions necessary for interactive rebase that are too\nspecific for the sequencer, and is part of libgit.a.\n\nTwo flags are added to rebase--helper.c: one to call\nappend_todo_help() (`--append-todo-help`), and another one to tell\nappend_todo_help() to write the help text suited for the edit-todo\nmode (`--write-edit-todo`).\n\nFinally, append_todo_help() is removed from git-rebase--interactive.sh\nto use `rebase--helper --append-todo-help` instead.\n\nSigned-off-by: Alban Gruin <alban.gruin@gmail.com>\n---\nNo changes since v6.\n\n Makefile                   |  1 +\n builtin/rebase--helper.c   | 11 ++++--\n git-rebase--interactive.sh | 52 ++---------------------------\n rebase-interactive.c       | 68 ++++++++++++++++++++++++++++++++++++++\n rebase-interactive.h       |  6 ++++\n 5 files changed, 86 insertions(+), 52 deletions(-)\n create mode 100644 rebase-interactive.c\n create mode 100644 rebase-interactive.h\n\ndiff --git a/Makefile b/Makefile\nindex 08e5c54549..909a687857 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -922,6 +922,7 @@ LIB_OBJS += protocol.o\n LIB_OBJS += quote.o\n LIB_OBJS += reachable.o\n LIB_OBJS += read-cache.o\n+LIB_OBJS += rebase-interactive.o\n LIB_OBJS += reflog-walk.o\n LIB_OBJS += refs.o\n LIB_OBJS += refs/files-backend.o\ndiff --git a/builtin/rebase--helper.c b/builtin/rebase--helper.c\nindex f7c2a5fdc8..05e73e71d4 100644\n--- a/builtin/rebase--helper.c\n+++ b/builtin/rebase--helper.c\n@@ -3,6 +3,7 @@\n #include \"config.h\"\n #include \"parse-options.h\"\n #include \"sequencer.h\"\n+#include \"rebase-interactive.h\"\n \n static const char * const builtin_rebase_helper_usage[] = {\n \tN_(\"git rebase--helper [<options>]\"),\n@@ -12,12 +13,12 @@ static const char * const builtin_rebase_helper_usage[] = {\n int cmd_rebase__helper(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;\n+\tunsigned flags = 0, keep_empty = 0, rebase_merges = 0, write_edit_todo = 0;\n \tint abbreviate_commands = 0, rebase_cousins = -1;\n \tenum {\n \t\tCONTINUE = 1, ABORT, MAKE_SCRIPT, SHORTEN_OIDS, EXPAND_OIDS,\n \t\tCHECK_TODO_LIST, SKIP_UNNECESSARY_PICKS, REARRANGE_SQUASH,\n-\t\tADD_EXEC\n+\t\tADD_EXEC, APPEND_TODO_HELP\n \t} command = 0;\n \tstruct option options[] = {\n \t\tOPT_BOOL(0, \"ff\", &opts.allow_ff, N_(\"allow fast-forward\")),\n@@ -27,6 +28,8 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\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, \"write-edit-todo\", &write_edit_todo,\n+\t\t\t N_(\"append the edit-todo message to the todo-list\")),\n \t\tOPT_CMDMODE(0, \"continue\", &command, N_(\"continue rebase\"),\n \t\t\t\tCONTINUE),\n \t\tOPT_CMDMODE(0, \"abort\", &command, N_(\"abort rebase\"),\n@@ -45,6 +48,8 @@ int cmd_rebase__helper(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_CMDMODE(0, \"append-todo-help\", &command,\n+\t\t\t    N_(\"insert the help in the todo list\"), APPEND_TODO_HELP),\n \t\tOPT_END()\n \t};\n \n@@ -84,5 +89,7 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\n \t\treturn !!rearrange_squash();\n \tif (command == ADD_EXEC && argc == 2)\n \t\treturn !!sequencer_add_exec_commands(argv[1]);\n+\tif (command == APPEND_TODO_HELP && argc == 1)\n+\t\treturn !!append_todo_help(write_edit_todo, keep_empty);\n \tusage_with_options(builtin_rebase_helper_usage, options);\n }\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex 299ded2137..94c23a7af2 100644\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -39,38 +39,6 @@ comment_for_reflog () {\n \tesac\n }\n \n-append_todo_help () {\n-\tgettext \"\n-Commands:\n-p, pick <commit> = use commit\n-r, reword <commit> = use commit, but edit the commit message\n-e, edit <commit> = use commit, but stop for amending\n-s, squash <commit> = use commit, but meld into previous commit\n-f, fixup <commit> = like \\\"squash\\\", but discard this commit's log message\n-x, exec <command> = run command (the rest of the line) using shell\n-d, drop <commit> = remove commit\n-l, label <label> = label current HEAD with a name\n-t, reset <label> = reset HEAD to a label\n-m, merge [-C <commit> | -c <commit>] <label> [# <oneline>]\n-.       create a merge commit using the original merge commit's\n-.       message (or the oneline, if no original merge commit was\n-.       specified). Use -c <commit> to reword the commit message.\n-\n-These lines can be re-ordered; they are executed from top to bottom.\n-\" | git stripspace --comment-lines >>\"$todo\"\n-\n-\tif test $(get_missing_commit_check_level) = error\n-\tthen\n-\t\tgettext \"\n-Do not remove any line. Use 'drop' explicitly to remove a commit.\n-\" | git stripspace --comment-lines >>\"$todo\"\n-\telse\n-\t\tgettext \"\n-If you remove a line here THAT COMMIT WILL BE LOST.\n-\" | git stripspace --comment-lines >>\"$todo\"\n-\tfi\n-}\n-\n die_abort () {\n \tapply_autostash\n \trm -rf \"$state_dir\"\n@@ -143,13 +111,7 @@ initiate_action () {\n \t\tgit stripspace --strip-comments <\"$todo\" >\"$todo\".new\n \t\tmv -f \"$todo\".new \"$todo\"\n \t\tcollapse_todo_ids\n-\t\tappend_todo_help\n-\t\tgettext \"\n-You are editing the todo file of an ongoing interactive rebase.\n-To continue rebase after editing, run:\n-    git rebase --continue\n-\n-\" | git stripspace --comment-lines >>\"$todo\"\n+\t\tgit rebase--helper --append-todo-help --write-edit-todo\n \n \t\tgit_sequence_editor \"$todo\" ||\n \t\t\tdie \"$(gettext \"Could not execute editor\")\"\n@@ -220,17 +182,7 @@ $comment_char $(eval_ngettext \\\n \t\"Rebase \\$shortrevisions onto \\$shortonto (\\$todocount commands)\" \\\n \t\"$todocount\")\n EOF\n-\tappend_todo_help\n-\tgettext \"\n-\tHowever, if you remove everything, the rebase will be aborted.\n-\n-\t\" | git stripspace --comment-lines >>\"$todo\"\n-\n-\tif test -z \"$keep_empty\"\n-\tthen\n-\t\tprintf '%s\\n' \"$comment_char $(gettext \"Note that empty commits are commented out\")\" >>\"$todo\"\n-\tfi\n-\n+\tgit rebase--helper --append-todo-help ${keep_empty:+--keep-empty}\n \n \thas_action \"$todo\" ||\n \t\treturn 2\ndiff --git a/rebase-interactive.c b/rebase-interactive.c\nnew file mode 100644\nindex 0000000000..d7996bc8d9\n--- /dev/null\n+++ b/rebase-interactive.c\n@@ -0,0 +1,68 @@\n+#include \"cache.h\"\n+#include \"commit.h\"\n+#include \"rebase-interactive.h\"\n+#include \"sequencer.h\"\n+#include \"strbuf.h\"\n+\n+int append_todo_help(unsigned edit_todo, unsigned keep_empty)\n+{\n+\tstruct strbuf buf = STRBUF_INIT;\n+\tFILE *todo;\n+\tint ret;\n+\tconst char *msg = _(\"\\nCommands:\\n\"\n+\"p, pick <commit> = use commit\\n\"\n+\"r, reword <commit> = use commit, but edit the commit message\\n\"\n+\"e, edit <commit> = use commit, but stop for amending\\n\"\n+\"s, squash <commit> = use commit, but meld into previous commit\\n\"\n+\"f, fixup <commit> = like \\\"squash\\\", but discard this commit's log message\\n\"\n+\"x, exec <command> = run command (the rest of the line) using shell\\n\"\n+\"d, drop <commit> = remove commit\\n\"\n+\"l, label <label> = label current HEAD with a name\\n\"\n+\"t, reset <label> = reset HEAD to a label\\n\"\n+\"m, merge [-C <commit> | -c <commit>] <label> [# <oneline>]\\n\"\n+\".       create a merge commit using the original merge commit's\\n\"\n+\".       message (or the oneline, if no original merge commit was\\n\"\n+\".       specified). Use -c <commit> to reword the commit message.\\n\"\n+\"\\n\"\n+\"These lines can be re-ordered; they are executed from top to bottom.\\n\");\n+\n+\ttodo = fopen_or_warn(rebase_path_todo(), \"a\");\n+\tif (!todo)\n+\t\treturn 1;\n+\n+\tstrbuf_add_commented_lines(&buf, msg, strlen(msg));\n+\n+\tif (get_missing_commit_check_level() == MISSING_COMMIT_CHECK_ERROR)\n+\t\tmsg = _(\"\\nDo not remove any line. Use 'drop' \"\n+\t\t\t \"explicitly to remove a commit.\\n\");\n+\telse\n+\t\tmsg = _(\"\\nIf you remove a line here \"\n+\t\t\t \"THAT COMMIT WILL BE LOST.\\n\");\n+\n+\tstrbuf_add_commented_lines(&buf, msg, strlen(msg));\n+\n+\tif (edit_todo)\n+\t\tmsg = _(\"\\nYou are editing the todo file \"\n+\t\t\t\"of an ongoing interactive rebase.\\n\"\n+\t\t\t\"To continue rebase after editing, run:\\n\"\n+\t\t\t\"    git rebase --continue\\n\\n\");\n+\telse\n+\t\tmsg = _(\"\\nHowever, if you remove everything, \"\n+\t\t\t\"the rebase will be aborted.\\n\\n\");\n+\n+\tstrbuf_add_commented_lines(&buf, msg, strlen(msg));\n+\n+\tif (!keep_empty) {\n+\t\tmsg = _(\"Note that empty commits are commented out\");\n+\t\tstrbuf_add_commented_lines(&buf, msg, strlen(msg));\n+\t}\n+\n+\tret = fputs(buf.buf, todo);\n+\tif (ret < 0)\n+\t\terror_errno(_(\"could not append help text to '%s'\"), rebase_path_todo());\n+\n+\tfclose(todo);\n+\tstrbuf_release(&buf);\n+\n+\treturn ret;\n+}\ndiff --git a/rebase-interactive.h b/rebase-interactive.h\nnew file mode 100644\nindex 0000000000..47372624e0\n--- /dev/null\n+++ b/rebase-interactive.h\n@@ -0,0 +1,6 @@\n+#ifndef REBASE_INTERACTIVE_H\n+#define REBASE_INTERACTIVE_H\n+\n+int append_todo_help(unsigned edit_todo, unsigned keep_empty);\n+\n+#endif\n-- \n2.18.0\n\n"},{"id":"356664","messageId":"20180828121045.14933-4-alban.gruin@gmail.com","threadId":"48814","inReplyTo":"20180828121045.14933-1-alban.gruin@gmail.com","subject":"[GSoC][PATCH v7 03/20] editor: add a function to launch the sequence editor","fromName":"Alban Gruin","fromEmail":"alban.gruin@gmail.com","sentAt":"2018-08-28T12:10:28Z","receivedAt":"2018-08-28T12:11:09Z","isPatch":true,"sender":{"key":"alban.gruin@gmail.com","avatar":"https://avatars.githubusercontent.com/u/6310153?v=4"},"body":"As part of the rewrite of interactive rebase, the sequencer will need to\nopen the sequence editor to allow the user to edit the todo list.\nInstead of duplicating the existing launch_editor() function, this\nrefactors it to a new function, launch_specified_editor(), which takes\nthe editor as a parameter, in addition to the path, the buffer and the\nenvironment variables.  launch_sequence_editor() is then added to launch\nthe sequence editor.\n\nSigned-off-by: Alban Gruin <alban.gruin@gmail.com>\n---\nNo changes since v6.\n\n cache.h  |  1 +\n editor.c | 27 +++++++++++++++++++++++++--\n strbuf.h |  2 ++\n 3 files changed, 28 insertions(+), 2 deletions(-)\n\ndiff --git a/cache.h b/cache.h\nindex 8b447652a7..d70ae49ca2 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -1409,6 +1409,7 @@ extern const char *fmt_name(const char *name, const char *email);\n extern const char *ident_default_name(void);\n extern const char *ident_default_email(void);\n extern const char *git_editor(void);\n+extern const char *git_sequence_editor(void);\n extern const char *git_pager(int stdout_is_tty);\n extern int is_terminal_dumb(void);\n extern int git_ident_config(const char *, const char *, void *);\ndiff --git a/editor.c b/editor.c\nindex 9a9b4e12d1..c985eee1f9 100644\n--- a/editor.c\n+++ b/editor.c\n@@ -1,4 +1,5 @@\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"strbuf.h\"\n #include \"run-command.h\"\n #include \"sigchain.h\"\n@@ -34,10 +35,21 @@ const char *git_editor(void)\n \treturn editor;\n }\n \n-int launch_editor(const char *path, struct strbuf *buffer, const char *const *env)\n+const char *git_sequence_editor(void)\n {\n-\tconst char *editor = git_editor();\n+\tconst char *editor = getenv(\"GIT_SEQUENCE_EDITOR\");\n+\n+\tif (!editor)\n+\t\tgit_config_get_string_const(\"sequence.editor\", &editor);\n+\tif (!editor)\n+\t\teditor = git_editor();\n \n+\treturn editor;\n+}\n+\n+static int launch_specified_editor(const char *editor, const char *path,\n+\t\t\t\t   struct strbuf *buffer, const char *const *env)\n+{\n \tif (!editor)\n \t\treturn error(\"Terminal is dumb, but EDITOR unset\");\n \n@@ -95,3 +107,14 @@ int launch_editor(const char *path, struct strbuf *buffer, const char *const *en\n \t\treturn error_errno(\"could not read file '%s'\", path);\n \treturn 0;\n }\n+\n+int launch_editor(const char *path, struct strbuf *buffer, const char *const *env)\n+{\n+\treturn launch_specified_editor(git_editor(), path, buffer, env);\n+}\n+\n+int launch_sequence_editor(const char *path, struct strbuf *buffer,\n+\t\t\t   const char *const *env)\n+{\n+\treturn launch_specified_editor(git_sequence_editor(), path, buffer, env);\n+}\ndiff --git a/strbuf.h b/strbuf.h\nindex 60a35aef16..66da9822fd 100644\n--- a/strbuf.h\n+++ b/strbuf.h\n@@ -575,6 +575,8 @@ extern void strbuf_add_unique_abbrev(struct strbuf *sb,\n  * file's contents are not read into the buffer upon completion.\n  */\n extern int launch_editor(const char *path, struct strbuf *buffer, const char *const *env);\n+extern int launch_sequence_editor(const char *path, struct strbuf *buffer,\n+\t\t\t\t  const char *const *env);\n \n extern void strbuf_add_lines(struct strbuf *sb, const char *prefix, const char *buf, size_t size);\n \n-- \n2.18.0\n\n"},{"id":"356665","messageId":"20180828121045.14933-5-alban.gruin@gmail.com","threadId":"48814","inReplyTo":"20180828121045.14933-1-alban.gruin@gmail.com","subject":"[GSoC][PATCH v7 04/20] rebase -i: rewrite the edit-todo functionality in C","fromName":"Alban Gruin","fromEmail":"alban.gruin@gmail.com","sentAt":"2018-08-28T12:10:29Z","receivedAt":"2018-08-28T12:11:10Z","isPatch":true,"sender":{"key":"alban.gruin@gmail.com","avatar":"https://avatars.githubusercontent.com/u/6310153?v=4"},"body":"This rewrites the edit-todo functionality from shell to C.\n\nTo achieve that, a new command mode, `edit-todo`, is added, and the\n`write-edit-todo` flag is removed, as the shell script does not need to\nwrite the edit todo help message to the todo list anymore.\n\nThe shell version is then stripped in favour of a call to the helper.\n\nSigned-off-by: Alban Gruin <alban.gruin@gmail.com>\n---\nNo changes since v6.\n\n builtin/rebase--helper.c   | 13 ++++++++-----\n git-rebase--interactive.sh | 11 +----------\n rebase-interactive.c       | 27 +++++++++++++++++++++++++++\n rebase-interactive.h       |  1 +\n 4 files changed, 37 insertions(+), 15 deletions(-)\n\ndiff --git a/builtin/rebase--helper.c b/builtin/rebase--helper.c\nindex 05e73e71d4..731a64971d 100644\n--- a/builtin/rebase--helper.c\n+++ b/builtin/rebase--helper.c\n@@ -13,12 +13,12 @@ static const char * const builtin_rebase_helper_usage[] = {\n int cmd_rebase__helper(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, write_edit_todo = 0;\n+\tunsigned flags = 0, keep_empty = 0, rebase_merges = 0;\n \tint abbreviate_commands = 0, rebase_cousins = -1;\n \tenum {\n \t\tCONTINUE = 1, ABORT, MAKE_SCRIPT, SHORTEN_OIDS, EXPAND_OIDS,\n \t\tCHECK_TODO_LIST, SKIP_UNNECESSARY_PICKS, REARRANGE_SQUASH,\n-\t\tADD_EXEC, APPEND_TODO_HELP\n+\t\tADD_EXEC, APPEND_TODO_HELP, EDIT_TODO\n \t} command = 0;\n \tstruct option options[] = {\n \t\tOPT_BOOL(0, \"ff\", &opts.allow_ff, N_(\"allow fast-forward\")),\n@@ -28,8 +28,6 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\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, \"write-edit-todo\", &write_edit_todo,\n-\t\t\t N_(\"append the edit-todo message to the todo-list\")),\n \t\tOPT_CMDMODE(0, \"continue\", &command, N_(\"continue rebase\"),\n \t\t\t\tCONTINUE),\n \t\tOPT_CMDMODE(0, \"abort\", &command, N_(\"abort rebase\"),\n@@ -50,6 +48,9 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\n \t\t\tN_(\"insert exec commands in todo list\"), ADD_EXEC),\n \t\tOPT_CMDMODE(0, \"append-todo-help\", &command,\n \t\t\t    N_(\"insert the help in the todo list\"), APPEND_TODO_HELP),\n+\t\tOPT_CMDMODE(0, \"edit-todo\", &command,\n+\t\t\t    N_(\"edit the todo list during an interactive rebase\"),\n+\t\t\t    EDIT_TODO),\n \t\tOPT_END()\n \t};\n \n@@ -90,6 +91,8 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\n \tif (command == ADD_EXEC && argc == 2)\n \t\treturn !!sequencer_add_exec_commands(argv[1]);\n \tif (command == APPEND_TODO_HELP && argc == 1)\n-\t\treturn !!append_todo_help(write_edit_todo, keep_empty);\n+\t\treturn !!append_todo_help(0, keep_empty);\n+\tif (command == EDIT_TODO && argc == 1)\n+\t\treturn !!edit_todo_list(flags);\n \tusage_with_options(builtin_rebase_helper_usage, options);\n }\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex 94c23a7af2..2defe607f4 100644\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -108,16 +108,7 @@ initiate_action () {\n \t\t     --continue\n \t\t;;\n \tedit-todo)\n-\t\tgit stripspace --strip-comments <\"$todo\" >\"$todo\".new\n-\t\tmv -f \"$todo\".new \"$todo\"\n-\t\tcollapse_todo_ids\n-\t\tgit rebase--helper --append-todo-help --write-edit-todo\n-\n-\t\tgit_sequence_editor \"$todo\" ||\n-\t\t\tdie \"$(gettext \"Could not execute editor\")\"\n-\t\texpand_todo_ids\n-\n-\t\texit\n+\t\texec git rebase--helper --edit-todo\n \t\t;;\n \tshow-current-patch)\n \t\texec git show REBASE_HEAD --\ndiff --git a/rebase-interactive.c b/rebase-interactive.c\nindex d7996bc8d9..3f9468fc69 100644\n--- a/rebase-interactive.c\n+++ b/rebase-interactive.c\n@@ -66,3 +66,30 @@ int append_todo_help(unsigned edit_todo, unsigned keep_empty)\n \n \treturn ret;\n }\n+\n+int edit_todo_list(unsigned flags)\n+{\n+\tstruct strbuf buf = STRBUF_INIT;\n+\tconst char *todo_file = rebase_path_todo();\n+\n+\tif (strbuf_read_file(&buf, todo_file, 0) < 0)\n+\t\treturn error_errno(_(\"could not read '%s'.\"), todo_file);\n+\n+\tstrbuf_stripspace(&buf, 1);\n+\tif (write_message(buf.buf, buf.len, todo_file, 0)) {\n+\t\tstrbuf_release(&buf);\n+\t\treturn -1;\n+\t}\n+\n+\tstrbuf_release(&buf);\n+\n+\ttransform_todos(flags | TODO_LIST_SHORTEN_IDS);\n+\tappend_todo_help(1, 0);\n+\n+\tif (launch_sequence_editor(todo_file, NULL, NULL))\n+\t\treturn -1;\n+\n+\ttransform_todos(flags & ~(TODO_LIST_SHORTEN_IDS));\n+\n+\treturn 0;\n+}\ndiff --git a/rebase-interactive.h b/rebase-interactive.h\nindex 47372624e0..155219e742 100644\n--- a/rebase-interactive.h\n+++ b/rebase-interactive.h\n@@ -2,5 +2,6 @@\n #define REBASE_INTERACTIVE_H\n \n int append_todo_help(unsigned edit_todo, unsigned keep_empty);\n+int edit_todo_list(unsigned flags);\n \n #endif\n-- \n2.18.0\n\n"},{"id":"356666","messageId":"20180828121045.14933-6-alban.gruin@gmail.com","threadId":"48814","inReplyTo":"20180828121045.14933-1-alban.gruin@gmail.com","subject":"[GSoC][PATCH v7 05/20] sequencer: add a new function to silence a command, except if it fails","fromName":"Alban Gruin","fromEmail":"alban.gruin@gmail.com","sentAt":"2018-08-28T12:10:30Z","receivedAt":"2018-08-28T12:11:11Z","isPatch":true,"sender":{"key":"alban.gruin@gmail.com","avatar":"https://avatars.githubusercontent.com/u/6310153?v=4"},"body":"This adds a new function, run_command_silent_on_success(), to\nredirect the stdout and stderr of a command to a strbuf, and then to run\nthat command. This strbuf is printed only if the command fails. It is\nfunctionnaly similar to output() from git-rebase.sh.\n\nrun_git_commit() is then refactored to use of\nrun_command_silent_on_success().\n\nSigned-off-by: Alban Gruin <alban.gruin@gmail.com>\n---\nNo changes since v6.\n\n sequencer.c | 51 +++++++++++++++++++++++++--------------------------\n 1 file changed, 25 insertions(+), 26 deletions(-)\n\ndiff --git a/sequencer.c b/sequencer.c\nindex dd1b060863..eaa1aa7deb 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -769,6 +769,23 @@ N_(\"you have staged changes in your working tree\\n\"\n #define VERIFY_MSG  (1<<4)\n #define CREATE_ROOT_COMMIT (1<<5)\n \n+static int run_command_silent_on_success(struct child_process *cmd)\n+{\n+\tstruct strbuf buf = STRBUF_INIT;\n+\tint rc;\n+\n+\tcmd->stdout_to_stderr = 1;\n+\trc = pipe_command(cmd,\n+\t\t\t  NULL, 0,\n+\t\t\t  NULL, 0,\n+\t\t\t  &buf, 0);\n+\n+\tif (rc)\n+\t\tfputs(buf.buf, stderr);\n+\tstrbuf_release(&buf);\n+\treturn rc;\n+}\n+\n /*\n  * If we are cherry-pick, and if the merge did not result in\n  * hand-editing, we will hit this commit and inherit the original\n@@ -823,18 +840,11 @@ static int run_git_commit(const char *defmsg, struct replay_opts *opts,\n \n \tcmd.git_cmd = 1;\n \n-\tif (is_rebase_i(opts)) {\n-\t\tif (!(flags & EDIT_MSG)) {\n-\t\t\tcmd.stdout_to_stderr = 1;\n-\t\t\tcmd.err = -1;\n-\t\t}\n-\n-\t\tif (read_env_script(&cmd.env_array)) {\n-\t\t\tconst char *gpg_opt = gpg_sign_opt_quoted(opts);\n+\tif (is_rebase_i(opts) && read_env_script(&cmd.env_array)) {\n+\t\tconst char *gpg_opt = gpg_sign_opt_quoted(opts);\n \n-\t\t\treturn error(_(staged_changes_advice),\n-\t\t\t\t     gpg_opt, gpg_opt);\n-\t\t}\n+\t\treturn error(_(staged_changes_advice),\n+\t\t\t     gpg_opt, gpg_opt);\n \t}\n \n \targv_array_push(&cmd.args, \"commit\");\n@@ -864,21 +874,10 @@ static int run_git_commit(const char *defmsg, struct replay_opts *opts,\n \tif (opts->allow_empty_message)\n \t\targv_array_push(&cmd.args, \"--allow-empty-message\");\n \n-\tif (cmd.err == -1) {\n-\t\t/* hide stderr on success */\n-\t\tstruct strbuf buf = STRBUF_INIT;\n-\t\tint rc = pipe_command(&cmd,\n-\t\t\t\t      NULL, 0,\n-\t\t\t\t      /* stdout is already redirected */\n-\t\t\t\t      NULL, 0,\n-\t\t\t\t      &buf, 0);\n-\t\tif (rc)\n-\t\t\tfputs(buf.buf, stderr);\n-\t\tstrbuf_release(&buf);\n-\t\treturn rc;\n-\t}\n-\n-\treturn run_command(&cmd);\n+\tif (is_rebase_i(opts) && !(flags & EDIT_MSG))\n+\t\treturn run_command_silent_on_success(&cmd);\n+\telse\n+\t\treturn run_command(&cmd);\n }\n \n static int rest_is_empty(const struct strbuf *sb, int start)\n-- \n2.18.0\n\n"},{"id":"356670","messageId":"20180828121045.14933-7-alban.gruin@gmail.com","threadId":"48814","inReplyTo":"20180828121045.14933-1-alban.gruin@gmail.com","subject":"[GSoC][PATCH v7 06/20] rebase -i: rewrite setup_reflog_action() in C","fromName":"Alban Gruin","fromEmail":"alban.gruin@gmail.com","sentAt":"2018-08-28T12:10:31Z","receivedAt":"2018-08-28T12:11:14Z","isPatch":true,"sender":{"key":"alban.gruin@gmail.com","avatar":"https://avatars.githubusercontent.com/u/6310153?v=4"},"body":"This rewrites (the misnamed) setup_reflog_action() from shell to C. The\nnew version is called prepare_branch_to_be_rebased().\n\nA new command is added to rebase--helper.c, “checkout-base”, as well as\na new flag, “verbose”, to avoid silencing the output of the checkout\noperation called by checkout_base_commit().\n\nThe function `run_git_checkout()` will also be used in the next commit,\ntherefore its code is not part of `checkout_base_commit()`.\n\nThe shell version is then stripped in favour of a call to the helper.\n\nAs $GIT_REFLOG_ACTION is no longer set at the first call of\ncheckout_onto(), a call to comment_for_reflog() is added at the\nbeginning of this function.\n\nSigned-off-by: Alban Gruin <alban.gruin@gmail.com>\n---\nNo changes since v6.\n\n builtin/rebase--helper.c   |  7 ++++++-\n git-rebase--interactive.sh | 16 ++--------------\n sequencer.c                | 30 ++++++++++++++++++++++++++++++\n sequencer.h                |  2 ++\n 4 files changed, 40 insertions(+), 15 deletions(-)\n\ndiff --git a/builtin/rebase--helper.c b/builtin/rebase--helper.c\nindex 731a64971d..0e76dadba6 100644\n--- a/builtin/rebase--helper.c\n+++ b/builtin/rebase--helper.c\n@@ -18,7 +18,7 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\n \tenum {\n \t\tCONTINUE = 1, ABORT, MAKE_SCRIPT, SHORTEN_OIDS, EXPAND_OIDS,\n \t\tCHECK_TODO_LIST, SKIP_UNNECESSARY_PICKS, REARRANGE_SQUASH,\n-\t\tADD_EXEC, APPEND_TODO_HELP, EDIT_TODO\n+\t\tADD_EXEC, APPEND_TODO_HELP, EDIT_TODO, PREPARE_BRANCH\n \t} command = 0;\n \tstruct option options[] = {\n \t\tOPT_BOOL(0, \"ff\", &opts.allow_ff, N_(\"allow fast-forward\")),\n@@ -28,6 +28,7 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\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__VERBOSE(&opts.verbose, N_(\"be verbose\")),\n \t\tOPT_CMDMODE(0, \"continue\", &command, N_(\"continue rebase\"),\n \t\t\t\tCONTINUE),\n \t\tOPT_CMDMODE(0, \"abort\", &command, N_(\"abort rebase\"),\n@@ -51,6 +52,8 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\n \t\tOPT_CMDMODE(0, \"edit-todo\", &command,\n \t\t\t    N_(\"edit the todo list during an interactive rebase\"),\n \t\t\t    EDIT_TODO),\n+\t\tOPT_CMDMODE(0, \"prepare-branch\", &command,\n+\t\t\t    N_(\"prepare the branch to be rebased\"), PREPARE_BRANCH),\n \t\tOPT_END()\n \t};\n \n@@ -94,5 +97,7 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\n \t\treturn !!append_todo_help(0, keep_empty);\n \tif (command == EDIT_TODO && argc == 1)\n \t\treturn !!edit_todo_list(flags);\n+\tif (command == PREPARE_BRANCH && argc == 2)\n+\t\treturn !!prepare_branch_to_be_rebased(&opts, argv[1]);\n \tusage_with_options(builtin_rebase_helper_usage, options);\n }\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex 2defe607f4..77e972bb6c 100644\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -72,6 +72,7 @@ collapse_todo_ids() {\n \n # Switch to the branch in $into and notify it in the reflog\n checkout_onto () {\n+\tcomment_for_reflog start\n \tGIT_REFLOG_ACTION=\"$GIT_REFLOG_ACTION: checkout $onto_name\"\n \toutput git checkout $onto || die_abort \"$(gettext \"could not detach HEAD\")\"\n \tgit update-ref ORIG_HEAD $orig_head\n@@ -119,19 +120,6 @@ initiate_action () {\n \tesac\n }\n \n-setup_reflog_action () {\n-\tcomment_for_reflog start\n-\n-\tif test ! -z \"$switch_to\"\n-\tthen\n-\t\tGIT_REFLOG_ACTION=\"$GIT_REFLOG_ACTION: checkout $switch_to\"\n-\t\toutput git checkout \"$switch_to\" -- ||\n-\t\t\tdie \"$(eval_gettext \"Could not checkout \\$switch_to\")\"\n-\n-\t\tcomment_for_reflog start\n-\tfi\n-}\n-\n init_basic_state () {\n \torig_head=$(git rev-parse --verify HEAD) || die \"$(gettext \"No HEAD?\")\"\n \tmkdir -p \"$state_dir\" || die \"$(eval_gettext \"Could not create temporary \\$state_dir\")\"\n@@ -211,7 +199,7 @@ git_rebase__interactive () {\n \t\treturn 0\n \tfi\n \n-\tsetup_reflog_action\n+\tgit rebase--helper --prepare-branch \"$switch_to\" ${verbose:+--verbose}\n \tinit_basic_state\n \n \tinit_revisions_and_shortrevisions\ndiff --git a/sequencer.c b/sequencer.c\nindex eaa1aa7deb..c1cfa2ee5c 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -3141,6 +3141,36 @@ 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+{\n+\tstruct child_process cmd = CHILD_PROCESS_INIT;\n+\n+\tcmd.git_cmd = 1;\n+\n+\targv_array_push(&cmd.args, \"checkout\");\n+\targv_array_push(&cmd.args, 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+\telse\n+\t\treturn run_command_silent_on_success(&cmd);\n+}\n+\n+int prepare_branch_to_be_rebased(struct replay_opts *opts, 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\t\treturn error(_(\"could not checkout %s\"), commit);\n+\t}\n+\n+\treturn 0;\n+}\n+\n static const char rescheduled_advice[] =\n N_(\"Could not execute the todo command\\n\"\n \"\\n\"\ndiff --git a/sequencer.h b/sequencer.h\nindex 792e448b67..f619b02a13 100644\n--- a/sequencer.h\n+++ b/sequencer.h\n@@ -109,6 +109,8 @@ int update_head_with_reflog(const struct commit *old_head,\n void commit_post_rewrite(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+\n #define SUMMARY_INITIAL_COMMIT   (1 << 0)\n #define SUMMARY_SHOW_AUTHOR_DATE (1 << 1)\n void print_commit_summary(const char *prefix, const struct object_id *oid,\n-- \n2.18.0\n\n"},{"id":"356669","messageId":"20180828121045.14933-8-alban.gruin@gmail.com","threadId":"48814","inReplyTo":"20180828121045.14933-1-alban.gruin@gmail.com","subject":"[GSoC][PATCH v7 07/20] rebase -i: rewrite checkout_onto() in C","fromName":"Alban Gruin","fromEmail":"alban.gruin@gmail.com","sentAt":"2018-08-28T12:10:32Z","receivedAt":"2018-08-28T12:11:16Z","isPatch":true,"sender":{"key":"alban.gruin@gmail.com","avatar":"https://avatars.githubusercontent.com/u/6310153?v=4"},"body":"This rewrites checkout_onto() from shell to C.\n\nA new command (“checkout-onto”) is added to rebase--helper.c. The shell\nversion is then stripped.\n\nSigned-off-by: Alban Gruin <alban.gruin@gmail.com>\n---\nNo changes since v6.\n\n builtin/rebase--helper.c   |  7 ++++++-\n git-rebase--interactive.sh | 25 ++++---------------------\n sequencer.c                | 19 +++++++++++++++++++\n sequencer.h                |  3 +++\n 4 files changed, 32 insertions(+), 22 deletions(-)\n\ndiff --git a/builtin/rebase--helper.c b/builtin/rebase--helper.c\nindex 0e76dadba6..7d9426d23c 100644\n--- a/builtin/rebase--helper.c\n+++ b/builtin/rebase--helper.c\n@@ -18,7 +18,8 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\n \tenum {\n \t\tCONTINUE = 1, ABORT, MAKE_SCRIPT, SHORTEN_OIDS, EXPAND_OIDS,\n \t\tCHECK_TODO_LIST, SKIP_UNNECESSARY_PICKS, REARRANGE_SQUASH,\n-\t\tADD_EXEC, APPEND_TODO_HELP, EDIT_TODO, PREPARE_BRANCH\n+\t\tADD_EXEC, APPEND_TODO_HELP, EDIT_TODO, PREPARE_BRANCH,\n+\t\tCHECKOUT_ONTO\n \t} command = 0;\n \tstruct option options[] = {\n \t\tOPT_BOOL(0, \"ff\", &opts.allow_ff, N_(\"allow fast-forward\")),\n@@ -54,6 +55,8 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\n \t\t\t    EDIT_TODO),\n \t\tOPT_CMDMODE(0, \"prepare-branch\", &command,\n \t\t\t    N_(\"prepare the branch to be rebased\"), PREPARE_BRANCH),\n+\t\tOPT_CMDMODE(0, \"checkout-onto\", &command,\n+\t\t\t    N_(\"checkout a commit\"), CHECKOUT_ONTO),\n \t\tOPT_END()\n \t};\n \n@@ -99,5 +102,7 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\n \t\treturn !!edit_todo_list(flags);\n \tif (command == PREPARE_BRANCH && argc == 2)\n \t\treturn !!prepare_branch_to_be_rebased(&opts, argv[1]);\n+\tif (command == CHECKOUT_ONTO && argc == 4)\n+\t\treturn !!checkout_onto(&opts, argv[1], argv[2], argv[3]);\n \tusage_with_options(builtin_rebase_helper_usage, options);\n }\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex 77e972bb6c..b68f108f28 100644\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -28,17 +28,6 @@ case \"$comment_char\" in\n \t;;\n esac\n \n-orig_reflog_action=\"$GIT_REFLOG_ACTION\"\n-\n-comment_for_reflog () {\n-\tcase \"$orig_reflog_action\" in\n-\t''|rebase*)\n-\t\tGIT_REFLOG_ACTION=\"rebase -i ($1)\"\n-\t\texport GIT_REFLOG_ACTION\n-\t\t;;\n-\tesac\n-}\n-\n die_abort () {\n \tapply_autostash\n \trm -rf \"$state_dir\"\n@@ -70,14 +59,6 @@ collapse_todo_ids() {\n \tgit rebase--helper --shorten-ids\n }\n \n-# Switch to the branch in $into and notify it in the reflog\n-checkout_onto () {\n-\tcomment_for_reflog start\n-\tGIT_REFLOG_ACTION=\"$GIT_REFLOG_ACTION: checkout $onto_name\"\n-\toutput git checkout $onto || die_abort \"$(gettext \"could not detach HEAD\")\"\n-\tgit update-ref ORIG_HEAD $orig_head\n-}\n-\n get_missing_commit_check_level () {\n \tcheck_level=$(git config --get rebase.missingCommitsCheck)\n \tcheck_level=${check_level:-ignore}\n@@ -176,7 +157,8 @@ EOF\n \n \tgit rebase--helper --check-todo-list || {\n \t\tret=$?\n-\t\tcheckout_onto\n+\t\tgit rebase--helper --checkout-onto \"$onto_name\" \"$onto\" \\\n+\t\t    \"$orig_head\" ${verbose:+--verbose}\n \t\texit $ret\n \t}\n \n@@ -186,7 +168,8 @@ EOF\n \tonto=\"$(git rebase--helper --skip-unnecessary-picks)\" ||\n \tdie \"Could not skip unnecessary pick commands\"\n \n-\tcheckout_onto\n+\tgit rebase--helper --checkout-onto \"$onto_name\" \"$onto\" \"$orig_head\" \\\n+\t    ${verbose:+--verbose}\n \trequire_clean_work_tree \"rebase\"\n \texec git rebase--helper ${force_rebase:+--no-ff} $allow_empty_message \\\n \t     --continue\ndiff --git a/sequencer.c b/sequencer.c\nindex c1cfa2ee5c..48447d7f0e 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -3171,6 +3171,25 @@ int prepare_branch_to_be_rebased(struct replay_opts *opts, const char *commit)\n \treturn 0;\n }\n \n+int checkout_onto(struct replay_opts *opts,\n+\t\t  const char *onto_name, const char *onto,\n+\t\t  const char *orig_head)\n+{\n+\tstruct object_id oid;\n+\tconst char *action = reflog_message(opts, \"start\", \"checkout %s\", onto_name);\n+\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+\t\tapply_autostash(opts);\n+\t\tsequencer_remove_state(opts);\n+\t\treturn error(_(\"could not detach HEAD\"));\n+\t}\n+\n+\treturn update_ref(NULL, \"ORIG_HEAD\", &oid, NULL, 0, UPDATE_REFS_MSG_ON_ERR);\n+}\n+\n static const char rescheduled_advice[] =\n N_(\"Could not execute the todo command\\n\"\n \"\\n\"\ndiff --git a/sequencer.h b/sequencer.h\nindex f619b02a13..d2b54adf45 100644\n--- a/sequencer.h\n+++ b/sequencer.h\n@@ -110,6 +110,9 @@ void commit_post_rewrite(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 checkout_onto(struct replay_opts *opts,\n+\t\t  const char *onto_name, const char *onto,\n+\t\t  const char *orig_head);\n \n #define SUMMARY_INITIAL_COMMIT   (1 << 0)\n #define SUMMARY_SHOW_AUTHOR_DATE (1 << 1)\n-- \n2.18.0\n\n"},{"id":"356677","messageId":"20180828121045.14933-9-alban.gruin@gmail.com","threadId":"48814","inReplyTo":"20180828121045.14933-1-alban.gruin@gmail.com","subject":"[GSoC][PATCH v7 08/20] sequencer: refactor append_todo_help() to write its message to a buffer","fromName":"Alban Gruin","fromEmail":"alban.gruin@gmail.com","sentAt":"2018-08-28T12:10:33Z","receivedAt":"2018-08-28T12:11:17Z","isPatch":true,"sender":{"key":"alban.gruin@gmail.com","avatar":"https://avatars.githubusercontent.com/u/6310153?v=4"},"body":"This refactors append_todo_help() to write its message to a buffer\ninstead of the todo-list.  This is needed for the rewrite of\ncomplete_action(), which will come after the next commit.\n\nAs rebase--helper still needs the file manipulation part of\nappend_todo_help(), it is extracted to a temporary function,\nappend_todo_help_to_file().  This function will go away after the\nrewrite of complete_action().\n\nSigned-off-by: Alban Gruin <alban.gruin@gmail.com>\n---\nNo changes since v6.\n\n builtin/rebase--helper.c |  2 +-\n rebase-interactive.c     | 43 ++++++++++++++++++++++++++++------------\n rebase-interactive.h     |  4 +++-\n 3 files changed, 34 insertions(+), 15 deletions(-)\n\ndiff --git a/builtin/rebase--helper.c b/builtin/rebase--helper.c\nindex 7d9426d23c..313092c465 100644\n--- a/builtin/rebase--helper.c\n+++ b/builtin/rebase--helper.c\n@@ -97,7 +97,7 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\n \tif (command == ADD_EXEC && argc == 2)\n \t\treturn !!sequencer_add_exec_commands(argv[1]);\n \tif (command == APPEND_TODO_HELP && argc == 1)\n-\t\treturn !!append_todo_help(0, keep_empty);\n+\t\treturn !!append_todo_help_to_file(0, keep_empty);\n \tif (command == EDIT_TODO && argc == 1)\n \t\treturn !!edit_todo_list(flags);\n \tif (command == PREPARE_BRANCH && argc == 2)\ndiff --git a/rebase-interactive.c b/rebase-interactive.c\nindex 3f9468fc69..4a9a10eff4 100644\n--- a/rebase-interactive.c\n+++ b/rebase-interactive.c\n@@ -4,11 +4,9 @@\n #include \"sequencer.h\"\n #include \"strbuf.h\"\n \n-int append_todo_help(unsigned edit_todo, unsigned keep_empty)\n+void append_todo_help(unsigned edit_todo, unsigned keep_empty,\n+\t\t      struct strbuf *buf)\n {\n-\tstruct strbuf buf = STRBUF_INIT;\n-\tFILE *todo;\n-\tint ret;\n \tconst char *msg = _(\"\\nCommands:\\n\"\n \"p, pick <commit> = use commit\\n\"\n \"r, reword <commit> = use commit, but edit the commit message\\n\"\n@@ -26,11 +24,7 @@ int append_todo_help(unsigned edit_todo, unsigned keep_empty)\n \"\\n\"\n \"These lines can be re-ordered; they are executed from top to bottom.\\n\");\n \n-\ttodo = fopen_or_warn(rebase_path_todo(), \"a\");\n-\tif (!todo)\n-\t\treturn 1;\n-\n-\tstrbuf_add_commented_lines(&buf, msg, strlen(msg));\n+\tstrbuf_add_commented_lines(buf, msg, strlen(msg));\n \n \tif (get_missing_commit_check_level() == MISSING_COMMIT_CHECK_ERROR)\n \t\tmsg = _(\"\\nDo not remove any line. Use 'drop' \"\n@@ -39,7 +33,7 @@ int append_todo_help(unsigned edit_todo, unsigned keep_empty)\n \t\tmsg = _(\"\\nIf you remove a line here \"\n \t\t\t \"THAT COMMIT WILL BE LOST.\\n\");\n \n-\tstrbuf_add_commented_lines(&buf, msg, strlen(msg));\n+\tstrbuf_add_commented_lines(buf, msg, strlen(msg));\n \n \tif (edit_todo)\n \t\tmsg = _(\"\\nYou are editing the todo file \"\n@@ -50,12 +44,25 @@ int append_todo_help(unsigned edit_todo, unsigned keep_empty)\n \t\tmsg = _(\"\\nHowever, if you remove everything, \"\n \t\t\t\"the rebase will be aborted.\\n\\n\");\n \n-\tstrbuf_add_commented_lines(&buf, msg, strlen(msg));\n+\tstrbuf_add_commented_lines(buf, msg, strlen(msg));\n \n \tif (!keep_empty) {\n \t\tmsg = _(\"Note that empty commits are commented out\");\n-\t\tstrbuf_add_commented_lines(&buf, msg, strlen(msg));\n+\t\tstrbuf_add_commented_lines(buf, msg, strlen(msg));\n \t}\n+}\n+\n+int append_todo_help_to_file(unsigned edit_todo, unsigned keep_empty)\n+{\n+\tstruct strbuf buf = STRBUF_INIT;\n+\tFILE *todo;\n+\tint ret;\n+\n+\ttodo = fopen_or_warn(rebase_path_todo(), \"a\");\n+\tif (!todo)\n+\t\treturn -1;\n+\n+\tappend_todo_help(edit_todo, keep_empty, &buf);\n \n \tret = fputs(buf.buf, todo);\n \tif (ret < 0)\n@@ -84,7 +91,17 @@ int edit_todo_list(unsigned flags)\n \tstrbuf_release(&buf);\n \n \ttransform_todos(flags | TODO_LIST_SHORTEN_IDS);\n-\tappend_todo_help(1, 0);\n+\n+\tif (strbuf_read_file(&buf, todo_file, 0) < 0)\n+\t\treturn error_errno(_(\"could not read '%s'.\"), todo_file);\n+\n+\tappend_todo_help(1, 0, &buf);\n+\tif (write_message(buf.buf, buf.len, todo_file, 0)) {\n+\t\tstrbuf_release(&buf);\n+\t\treturn -1;\n+\t}\n+\n+\tstrbuf_release(&buf);\n \n \tif (launch_sequence_editor(todo_file, NULL, NULL))\n \t\treturn -1;\ndiff --git a/rebase-interactive.h b/rebase-interactive.h\nindex 155219e742..d33f3176b7 100644\n--- a/rebase-interactive.h\n+++ b/rebase-interactive.h\n@@ -1,7 +1,9 @@\n #ifndef REBASE_INTERACTIVE_H\n #define REBASE_INTERACTIVE_H\n \n-int append_todo_help(unsigned edit_todo, unsigned keep_empty);\n+void append_todo_help(unsigned edit_todo, unsigned keep_empty,\n+\t\t      struct strbuf *buf);\n+int append_todo_help_to_file(unsigned edit_todo, unsigned keep_empty);\n int edit_todo_list(unsigned flags);\n \n #endif\n-- \n2.18.0\n\n"},{"id":"356674","messageId":"20180828121045.14933-10-alban.gruin@gmail.com","threadId":"48814","inReplyTo":"20180828121045.14933-1-alban.gruin@gmail.com","subject":"[GSoC][PATCH v7 09/20] sequencer: change the way skip_unnecessary_picks() returns its result","fromName":"Alban Gruin","fromEmail":"alban.gruin@gmail.com","sentAt":"2018-08-28T12:10:34Z","receivedAt":"2018-08-28T12:11:18Z","isPatch":true,"sender":{"key":"alban.gruin@gmail.com","avatar":"https://avatars.githubusercontent.com/u/6310153?v=4"},"body":"Instead of skip_unnecessary_picks() printing its result to stdout, it\nreturns it into a struct object_id, as the rewrite of complete_action()\n(to come in the next commit) will need it.\n\nrebase--helper then is modified to fit this change.\n\nSigned-off-by: Alban Gruin <alban.gruin@gmail.com>\n---\nNo changes since v6.\n\n builtin/rebase--helper.c | 10 ++++++++--\n sequencer.c              | 13 ++++++-------\n sequencer.h              |  2 +-\n 3 files changed, 15 insertions(+), 10 deletions(-)\n\ndiff --git a/builtin/rebase--helper.c b/builtin/rebase--helper.c\nindex 313092c465..bed3dd2b95 100644\n--- a/builtin/rebase--helper.c\n+++ b/builtin/rebase--helper.c\n@@ -90,8 +90,14 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\n \t\treturn !!transform_todos(flags);\n \tif (command == CHECK_TODO_LIST && argc == 1)\n \t\treturn !!check_todo_list();\n-\tif (command == SKIP_UNNECESSARY_PICKS && argc == 1)\n-\t\treturn !!skip_unnecessary_picks();\n+\tif (command == SKIP_UNNECESSARY_PICKS && argc == 1) {\n+\t\tstruct object_id oid;\n+\t\tint ret = skip_unnecessary_picks(&oid);\n+\n+\t\tif (!ret)\n+\t\t\tputs(oid_to_hex(&oid));\n+\t\treturn !!ret;\n+\t}\n \tif (command == REARRANGE_SQUASH && argc == 1)\n \t\treturn !!rearrange_squash();\n \tif (command == ADD_EXEC && argc == 2)\ndiff --git a/sequencer.c b/sequencer.c\nindex 48447d7f0e..a56a781539 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -4420,17 +4420,17 @@ static int rewrite_file(const char *path, const char *buf, size_t len)\n }\n \n /* skip picking commits whose parents are unchanged */\n-int skip_unnecessary_picks(void)\n+int skip_unnecessary_picks(struct object_id *output_oid)\n {\n \tconst char *todo_file = rebase_path_todo();\n \tstruct strbuf buf = STRBUF_INIT;\n \tstruct todo_list todo_list = TODO_LIST_INIT;\n-\tstruct object_id onto_oid, *oid = &onto_oid, *parent_oid;\n+\tstruct object_id *parent_oid;\n \tint fd, i;\n \n \tif (!read_oneliner(&buf, rebase_path_onto(), 0))\n \t\treturn error(_(\"could not read 'onto'\"));\n-\tif (get_oid(buf.buf, &onto_oid)) {\n+\tif (get_oid(buf.buf, output_oid)) {\n \t\tstrbuf_release(&buf);\n \t\treturn error(_(\"need a HEAD to fixup\"));\n \t}\n@@ -4460,9 +4460,9 @@ int skip_unnecessary_picks(void)\n \t\tif (item->commit->parents->next)\n \t\t\tbreak; /* merge commit */\n \t\tparent_oid = &item->commit->parents->item->object.oid;\n-\t\tif (hashcmp(parent_oid->hash, oid->hash))\n+\t\tif (hashcmp(parent_oid->hash, output_oid->hash))\n \t\t\tbreak;\n-\t\toid = &item->commit->object.oid;\n+\t\toidcpy(output_oid, &item->commit->object.oid);\n \t}\n \tif (i > 0) {\n \t\tint offset = get_item_line_offset(&todo_list, i);\n@@ -4491,11 +4491,10 @@ int skip_unnecessary_picks(void)\n \n \t\ttodo_list.current = i;\n \t\tif (is_fixup(peek_command(&todo_list, 0)))\n-\t\t\trecord_in_rewritten(oid, peek_command(&todo_list, 0));\n+\t\t\trecord_in_rewritten(output_oid, peek_command(&todo_list, 0));\n \t}\n \n \ttodo_list_release(&todo_list);\n-\tprintf(\"%s\\n\", oid_to_hex(oid));\n \n \treturn 0;\n }\ndiff --git a/sequencer.h b/sequencer.h\nindex d2b54adf45..fcbcd246c2 100644\n--- a/sequencer.h\n+++ b/sequencer.h\n@@ -91,7 +91,7 @@ int sequencer_add_exec_commands(const char *command);\n int transform_todos(unsigned flags);\n enum missing_commit_check_level get_missing_commit_check_level(void);\n int check_todo_list(void);\n-int skip_unnecessary_picks(void);\n+int skip_unnecessary_picks(struct object_id *output_oid);\n int rearrange_squash(void);\n \n extern const char sign_off_header[];\n-- \n2.18.0\n\n"},{"id":"356668","messageId":"20180828121045.14933-11-alban.gruin@gmail.com","threadId":"48814","inReplyTo":"20180828121045.14933-1-alban.gruin@gmail.com","subject":"[GSoC][PATCH v7 10/20] t3404: todo list with commented-out commands only aborts","fromName":"Alban Gruin","fromEmail":"alban.gruin@gmail.com","sentAt":"2018-08-28T12:10:35Z","receivedAt":"2018-08-28T12:11:20Z","isPatch":true,"sender":{"key":"alban.gruin@gmail.com","avatar":"https://avatars.githubusercontent.com/u/6310153?v=4"},"body":"If the todo list generated by `--make-script` is empty,\ncomplete_action() writes a noop, but if it has only commented-out\ncommands, it will abort with the message \"Nothing to do\", and does not\nlaunch the editor.  This adds a new test to ensure that\ncomplete_action() behaves this way.\n\nSigned-off-by: Alban Gruin <alban.gruin@gmail.com>\n---\nNo changes since v6.\n\n t/t3404-rebase-interactive.sh | 10 ++++++++++\n 1 file changed, 10 insertions(+)\n\ndiff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh\nindex 01616901bd..496d88d7d6 100755\n--- a/t/t3404-rebase-interactive.sh\n+++ b/t/t3404-rebase-interactive.sh\n@@ -75,6 +75,16 @@ test_expect_success 'rebase --keep-empty' '\n \ttest_line_count = 6 actual\n '\n \n+cat > expect <<EOF\n+Nothing to do\n+EOF\n+\n+test_expect_success 'rebase -i with empty HEAD' '\n+\tset_fake_editor &&\n+\ttest_must_fail env FAKE_LINES=\"1 exec_true\" git rebase -i HEAD^ >actual 2>&1 &&\n+\ttest_i18ncmp expect actual\n+'\n+\n test_expect_success 'rebase -i with the exec command' '\n \tgit checkout master &&\n \t(\n-- \n2.18.0\n\n"},{"id":"356676","messageId":"20180828121045.14933-12-alban.gruin@gmail.com","threadId":"48814","inReplyTo":"20180828121045.14933-1-alban.gruin@gmail.com","subject":"[GSoC][PATCH v7 11/20] rebase -i: rewrite complete_action() in C","fromName":"Alban Gruin","fromEmail":"alban.gruin@gmail.com","sentAt":"2018-08-28T12:10:36Z","receivedAt":"2018-08-28T12:11:24Z","isPatch":true,"sender":{"key":"alban.gruin@gmail.com","avatar":"https://avatars.githubusercontent.com/u/6310153?v=4"},"body":"This rewrites complete_action() from shell to C.\n\nA new mode is added to rebase--helper (`--complete-action`), as well as\na new flag (`--autosquash`).\n\nFinally, complete_action() is stripped from git-rebase--interactive.sh.\n\nThe original complete_action() would return the code 2 when the todo\nlist contained no actions.  This was a special case for rebase -i and\n-p; git-rebase.sh would then apply the autostash, delete the state\ndirectory, and die with the message \"Nothing to do\".  This cleanup is\nrewritten in C instead of returning 2.  As rebase -i no longer returns\n2, the comment describing this behaviour in git-rebase.sh is updated to\nreflect this change.\n\nThe message \"Nothing to do\" is now printed with error(), and so becomes\n\"error: nothing to do\".  Some tests in t3404 check this value, so they\nare updated to fit this change.\n\nThe first check might seem useless as we write \"noop\" to the todo list\nif it is empty.  Actually, the todo list might contain commented\ncommands (ie. empty commits).  In this case, complete_action() won’t\nwrite \"noop\", and will abort without starting the editor.\n\nSigned-off-by: Alban Gruin <alban.gruin@gmail.com>\n---\n builtin/rebase--helper.c      |  12 +++-\n git-rebase--interactive.sh    |  53 ++---------------\n git-rebase.sh                 |   2 +-\n sequencer.c                   | 104 ++++++++++++++++++++++++++++++++++\n sequencer.h                   |   4 ++\n t/t3404-rebase-interactive.sh |   2 +-\n 6 files changed, 124 insertions(+), 53 deletions(-)\n\ndiff --git a/builtin/rebase--helper.c b/builtin/rebase--helper.c\nindex bed3dd2b95..01b3333958 100644\n--- a/builtin/rebase--helper.c\n+++ b/builtin/rebase--helper.c\n@@ -13,13 +13,13 @@ static const char * const builtin_rebase_helper_usage[] = {\n int cmd_rebase__helper(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;\n+\tunsigned flags = 0, keep_empty = 0, rebase_merges = 0, autosquash = 0;\n \tint abbreviate_commands = 0, rebase_cousins = -1;\n \tenum {\n \t\tCONTINUE = 1, ABORT, MAKE_SCRIPT, SHORTEN_OIDS, EXPAND_OIDS,\n \t\tCHECK_TODO_LIST, SKIP_UNNECESSARY_PICKS, REARRANGE_SQUASH,\n \t\tADD_EXEC, APPEND_TODO_HELP, EDIT_TODO, PREPARE_BRANCH,\n-\t\tCHECKOUT_ONTO\n+\t\tCHECKOUT_ONTO, COMPLETE_ACTION\n \t} command = 0;\n \tstruct option options[] = {\n \t\tOPT_BOOL(0, \"ff\", &opts.allow_ff, N_(\"allow fast-forward\")),\n@@ -29,6 +29,8 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\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__VERBOSE(&opts.verbose, N_(\"be verbose\")),\n \t\tOPT_CMDMODE(0, \"continue\", &command, N_(\"continue rebase\"),\n \t\t\t\tCONTINUE),\n@@ -57,6 +59,8 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\n \t\t\t    N_(\"prepare the branch to be rebased\"), PREPARE_BRANCH),\n \t\tOPT_CMDMODE(0, \"checkout-onto\", &command,\n \t\t\t    N_(\"checkout a commit\"), CHECKOUT_ONTO),\n+\t\tOPT_CMDMODE(0, \"complete-action\", &command,\n+\t\t\t    N_(\"complete the action\"), COMPLETE_ACTION),\n \t\tOPT_END()\n \t};\n \n@@ -110,5 +114,9 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\n \t\treturn !!prepare_branch_to_be_rebased(&opts, argv[1]);\n \tif (command == CHECKOUT_ONTO && argc == 4)\n \t\treturn !!checkout_onto(&opts, argv[1], argv[2], argv[3]);\n+\tif (command == COMPLETE_ACTION && argc == 6)\n+\t\treturn !!complete_action(&opts, flags, argv[1], argv[2], argv[3],\n+\t\t\t\t\t argv[4], argv[5], autosquash);\n+\n \tusage_with_options(builtin_rebase_helper_usage, options);\n }\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex b68f108f28..59dc4888a6 100644\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -127,54 +127,6 @@ init_revisions_and_shortrevisions () {\n \tfi\n }\n \n-complete_action() {\n-\ttest -s \"$todo\" || echo noop >> \"$todo\"\n-\ttest -z \"$autosquash\" || git rebase--helper --rearrange-squash || exit\n-\ttest -n \"$cmd\" && git rebase--helper --add-exec-commands \"$cmd\"\n-\n-\ttodocount=$(git stripspace --strip-comments <\"$todo\" | wc -l)\n-\ttodocount=${todocount##* }\n-\n-cat >>\"$todo\" <<EOF\n-\n-$comment_char $(eval_ngettext \\\n-\t\"Rebase \\$shortrevisions onto \\$shortonto (\\$todocount command)\" \\\n-\t\"Rebase \\$shortrevisions onto \\$shortonto (\\$todocount commands)\" \\\n-\t\"$todocount\")\n-EOF\n-\tgit rebase--helper --append-todo-help ${keep_empty:+--keep-empty}\n-\n-\thas_action \"$todo\" ||\n-\t\treturn 2\n-\n-\tcp \"$todo\" \"$todo\".backup\n-\tcollapse_todo_ids\n-\tgit_sequence_editor \"$todo\" ||\n-\t\tdie_abort \"$(gettext \"Could not execute editor\")\"\n-\n-\thas_action \"$todo\" ||\n-\t\treturn 2\n-\n-\tgit rebase--helper --check-todo-list || {\n-\t\tret=$?\n-\t\tgit rebase--helper --checkout-onto \"$onto_name\" \"$onto\" \\\n-\t\t    \"$orig_head\" ${verbose:+--verbose}\n-\t\texit $ret\n-\t}\n-\n-\texpand_todo_ids\n-\n-\ttest -n \"$force_rebase\" ||\n-\tonto=\"$(git rebase--helper --skip-unnecessary-picks)\" ||\n-\tdie \"Could not skip unnecessary pick commands\"\n-\n-\tgit rebase--helper --checkout-onto \"$onto_name\" \"$onto\" \"$orig_head\" \\\n-\t    ${verbose:+--verbose}\n-\trequire_clean_work_tree \"rebase\"\n-\texec git rebase--helper ${force_rebase:+--no-ff} $allow_empty_message \\\n-\t     --continue\n-}\n-\n git_rebase__interactive () {\n \tinitiate_action \"$action\"\n \tret=$?\n@@ -193,5 +145,8 @@ git_rebase__interactive () {\n \t\t$revisions ${restrict_revision+^$restrict_revision} >\"$todo\" ||\n \tdie \"$(gettext \"Could not generate todo list\")\"\n \n-\tcomplete_action\n+\texec git rebase--helper --complete-action \"$shortrevisions\" \"$onto_name\" \\\n+\t\t\"$shortonto\" \"$orig_head\" \"$cmd\" $allow_empty_message \\\n+\t\t${autosquash:+--autosquash} ${keep_empty:+--keep-empty} \\\n+\t\t${verbose:+--verbose} ${force_rebase:+--no-ff}\n }\ndiff --git a/git-rebase.sh b/git-rebase.sh\nindex 7973447645..51a6db7daa 100755\n--- a/git-rebase.sh\n+++ b/git-rebase.sh\n@@ -219,7 +219,7 @@ run_specific_rebase () {\n \tif test $ret -eq 0\n \tthen\n \t\tfinish_rebase\n-\telif test $ret -eq 2 # special exit status for rebase -i\n+\telif test $ret -eq 2 # special exit status for rebase -p\n \tthen\n \t\tapply_autostash &&\n \t\trm -rf \"$state_dir\" &&\ndiff --git a/sequencer.c b/sequencer.c\nindex a56a781539..241195a8be 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -30,6 +30,7 @@\n #include \"oidset.h\"\n #include \"commit-slab.h\"\n #include \"alias.h\"\n+#include \"rebase-interactive.h\"\n \n #define GIT_REFLOG_ACTION \"GIT_REFLOG_ACTION\"\n \n@@ -53,6 +54,9 @@ static GIT_PATH_FUNC(rebase_path, \"rebase-merge\")\n  * file and written to the tail of 'done'.\n  */\n GIT_PATH_FUNC(rebase_path_todo, \"rebase-merge/git-rebase-todo\")\n+static GIT_PATH_FUNC(rebase_path_todo_backup,\n+\t\t     \"rebase-merge/git-rebase-todo.backup\")\n+\n /*\n  * The rebase command lines that have already been processed. A line\n  * is moved here when it is first handled, before any associated user\n@@ -4499,6 +4503,106 @@ int skip_unnecessary_picks(struct object_id *output_oid)\n \treturn 0;\n }\n \n+int complete_action(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, const char *cmd,\n+\t\t    unsigned autosquash)\n+{\n+\tconst char *shortonto, *todo_file = rebase_path_todo();\n+\tstruct todo_list todo_list = TODO_LIST_INIT;\n+\tstruct strbuf *buf = &(todo_list.buf);\n+\tstruct object_id oid;\n+\tstruct stat st;\n+\n+\tget_oid(onto, &oid);\n+\tshortonto = find_unique_abbrev(&oid, DEFAULT_ABBREV);\n+\n+\tif (!lstat(todo_file, &st) && st.st_size == 0 &&\n+\t    write_message(\"noop\\n\", 5, todo_file, 0))\n+\t\treturn -1;\n+\n+\tif (autosquash && rearrange_squash())\n+\t\treturn -1;\n+\n+\tif (cmd && *cmd)\n+\t\tsequencer_add_exec_commands(cmd);\n+\n+\tif (strbuf_read_file(buf, todo_file, 0) < 0)\n+\t\treturn error_errno(_(\"could not read '%s'.\"), todo_file);\n+\n+\tif (parse_insn_buffer(buf->buf, &todo_list)) {\n+\t\ttodo_list_release(&todo_list);\n+\t\treturn error(_(\"unusable todo list: '%s'\"), todo_file);\n+\t}\n+\n+\tif (count_commands(&todo_list) == 0) {\n+\t\tapply_autostash(opts);\n+\t\tsequencer_remove_state(opts);\n+\t\ttodo_list_release(&todo_list);\n+\n+\t\treturn error(_(\"nothing to do\"));\n+\t}\n+\n+\tstrbuf_addch(buf, '\\n');\n+\tstrbuf_commented_addf(buf, Q_(\"Rebase %s onto %s (%d command)\",\n+\t\t\t\t      \"Rebase %s onto %s (%d commands)\",\n+\t\t\t\t      count_commands(&todo_list)),\n+\t\t\t      shortrevisions, shortonto, count_commands(&todo_list));\n+\tappend_todo_help(0, flags & TODO_LIST_KEEP_EMPTY, buf);\n+\n+\tif (write_message(buf->buf, buf->len, todo_file, 0)) {\n+\t\ttodo_list_release(&todo_list);\n+\t\treturn -1;\n+\t}\n+\n+\tif (copy_file(rebase_path_todo_backup(), todo_file, 0666))\n+\t\treturn error(_(\"could not copy '%s' to '%s'.\"), todo_file,\n+\t\t\t     rebase_path_todo_backup());\n+\n+\tif (transform_todos(flags | TODO_LIST_SHORTEN_IDS))\n+\t\treturn error(_(\"could not transform the todo list\"));\n+\n+\tstrbuf_reset(buf);\n+\n+\tif (launch_sequence_editor(todo_file, buf, NULL)) {\n+\t\tapply_autostash(opts);\n+\t\tsequencer_remove_state(opts);\n+\t\ttodo_list_release(&todo_list);\n+\n+\t\treturn -1;\n+\t}\n+\n+\tstrbuf_stripspace(buf, 1);\n+\tif (buf->len == 0) {\n+\t\tapply_autostash(opts);\n+\t\tsequencer_remove_state(opts);\n+\t\ttodo_list_release(&todo_list);\n+\n+\t\treturn error(_(\"nothing to do\"));\n+\t}\n+\n+\ttodo_list_release(&todo_list);\n+\n+\tif (check_todo_list()) {\n+\t\tcheckout_onto(opts, onto_name, onto, orig_head);\n+\t\treturn -1;\n+\t}\n+\n+\tif (transform_todos(flags & ~(TODO_LIST_SHORTEN_IDS)))\n+\t\treturn error(_(\"could not transform the todo list\"));\n+\n+\tif (opts->allow_ff && skip_unnecessary_picks(&oid))\n+\t\treturn error(_(\"could not skip unnecessary pick commands\"));\n+\n+\tif (checkout_onto(opts, onto_name, oid_to_hex(&oid), orig_head))\n+\t\treturn -1;\n+;\n+\tif (require_clean_work_tree(\"rebase\", \"\", 1, 1))\n+\t\treturn -1;\n+\n+\treturn sequencer_continue(opts);\n+}\n+\n struct subject2item_entry {\n \tstruct hashmap_entry entry;\n \tint i;\ndiff --git a/sequencer.h b/sequencer.h\nindex fcbcd246c2..d58766c6d7 100644\n--- a/sequencer.h\n+++ b/sequencer.h\n@@ -92,6 +92,10 @@ int transform_todos(unsigned flags);\n enum missing_commit_check_level get_missing_commit_check_level(void);\n int check_todo_list(void);\n int skip_unnecessary_picks(struct object_id *output_oid);\n+int complete_action(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, const char *cmd,\n+\t\t    unsigned autosquash);\n int rearrange_squash(void);\n \n extern const char sign_off_header[];\ndiff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh\nindex 496d88d7d6..12d3ed8396 100755\n--- a/t/t3404-rebase-interactive.sh\n+++ b/t/t3404-rebase-interactive.sh\n@@ -76,7 +76,7 @@ test_expect_success 'rebase --keep-empty' '\n '\n \n cat > expect <<EOF\n-Nothing to do\n+error: nothing to do\n EOF\n \n test_expect_success 'rebase -i with empty HEAD' '\n-- \n2.18.0\n\n"},{"id":"356672","messageId":"20180828121045.14933-13-alban.gruin@gmail.com","threadId":"48814","inReplyTo":"20180828121045.14933-1-alban.gruin@gmail.com","subject":"[GSoC][PATCH v7 12/20] rebase -i: remove unused modes and functions","fromName":"Alban Gruin","fromEmail":"alban.gruin@gmail.com","sentAt":"2018-08-28T12:10:37Z","receivedAt":"2018-08-28T12:11:25Z","isPatch":true,"sender":{"key":"alban.gruin@gmail.com","avatar":"https://avatars.githubusercontent.com/u/6310153?v=4"},"body":"This removes the modes `--skip-unnecessary-picks`, `--append-todo-help`,\nand `--checkout-onto` from rebase--helper.c, the functions of\ngit-rebase--interactive.sh that were rendered useless by the rewrite of\ncomplete_action(), and append_todo_help_to_file() from\nrebase-interactive.c.\n\nskip_unnecessary_picks() and checkout_onto() becomes static, as they are\nonly used inside of the sequencer.\n\nSigned-off-by: Alban Gruin <alban.gruin@gmail.com>\n---\nNo changes since v6.\n\n builtin/rebase--helper.c   | 23 ++----------------\n git-rebase--interactive.sh | 50 --------------------------------------\n rebase-interactive.c       | 22 -----------------\n rebase-interactive.h       |  1 -\n sequencer.c                |  8 +++---\n sequencer.h                |  4 ---\n 6 files changed, 6 insertions(+), 102 deletions(-)\n\ndiff --git a/builtin/rebase--helper.c b/builtin/rebase--helper.c\nindex 01b3333958..e1460136f5 100644\n--- a/builtin/rebase--helper.c\n+++ b/builtin/rebase--helper.c\n@@ -17,9 +17,8 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\n \tint abbreviate_commands = 0, rebase_cousins = -1;\n \tenum {\n \t\tCONTINUE = 1, ABORT, MAKE_SCRIPT, SHORTEN_OIDS, EXPAND_OIDS,\n-\t\tCHECK_TODO_LIST, SKIP_UNNECESSARY_PICKS, REARRANGE_SQUASH,\n-\t\tADD_EXEC, APPEND_TODO_HELP, EDIT_TODO, PREPARE_BRANCH,\n-\t\tCHECKOUT_ONTO, COMPLETE_ACTION\n+\t\tCHECK_TODO_LIST, REARRANGE_SQUASH, ADD_EXEC, EDIT_TODO, PREPARE_BRANCH,\n+\t\tCOMPLETE_ACTION\n \t} command = 0;\n \tstruct option options[] = {\n \t\tOPT_BOOL(0, \"ff\", &opts.allow_ff, N_(\"allow fast-forward\")),\n@@ -44,21 +43,15 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\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, \"skip-unnecessary-picks\", &command,\n-\t\t\tN_(\"skip unnecessary picks\"), SKIP_UNNECESSARY_PICKS),\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_CMDMODE(0, \"append-todo-help\", &command,\n-\t\t\t    N_(\"insert the help in the todo list\"), APPEND_TODO_HELP),\n \t\tOPT_CMDMODE(0, \"edit-todo\", &command,\n \t\t\t    N_(\"edit the todo list during an interactive rebase\"),\n \t\t\t    EDIT_TODO),\n \t\tOPT_CMDMODE(0, \"prepare-branch\", &command,\n \t\t\t    N_(\"prepare the branch to be rebased\"), PREPARE_BRANCH),\n-\t\tOPT_CMDMODE(0, \"checkout-onto\", &command,\n-\t\t\t    N_(\"checkout a commit\"), CHECKOUT_ONTO),\n \t\tOPT_CMDMODE(0, \"complete-action\", &command,\n \t\t\t    N_(\"complete the action\"), COMPLETE_ACTION),\n \t\tOPT_END()\n@@ -94,26 +87,14 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\n \t\treturn !!transform_todos(flags);\n \tif (command == CHECK_TODO_LIST && argc == 1)\n \t\treturn !!check_todo_list();\n-\tif (command == SKIP_UNNECESSARY_PICKS && argc == 1) {\n-\t\tstruct object_id oid;\n-\t\tint ret = skip_unnecessary_picks(&oid);\n-\n-\t\tif (!ret)\n-\t\t\tputs(oid_to_hex(&oid));\n-\t\treturn !!ret;\n-\t}\n \tif (command == REARRANGE_SQUASH && argc == 1)\n \t\treturn !!rearrange_squash();\n \tif (command == ADD_EXEC && argc == 2)\n \t\treturn !!sequencer_add_exec_commands(argv[1]);\n-\tif (command == APPEND_TODO_HELP && argc == 1)\n-\t\treturn !!append_todo_help_to_file(0, keep_empty);\n \tif (command == EDIT_TODO && argc == 1)\n \t\treturn !!edit_todo_list(flags);\n \tif (command == PREPARE_BRANCH && argc == 2)\n \t\treturn !!prepare_branch_to_be_rebased(&opts, argv[1]);\n-\tif (command == CHECKOUT_ONTO && argc == 4)\n-\t\treturn !!checkout_onto(&opts, argv[1], argv[2], argv[3]);\n \tif (command == COMPLETE_ACTION && argc == 6)\n \t\treturn !!complete_action(&opts, flags, argv[1], argv[2], argv[3],\n \t\t\t\t\t argv[4], argv[5], autosquash);\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex 59dc4888a6..0d66c0f8b8 100644\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -16,56 +16,6 @@ todo=\"$state_dir\"/git-rebase-todo\n GIT_CHERRY_PICK_HELP=\"$resolvemsg\"\n export GIT_CHERRY_PICK_HELP\n \n-comment_char=$(git config --get core.commentchar 2>/dev/null)\n-case \"$comment_char\" in\n-'' | auto)\n-\tcomment_char=\"#\"\n-\t;;\n-?)\n-\t;;\n-*)\n-\tcomment_char=$(echo \"$comment_char\" | cut -c1)\n-\t;;\n-esac\n-\n-die_abort () {\n-\tapply_autostash\n-\trm -rf \"$state_dir\"\n-\tdie \"$1\"\n-}\n-\n-has_action () {\n-\ttest -n \"$(git stripspace --strip-comments <\"$1\")\"\n-}\n-\n-git_sequence_editor () {\n-\tif test -z \"$GIT_SEQUENCE_EDITOR\"\n-\tthen\n-\t\tGIT_SEQUENCE_EDITOR=\"$(git config sequence.editor)\"\n-\t\tif [ -z \"$GIT_SEQUENCE_EDITOR\" ]\n-\t\tthen\n-\t\t\tGIT_SEQUENCE_EDITOR=\"$(git var GIT_EDITOR)\" || return $?\n-\t\tfi\n-\tfi\n-\n-\teval \"$GIT_SEQUENCE_EDITOR\" '\"$@\"'\n-}\n-\n-expand_todo_ids() {\n-\tgit rebase--helper --expand-ids\n-}\n-\n-collapse_todo_ids() {\n-\tgit rebase--helper --shorten-ids\n-}\n-\n-get_missing_commit_check_level () {\n-\tcheck_level=$(git config --get rebase.missingCommitsCheck)\n-\tcheck_level=${check_level:-ignore}\n-\t# Don't be case sensitive\n-\tprintf '%s' \"$check_level\" | tr 'A-Z' 'a-z'\n-}\n-\n # Initiate an action. If the cannot be any\n # further action it  may exec a command\n # or exit and not return.\ndiff --git a/rebase-interactive.c b/rebase-interactive.c\nindex 4a9a10eff4..0f4119cbae 100644\n--- a/rebase-interactive.c\n+++ b/rebase-interactive.c\n@@ -52,28 +52,6 @@ void append_todo_help(unsigned edit_todo, unsigned keep_empty,\n \t}\n }\n \n-int append_todo_help_to_file(unsigned edit_todo, unsigned keep_empty)\n-{\n-\tstruct strbuf buf = STRBUF_INIT;\n-\tFILE *todo;\n-\tint ret;\n-\n-\ttodo = fopen_or_warn(rebase_path_todo(), \"a\");\n-\tif (!todo)\n-\t\treturn -1;\n-\n-\tappend_todo_help(edit_todo, keep_empty, &buf);\n-\n-\tret = fputs(buf.buf, todo);\n-\tif (ret < 0)\n-\t\terror_errno(_(\"could not append help text to '%s'\"), rebase_path_todo());\n-\n-\tfclose(todo);\n-\tstrbuf_release(&buf);\n-\n-\treturn ret;\n-}\n-\n int edit_todo_list(unsigned flags)\n {\n \tstruct strbuf buf = STRBUF_INIT;\ndiff --git a/rebase-interactive.h b/rebase-interactive.h\nindex d33f3176b7..971da03776 100644\n--- a/rebase-interactive.h\n+++ b/rebase-interactive.h\n@@ -3,7 +3,6 @@\n \n void append_todo_help(unsigned edit_todo, unsigned keep_empty,\n \t\t      struct strbuf *buf);\n-int append_todo_help_to_file(unsigned edit_todo, unsigned keep_empty);\n int edit_todo_list(unsigned flags);\n \n #endif\ndiff --git a/sequencer.c b/sequencer.c\nindex 241195a8be..fe0b52f08e 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -3175,9 +3175,9 @@ int prepare_branch_to_be_rebased(struct replay_opts *opts, const char *commit)\n \treturn 0;\n }\n \n-int checkout_onto(struct replay_opts *opts,\n-\t\t  const char *onto_name, const char *onto,\n-\t\t  const char *orig_head)\n+static int checkout_onto(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 \tstruct object_id oid;\n \tconst char *action = reflog_message(opts, \"start\", \"checkout %s\", onto_name);\n@@ -4424,7 +4424,7 @@ static int rewrite_file(const char *path, const char *buf, size_t len)\n }\n \n /* skip picking commits whose parents are unchanged */\n-int skip_unnecessary_picks(struct object_id *output_oid)\n+static int skip_unnecessary_picks(struct object_id *output_oid)\n {\n \tconst char *todo_file = rebase_path_todo();\n \tstruct strbuf buf = STRBUF_INIT;\ndiff --git a/sequencer.h b/sequencer.h\nindex d58766c6d7..02e3d7940e 100644\n--- a/sequencer.h\n+++ b/sequencer.h\n@@ -91,7 +91,6 @@ int sequencer_add_exec_commands(const char *command);\n int transform_todos(unsigned flags);\n enum missing_commit_check_level get_missing_commit_check_level(void);\n int check_todo_list(void);\n-int skip_unnecessary_picks(struct object_id *output_oid);\n int complete_action(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, const char *cmd,\n@@ -114,9 +113,6 @@ void commit_post_rewrite(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 checkout_onto(struct replay_opts *opts,\n-\t\t  const char *onto_name, const char *onto,\n-\t\t  const char *orig_head);\n \n #define SUMMARY_INITIAL_COMMIT   (1 << 0)\n #define SUMMARY_SHOW_AUTHOR_DATE (1 << 1)\n-- \n2.18.0\n\n"},{"id":"356673","messageId":"20180828121045.14933-14-alban.gruin@gmail.com","threadId":"48814","inReplyTo":"20180828121045.14933-1-alban.gruin@gmail.com","subject":"[GSoC][PATCH v7 13/20] rebase -i: implement the logic to initialize $revisions in C","fromName":"Alban Gruin","fromEmail":"alban.gruin@gmail.com","sentAt":"2018-08-28T12:10:38Z","receivedAt":"2018-08-28T12:11:26Z","isPatch":true,"sender":{"key":"alban.gruin@gmail.com","avatar":"https://avatars.githubusercontent.com/u/6310153?v=4"},"body":"This rewrites the part of init_revisions_and_shortrevisions() needed by\n`--make-script` from shell to C.  The new version is called\nget_revision_ranges(), and is a static function inside of\nrebase--helper.c.  As this does not initialize $shortrevision, the\noriginal shell version is not yet stripped.\n\nUnlike init_revisions_and_shortrevisions(), get_revision_ranges()\ndoesn’t write $squash_onto to the state directory, it’s done by the\nhandler of `--make-script` instead.\n\nFinally, this drops the $revision argument passed to `--make-script` in\ngit-rebase--interactive.sh, and rebase--helper is changed accordingly.\n\nSigned-off-by: Alban Gruin <alban.gruin@gmail.com>\n---\nNo changes since v6.\n\n builtin/rebase--helper.c   | 56 ++++++++++++++++++++++++++++++++++++--\n git-rebase--interactive.sh |  4 ++-\n 2 files changed, 56 insertions(+), 4 deletions(-)\n\ndiff --git a/builtin/rebase--helper.c b/builtin/rebase--helper.c\nindex e1460136f5..acc71a6f99 100644\n--- a/builtin/rebase--helper.c\n+++ b/builtin/rebase--helper.c\n@@ -4,6 +4,25 @@\n #include \"parse-options.h\"\n #include \"sequencer.h\"\n #include \"rebase-interactive.h\"\n+#include \"argv-array.h\"\n+\n+static GIT_PATH_FUNC(path_squash_onto, \"rebase-merge/squash-onto\")\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)\n+{\n+\tconst char *base_rev = upstream ? upstream : onto;\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+\treturn 0;\n+}\n \n static const char * const builtin_rebase_helper_usage[] = {\n \tN_(\"git rebase--helper [<options>]\"),\n@@ -14,7 +33,9 @@ int cmd_rebase__helper(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;\n+\tint abbreviate_commands = 0, rebase_cousins = -1, ret;\n+\tconst char *head_hash = NULL, *onto = NULL, *restrict_revision = NULL,\n+\t\t*squash_onto = NULL, *upstream = NULL;\n \tenum {\n \t\tCONTINUE = 1, ABORT, MAKE_SCRIPT, SHORTEN_OIDS, EXPAND_OIDS,\n \t\tCHECK_TODO_LIST, REARRANGE_SQUASH, ADD_EXEC, EDIT_TODO, PREPARE_BRANCH,\n@@ -54,6 +75,13 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\n \t\t\t    N_(\"prepare the branch to be rebased\"), PREPARE_BRANCH),\n \t\tOPT_CMDMODE(0, \"complete-action\", &command,\n \t\t\t    N_(\"complete the action\"), COMPLETE_ACTION),\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_END()\n \t};\n \n@@ -81,8 +109,30 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\n \t\treturn !!sequencer_continue(&opts);\n \tif (command == ABORT && argc == 1)\n \t\treturn !!sequencer_remove_state(&opts);\n-\tif (command == MAKE_SCRIPT && argc > 1)\n-\t\treturn !!sequencer_make_script(stdout, argc, argv, flags);\n+\tif (command == MAKE_SCRIPT && argc == 1) {\n+\t\tchar *revisions = NULL;\n+\t\tstruct argv_array make_script_args = ARGV_ARRAY_INIT;\n+\n+\t\tif (!upstream && squash_onto)\n+\t\t\twrite_file(path_squash_onto(), \"%s\\n\", squash_onto);\n+\n+\t\tret = get_revision_ranges(upstream, onto, &head_hash, &revisions);\n+\t\tif (ret)\n+\t\t\treturn ret;\n+\n+\t\targv_array_pushl(&make_script_args, \"\", revisions, NULL);\n+\t\tif (restrict_revision)\n+\t\t\targv_array_push(&make_script_args, restrict_revision);\n+\n+\t\tret = sequencer_make_script(stdout,\n+\t\t\t\t\t    make_script_args.argc, make_script_args.argv,\n+\t\t\t\t\t    flags);\n+\n+\t\tfree(revisions);\n+\t\targv_array_clear(&make_script_args);\n+\n+\t\treturn !!ret;\n+\t}\n \tif ((command == SHORTEN_OIDS || command == EXPAND_OIDS) && argc == 1)\n \t\treturn !!transform_todos(flags);\n \tif (command == CHECK_TODO_LIST && argc == 1)\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex 0d66c0f8b8..4ca47aed1e 100644\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -92,7 +92,9 @@ git_rebase__interactive () {\n \tgit rebase--helper --make-script ${keep_empty:+--keep-empty} \\\n \t\t${rebase_merges:+--rebase-merges} \\\n \t\t${rebase_cousins:+--rebase-cousins} \\\n-\t\t$revisions ${restrict_revision+^$restrict_revision} >\"$todo\" ||\n+\t\t${upstream:+--upstream \"$upstream\"} ${onto:+--onto \"$onto\"} \\\n+\t\t${squash_onto:+--squash-onto \"$squash_onto\"} \\\n+\t\t${restrict_revision:+--restrict-revision ^\"$restrict_revision\"} >\"$todo\" ||\n \tdie \"$(gettext \"Could not generate todo list\")\"\n \n \texec git rebase--helper --complete-action \"$shortrevisions\" \"$onto_name\" \\\n-- \n2.18.0\n\n"},{"id":"356667","messageId":"20180828121045.14933-15-alban.gruin@gmail.com","threadId":"48814","inReplyTo":"20180828121045.14933-1-alban.gruin@gmail.com","subject":"[GSoC][PATCH v7 14/20] rebase -i: rewrite the rest of init_revisions_and_shortrevisions() in C","fromName":"Alban Gruin","fromEmail":"alban.gruin@gmail.com","sentAt":"2018-08-28T12:10:39Z","receivedAt":"2018-08-28T12:11:28Z","isPatch":true,"sender":{"key":"alban.gruin@gmail.com","avatar":"https://avatars.githubusercontent.com/u/6310153?v=4"},"body":"This rewrites the part of init_revisions_and_shortrevisions() needed by\n`--complete-action` (which initialize $shortrevisions) from shell to C.\n\nWhen `upstream` is empty, it means that the user launched a `rebase\n--root`, and `onto` contains the ID of an empty commit.  As a range\nbetween an empty commit and `head` is not really meaningful, `onto` is\nnot used to initialize `shortrevisions` in this case.\n\nThe corresponding arguments passed to `--complete-action` are then\ndropped, and init_revisions_and_shortrevisions() is stripped from\ngit-rebase--interactive.sh\n\nSigned-off-by: Alban Gruin <alban.gruin@gmail.com>\n---\nNo changes since v6.\n\n builtin/rebase--helper.c   | 40 ++++++++++++++++++++++++++++++++------\n git-rebase--interactive.sh | 27 ++++---------------------\n 2 files changed, 38 insertions(+), 29 deletions(-)\n\ndiff --git a/builtin/rebase--helper.c b/builtin/rebase--helper.c\nindex acc71a6f99..0716bbfd78 100644\n--- a/builtin/rebase--helper.c\n+++ b/builtin/rebase--helper.c\n@@ -10,7 +10,7 @@ static GIT_PATH_FUNC(path_squash_onto, \"rebase-merge/squash-onto\")\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)\n+\t\t\t       char **revisions, char **shortrevisions)\n {\n \tconst char *base_rev = upstream ? upstream : onto;\n \tstruct object_id orig_head;\n@@ -19,7 +19,25 @@ static int get_revision_ranges(const char *upstream, const char *onto,\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+\tif (revisions)\n+\t\t*revisions = xstrfmt(\"%s...%s\", base_rev, *head_hash);\n+\tif (shortrevisions) {\n+\t\tconst char *shorthead;\n+\n+\t\tshorthead = find_unique_abbrev(&orig_head, DEFAULT_ABBREV);\n+\n+\t\tif (upstream) {\n+\t\t\tconst char *shortrev;\n+\t\t\tstruct object_id rev_oid;\n+\n+\t\t\tget_oid(base_rev, &rev_oid);\n+\t\t\tshortrev = find_unique_abbrev(&rev_oid, DEFAULT_ABBREV);\n+\n+\t\t\t*shortrevisions = xstrfmt(\"%s..%s\", shortrev, shorthead);\n+\t\t} else\n+\t\t\t*shortrevisions = xstrdup(shorthead);\n+\t}\n \n \treturn 0;\n }\n@@ -116,7 +134,7 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\n \t\tif (!upstream && squash_onto)\n \t\t\twrite_file(path_squash_onto(), \"%s\\n\", squash_onto);\n \n-\t\tret = get_revision_ranges(upstream, onto, &head_hash, &revisions);\n+\t\tret = get_revision_ranges(upstream, onto, &head_hash, &revisions, NULL);\n \t\tif (ret)\n \t\t\treturn ret;\n \n@@ -145,9 +163,19 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\n \t\treturn !!edit_todo_list(flags);\n \tif (command == PREPARE_BRANCH && argc == 2)\n \t\treturn !!prepare_branch_to_be_rebased(&opts, argv[1]);\n-\tif (command == COMPLETE_ACTION && argc == 6)\n-\t\treturn !!complete_action(&opts, flags, argv[1], argv[2], argv[3],\n-\t\t\t\t\t argv[4], argv[5], autosquash);\n+\tif (command == COMPLETE_ACTION && argc == 3) {\n+\t\tchar *shortrevisions = NULL;\n+\n+\t\tret = get_revision_ranges(upstream, onto, &head_hash, NULL, &shortrevisions);\n+\t\tif (ret)\n+\t\t\treturn ret;\n+\n+\t\tret = complete_action(&opts, flags, shortrevisions, argv[1], onto,\n+\t\t\t\t      head_hash, argv[2], autosquash);\n+\n+\t\tfree(shortrevisions);\n+\t\treturn !!ret;\n+\t}\n \n \tusage_with_options(builtin_rebase_helper_usage, options);\n }\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex 4ca47aed1e..08e9a21c2f 100644\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -60,23 +60,6 @@ init_basic_state () {\n \twrite_basic_state\n }\n \n-init_revisions_and_shortrevisions () {\n-\tshorthead=$(git rev-parse --short $orig_head)\n-\tshortonto=$(git rev-parse --short $onto)\n-\tif test -z \"$rebase_root\"\n-\t\t# this is now equivalent to ! -z \"$upstream\"\n-\tthen\n-\t\tshortupstream=$(git rev-parse --short $upstream)\n-\t\trevisions=$upstream...$orig_head\n-\t\tshortrevisions=$shortupstream..$shorthead\n-\telse\n-\t\trevisions=$onto...$orig_head\n-\t\tshortrevisions=$shorthead\n-\t\ttest -z \"$squash_onto\" ||\n-\t\techo \"$squash_onto\" >\"$state_dir\"/squash-onto\n-\tfi\n-}\n-\n git_rebase__interactive () {\n \tinitiate_action \"$action\"\n \tret=$?\n@@ -87,8 +70,6 @@ git_rebase__interactive () {\n \tgit rebase--helper --prepare-branch \"$switch_to\" ${verbose:+--verbose}\n \tinit_basic_state\n \n-\tinit_revisions_and_shortrevisions\n-\n \tgit rebase--helper --make-script ${keep_empty:+--keep-empty} \\\n \t\t${rebase_merges:+--rebase-merges} \\\n \t\t${rebase_cousins:+--rebase-cousins} \\\n@@ -97,8 +78,8 @@ git_rebase__interactive () {\n \t\t${restrict_revision:+--restrict-revision ^\"$restrict_revision\"} >\"$todo\" ||\n \tdie \"$(gettext \"Could not generate todo list\")\"\n \n-\texec git rebase--helper --complete-action \"$shortrevisions\" \"$onto_name\" \\\n-\t\t\"$shortonto\" \"$orig_head\" \"$cmd\" $allow_empty_message \\\n-\t\t${autosquash:+--autosquash} ${keep_empty:+--keep-empty} \\\n-\t\t${verbose:+--verbose} ${force_rebase:+--no-ff}\n+\texec git rebase--helper --complete-action \"$onto_name\" \"$cmd\" \\\n+\t\t$allow_empty_message ${autosquash:+--autosquash} ${verbose:+--verbose} \\\n+\t\t${keep_empty:+--keep-empty} ${force_rebase:+--no-ff} \\\n+\t\t${upstream:+--upstream \"$upstream\"} ${onto:+--onto \"$onto\"}\n }\n-- \n2.18.0\n\n"},{"id":"356679","messageId":"20180828121045.14933-17-alban.gruin@gmail.com","threadId":"48814","inReplyTo":"20180828121045.14933-1-alban.gruin@gmail.com","subject":"[GSoC][PATCH v7 16/20] rebase -i: rewrite init_basic_state() in C","fromName":"Alban Gruin","fromEmail":"alban.gruin@gmail.com","sentAt":"2018-08-28T12:10:41Z","receivedAt":"2018-08-28T12:11:31Z","isPatch":true,"sender":{"key":"alban.gruin@gmail.com","avatar":"https://avatars.githubusercontent.com/u/6310153?v=4"},"body":"This rewrites init_basic_state() from shell to C.  The call to\nwrite_basic_state() in cmd_rebase__helper() is replaced by a call to the\nnew function.\n\nThe shell version is then stripped from git-rebase--interactive.sh.\n\nSigned-off-by: Alban Gruin <alban.gruin@gmail.com>\n---\nNo changes since v6.\n\n builtin/rebase--helper.c   | 23 ++++++++++++++++++++++-\n git-rebase--interactive.sh |  9 ---------\n 2 files changed, 22 insertions(+), 10 deletions(-)\n\ndiff --git a/builtin/rebase--helper.c b/builtin/rebase--helper.c\nindex 63c5086e42..f8128037d3 100644\n--- a/builtin/rebase--helper.c\n+++ b/builtin/rebase--helper.c\n@@ -5,10 +5,13 @@\n #include \"sequencer.h\"\n #include \"rebase-interactive.h\"\n #include \"argv-array.h\"\n+#include \"refs.h\"\n #include \"rerere.h\"\n #include \"alias.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 get_revision_ranges(const char *upstream, const char *onto,\n \t\t\t       const char **head_hash,\n@@ -44,6 +47,24 @@ static int get_revision_ranges(const char *upstream, const char *onto,\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 const char * const builtin_rebase_helper_usage[] = {\n \tN_(\"git rebase--helper [<options>]\"),\n \tNULL\n@@ -198,7 +219,7 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\n \t\tif (ret)\n \t\t\treturn ret;\n \n-\t\treturn !!write_basic_state(&opts, head_name, onto, head_hash);\n+\t\treturn !!init_basic_state(&opts, head_name, onto, head_hash);\n \t}\n \n \tusage_with_options(builtin_rebase_helper_usage, options);\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex 6367da66e2..761be95ed1 100644\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -51,14 +51,6 @@ initiate_action () {\n \tesac\n }\n \n-init_basic_state () {\n-\torig_head=$(git rev-parse --verify HEAD) || die \"$(gettext \"No HEAD?\")\"\n-\tmkdir -p \"$state_dir\" || die \"$(eval_gettext \"Could not create temporary \\$state_dir\")\"\n-\trm -f \"$(git rev-parse --git-path REBASE_HEAD)\"\n-\n-\t: > \"$state_dir\"/interactive || die \"$(gettext \"Could not mark as interactive\")\"\n-}\n-\n git_rebase__interactive () {\n \tinitiate_action \"$action\"\n \tret=$?\n@@ -67,7 +59,6 @@ git_rebase__interactive () {\n \tfi\n \n \tgit rebase--helper --prepare-branch \"$switch_to\" ${verbose:+--verbose}\n-\tinit_basic_state\n \n \tgit rebase--helper --init-basic-state ${upstream:+--upstream \"$upstream\"} \\\n \t\t${onto:+--onto \"$onto\"} ${head_name:+--head-name \"$head_name\"} \\\n-- \n2.18.0\n\n"},{"id":"356681","messageId":"20180828121045.14933-16-alban.gruin@gmail.com","threadId":"48814","inReplyTo":"20180828121045.14933-1-alban.gruin@gmail.com","subject":"[GSoC][PATCH v7 15/20] rebase -i: rewrite write_basic_state() in C","fromName":"Alban Gruin","fromEmail":"alban.gruin@gmail.com","sentAt":"2018-08-28T12:10:40Z","receivedAt":"2018-08-28T12:11:31Z","isPatch":true,"sender":{"key":"alban.gruin@gmail.com","avatar":"https://avatars.githubusercontent.com/u/6310153?v=4"},"body":"This rewrites write_basic_state() from git-rebase.sh in C.  This is the\nfirst step in the conversion of init_basic_state(), hence the mode in\nrebase--helper.c is called INIT_BASIC_STATE.  init_basic_state() will be\nconverted in the next commit.\n\nThe part of read_strategy_opts() that parses the stategy options is\nmoved to a new function to allow its use in rebase--helper.c.\n\nFinally, the call to write_basic_state() is removed from\ngit-rebase--interactive.sh, replaced by a call to `--init-basic-state`.\n\nSigned-off-by: Alban Gruin <alban.gruin@gmail.com>\n---\nNo changes since v6.\n\n builtin/rebase--helper.c   | 28 +++++++++++++-\n git-rebase--interactive.sh |  7 +++-\n sequencer.c                | 77 ++++++++++++++++++++++++++++++++------\n sequencer.h                |  4 ++\n 4 files changed, 102 insertions(+), 14 deletions(-)\n\ndiff --git a/builtin/rebase--helper.c b/builtin/rebase--helper.c\nindex 0716bbfd78..63c5086e42 100644\n--- a/builtin/rebase--helper.c\n+++ b/builtin/rebase--helper.c\n@@ -5,6 +5,8 @@\n #include \"sequencer.h\"\n #include \"rebase-interactive.h\"\n #include \"argv-array.h\"\n+#include \"rerere.h\"\n+#include \"alias.h\"\n \n static GIT_PATH_FUNC(path_squash_onto, \"rebase-merge/squash-onto\")\n \n@@ -53,11 +55,12 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\n \tunsigned flags = 0, keep_empty = 0, rebase_merges = 0, autosquash = 0;\n \tint abbreviate_commands = 0, rebase_cousins = -1, ret;\n \tconst char *head_hash = NULL, *onto = NULL, *restrict_revision = NULL,\n-\t\t*squash_onto = NULL, *upstream = NULL;\n+\t\t*squash_onto = NULL, *upstream = NULL, *head_name = NULL;\n+\tchar *raw_strategies = NULL;\n \tenum {\n \t\tCONTINUE = 1, ABORT, MAKE_SCRIPT, SHORTEN_OIDS, EXPAND_OIDS,\n \t\tCHECK_TODO_LIST, REARRANGE_SQUASH, ADD_EXEC, EDIT_TODO, PREPARE_BRANCH,\n-\t\tCOMPLETE_ACTION\n+\t\tCOMPLETE_ACTION, INIT_BASIC_STATE\n \t} command = 0;\n \tstruct option options[] = {\n \t\tOPT_BOOL(0, \"ff\", &opts.allow_ff, N_(\"allow fast-forward\")),\n@@ -69,6 +72,7 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\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\tCONTINUE),\n@@ -93,6 +97,8 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\n \t\t\t    N_(\"prepare the branch to be rebased\"), PREPARE_BRANCH),\n \t\tOPT_CMDMODE(0, \"complete-action\", &command,\n \t\t\t    N_(\"complete the action\"), COMPLETE_ACTION),\n+\t\tOPT_CMDMODE(0, \"init-basic-state\", &command,\n+\t\t\t    N_(\"initialise the rebase state\"), INIT_BASIC_STATE),\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@@ -100,6 +106,14 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\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\tOPT_STRING('S', \"gpg-sign\", &opts.gpg_sign, N_(\"gpg-sign\"),\n+\t\t\t   N_(\"GPG-sign commits\")),\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_RERERE_AUTOUPDATE(&opts.allow_rerere_auto),\n \t\tOPT_END()\n \t};\n \n@@ -176,6 +190,16 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\n \t\tfree(shortrevisions);\n \t\treturn !!ret;\n \t}\n+\tif (command == INIT_BASIC_STATE) {\n+\t\tif (raw_strategies)\n+\t\t\tparse_strategy_opts(&opts, raw_strategies);\n+\n+\t\tret = get_revision_ranges(upstream, onto, &head_hash, NULL, NULL);\n+\t\tif (ret)\n+\t\t\treturn ret;\n+\n+\t\treturn !!write_basic_state(&opts, head_name, onto, head_hash);\n+\t}\n \n \tusage_with_options(builtin_rebase_helper_usage, options);\n }\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex 08e9a21c2f..6367da66e2 100644\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -57,7 +57,6 @@ init_basic_state () {\n \trm -f \"$(git rev-parse --git-path REBASE_HEAD)\"\n \n \t: > \"$state_dir\"/interactive || die \"$(gettext \"Could not mark as interactive\")\"\n-\twrite_basic_state\n }\n \n git_rebase__interactive () {\n@@ -70,6 +69,12 @@ git_rebase__interactive () {\n \tgit rebase--helper --prepare-branch \"$switch_to\" ${verbose:+--verbose}\n \tinit_basic_state\n \n+\tgit rebase--helper --init-basic-state ${upstream:+--upstream \"$upstream\"} \\\n+\t\t${onto:+--onto \"$onto\"} ${head_name:+--head-name \"$head_name\"} \\\n+\t\t${verbose:+--verbose} ${strategy:+--strategy \"$strategy\"} \\\n+\t\t${strategy_opts:+--strategy-opts=\"$strategy_opts\"} \\\n+\t\t\"$allow_rerere_autoupdate\" \"$gpg_sign_opt\" \"$signoff\" || exit\n+\n \tgit rebase--helper --make-script ${keep_empty:+--keep-empty} \\\n \t\t${rebase_merges:+--rebase-merges} \\\n \t\t${rebase_cousins:+--rebase-cousins} \\\ndiff --git a/sequencer.c b/sequencer.c\nindex fe0b52f08e..24c45dcefd 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -144,7 +144,7 @@ static GIT_PATH_FUNC(rebase_path_refs_to_delete, \"rebase-merge/refs-to-delete\")\n \n /*\n  * The following files are written by git-rebase just after parsing the\n- * command-line (and are only consumed, not modified, by the sequencer).\n+ * command-line.\n  */\n static GIT_PATH_FUNC(rebase_path_gpg_sign_opt, \"rebase-merge/gpg_sign_opt\")\n static GIT_PATH_FUNC(rebase_path_orig_head, \"rebase-merge/orig-head\")\n@@ -156,6 +156,7 @@ static GIT_PATH_FUNC(rebase_path_autostash, \"rebase-merge/autostash\")\n static GIT_PATH_FUNC(rebase_path_strategy, \"rebase-merge/strategy\")\n static GIT_PATH_FUNC(rebase_path_strategy_opts, \"rebase-merge/strategy_opts\")\n static GIT_PATH_FUNC(rebase_path_allow_rerere_autoupdate, \"rebase-merge/allow_rerere_autoupdate\")\n+static GIT_PATH_FUNC(rebase_path_quiet, \"rebase-merge/quiet\")\n \n static int git_sequencer_config(const char *k, const char *v, void *cb)\n {\n@@ -2205,21 +2206,14 @@ static int populate_opts_cb(const char *key, const char *value, void *data)\n \treturn 0;\n }\n \n-static void read_strategy_opts(struct replay_opts *opts, struct strbuf *buf)\n+void parse_strategy_opts(struct replay_opts *opts, char *raw_opts)\n {\n \tint i;\n-\tchar *strategy_opts_string;\n+\tchar *strategy_opts_string = raw_opts;\n \n-\tstrbuf_reset(buf);\n-\tif (!read_oneliner(buf, rebase_path_strategy(), 0))\n-\t\treturn;\n-\topts->strategy = strbuf_detach(buf, NULL);\n-\tif (!read_oneliner(buf, rebase_path_strategy_opts(), 0))\n-\t\treturn;\n-\n-\tstrategy_opts_string = buf->buf;\n \tif (*strategy_opts_string == ' ')\n \t\tstrategy_opts_string++;\n+\n \topts->xopts_nr = split_cmdline(strategy_opts_string,\n \t\t\t\t       (const char ***)&opts->xopts);\n \tfor (i = 0; i < opts->xopts_nr; i++) {\n@@ -2230,6 +2224,18 @@ static void read_strategy_opts(struct replay_opts *opts, struct strbuf *buf)\n \t}\n }\n \n+static void read_strategy_opts(struct replay_opts *opts, struct strbuf *buf)\n+{\n+\tstrbuf_reset(buf);\n+\tif (!read_oneliner(buf, rebase_path_strategy(), 0))\n+\t\treturn;\n+\topts->strategy = strbuf_detach(buf, NULL);\n+\tif (!read_oneliner(buf, rebase_path_strategy_opts(), 0))\n+\t\treturn;\n+\n+\tparse_strategy_opts(opts, buf->buf);\n+}\n+\n static int read_populate_opts(struct replay_opts *opts)\n {\n \tif (is_rebase_i(opts)) {\n@@ -2297,6 +2303,55 @@ static int read_populate_opts(struct replay_opts *opts)\n \treturn 0;\n }\n \n+static void write_strategy_opts(struct replay_opts *opts)\n+{\n+\tint i;\n+\tstruct strbuf buf = STRBUF_INIT;\n+\n+\tfor (i = 0; i < opts->xopts_nr; ++i)\n+\t\tstrbuf_addf(&buf, \" --%s\", opts->xopts[i]);\n+\n+\twrite_file(rebase_path_strategy_opts(), \"%s\\n\", buf.buf);\n+\tstrbuf_release(&buf);\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+{\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+\tif (orig_head)\n+\t\twrite_file(rebase_path_orig_head(), \"%s\\n\", orig_head);\n+\n+\tif (quiet)\n+\t\twrite_file(rebase_path_quiet(), \"%s\\n\", quiet);\n+\telse\n+\t\twrite_file(rebase_path_quiet(), \"\\n\");\n+\n+\tif (opts->verbose)\n+\t\twrite_file(rebase_path_verbose(), \"\");\n+\tif (opts->strategy)\n+\t\twrite_file(rebase_path_strategy(), \"%s\\n\", opts->strategy);\n+\tif (opts->xopts_nr > 0)\n+\t\twrite_strategy_opts(opts);\n+\n+\tif (opts->allow_rerere_auto == RERERE_AUTOUPDATE)\n+\t\twrite_file(rebase_path_allow_rerere_autoupdate(), \"--rerere-autoupdate\\n\");\n+\telse if (opts->allow_rerere_auto == RERERE_NOAUTOUPDATE)\n+\t\twrite_file(rebase_path_allow_rerere_autoupdate(), \"--no-rerere-autoupdate\\n\");\n+\n+\tif (opts->gpg_sign)\n+\t\twrite_file(rebase_path_gpg_sign_opt(), \"-S%s\\n\", opts->gpg_sign);\n+\tif (opts->signoff)\n+\t\twrite_file(rebase_path_signoff(), \"--signoff\\n\");\n+\n+\treturn 0;\n+}\n+\n static int walk_revs_populate_todo(struct todo_list *todo_list,\n \t\t\t\tstruct replay_opts *opts)\n {\ndiff --git a/sequencer.h b/sequencer.h\nindex 02e3d7940e..aab280f276 100644\n--- a/sequencer.h\n+++ b/sequencer.h\n@@ -119,3 +119,7 @@ int prepare_branch_to_be_rebased(struct replay_opts *opts, const char *commit);\n void print_commit_summary(const char *prefix, const struct object_id *oid,\n \t\t\t  unsigned int flags);\n #endif\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-- \n2.18.0\n\n"},{"id":"356678","messageId":"20180828121045.14933-18-alban.gruin@gmail.com","threadId":"48814","inReplyTo":"20180828121045.14933-1-alban.gruin@gmail.com","subject":"[GSoC][PATCH v7 17/20] rebase -i: implement the main part of interactive rebase as a builtin","fromName":"Alban Gruin","fromEmail":"alban.gruin@gmail.com","sentAt":"2018-08-28T12:10:42Z","receivedAt":"2018-08-28T12:11:35Z","isPatch":true,"sender":{"key":"alban.gruin@gmail.com","avatar":"https://avatars.githubusercontent.com/u/6310153?v=4"},"body":"This rewrites the part of interactive rebase which initializes the\nbasic state, make the script and complete the action, as a buitin, named\ngit-rebase--interactive2 for now.  Others modes (`--continue`,\n`--edit-todo`, etc.) will be rewritten in the next commit.\n\ngit-rebase--interactive.sh is modified to call git-rebase--interactive2\ninstead of git-rebase--helper.\n\nSigned-off-by: Alban Gruin <alban.gruin@gmail.com>\n---\n .gitignore                     |   1 +\n Makefile                       |   1 +\n builtin.h                      |   1 +\n builtin/rebase--interactive2.c | 206 +++++++++++++++++++++++++++++++++\n git-rebase--interactive.sh     |  41 ++++---\n git.c                          |   1 +\n 6 files changed, 232 insertions(+), 19 deletions(-)\n create mode 100644 builtin/rebase--interactive2.c\n\ndiff --git a/.gitignore b/.gitignore\nindex 3284a1e9b1..404c9a8472 100644\n--- a/.gitignore\n+++ b/.gitignore\n@@ -118,6 +118,7 @@\n /git-rebase--am\n /git-rebase--helper\n /git-rebase--interactive\n+/git-rebase--interactive2\n /git-rebase--merge\n /git-rebase--preserve-merges\n /git-receive-pack\ndiff --git a/Makefile b/Makefile\nindex 909a687857..71f8f45fe5 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -1060,6 +1060,7 @@ BUILTIN_OBJS += builtin/prune.o\n BUILTIN_OBJS += builtin/pull.o\n BUILTIN_OBJS += builtin/push.o\n BUILTIN_OBJS += builtin/read-tree.o\n+BUILTIN_OBJS += builtin/rebase--interactive2.o\n BUILTIN_OBJS += builtin/rebase--helper.o\n BUILTIN_OBJS += builtin/receive-pack.o\n BUILTIN_OBJS += builtin/reflog.o\ndiff --git a/builtin.h b/builtin.h\nindex 0362f1ce25..ed89b4f495 100644\n--- a/builtin.h\n+++ b/builtin.h\n@@ -202,6 +202,7 @@ extern int cmd_prune_packed(int argc, const char **argv, const char *prefix);\n extern int cmd_pull(int argc, const char **argv, const char *prefix);\n extern int cmd_push(int argc, const char **argv, const char *prefix);\n extern int cmd_read_tree(int argc, const char **argv, const char *prefix);\n+extern int cmd_rebase__interactive(int argc, const char **argv, const char *prefix);\n extern int cmd_rebase__helper(int argc, const char **argv, const char *prefix);\n extern int cmd_receive_pack(int argc, const char **argv, const char *prefix);\n extern int cmd_reflog(int argc, const char **argv, const char *prefix);\ndiff --git a/builtin/rebase--interactive2.c b/builtin/rebase--interactive2.c\nnew file mode 100644\nindex 0000000000..038bbf359e\n--- /dev/null\n+++ b/builtin/rebase--interactive2.c\n@@ -0,0 +1,206 @@\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 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 const char *cmd, 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+\tFILE *todo_list;\n+\n+\tif (prepare_branch_to_be_rebased(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+\ttodo_list = fopen(rebase_path_todo(), \"w\");\n+\tif (!todo_list) {\n+\t\tfree(revisions);\n+\t\tfree(shortrevisions);\n+\n+\t\treturn error_errno(_(\"could not open %s\"), rebase_path_todo());\n+\t}\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(todo_list,\n+\t\t\t\t    make_script_args.argc, make_script_args.argv,\n+\t\t\t\t    flags);\n+\tfclose(todo_list);\n+\n+\tif (ret)\n+\t\terror(_(\"could not generate todo list\"));\n+\telse {\n+\t\tdiscard_cache();\n+\t\tret = complete_action(opts, flags, shortrevisions, onto_name, onto,\n+\t\t\t\t      head_hash, cmd, autosquash);\n+\t}\n+\n+\tfree(revisions);\n+\tfree(shortrevisions);\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;\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+\tchar *raw_strategies = NULL;\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_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\tOPT_STRING('S', \"gpg-sign\", &opts.gpg_sign, N_(\"gpg-sign\"),\n+\t\t\t   N_(\"GPG-sign commits\")),\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_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+\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 (!onto && !upstream)\n+\t\tdie(_(\"a base commit must be provided with --upstream or --onto\"));\n+\n+\treturn !!do_interactive_rebase(&opts, flags, switch_to, upstream, onto,\n+\t\t\t\t       onto_name, squash_onto, head_name, restrict_revision,\n+\t\t\t\t       raw_strategies, cmd, autosquash);\n+}\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex 761be95ed1..e87d708a4d 100644\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -58,24 +58,27 @@ git_rebase__interactive () {\n \t\treturn 0\n \tfi\n \n-\tgit rebase--helper --prepare-branch \"$switch_to\" ${verbose:+--verbose}\n+\ttest -n \"$keep_empty\" && keep_empty=\"--keep-empty\"\n+\ttest -n \"$rebase_merges\" && rebase_merges=\"--rebase-merges\"\n+\ttest -n \"$rebase_cousins\" && rebase_cousins=\"--rebase-cousins\"\n+\ttest -n \"$autosquash\" && autosquash=\"--autosquash\"\n+\ttest -n \"$verbose\" && verbose=\"--verbose\"\n+\ttest -n \"$force_rebase\" && force_rebase=\"--no-ff\"\n+\ttest -n \"$restrict_revisions\" && restrict_revisions=\"--restrict-revisions=^$restrict_revisions\"\n+\ttest -n \"$upstream\" && upstream=\"--upstream=$upstream\"\n+\ttest -n \"$onto\" && onto=\"--onto=$onto\"\n+\ttest -n \"$squash_onto\" && squash_onto=\"--squash-onto=$squash_onto\"\n+\ttest -n \"$onto_name\" && onto_name=\"--onto-name=$onto_name\"\n+\ttest -n \"$head_name\" && head_name=\"--head-name=$head_name\"\n+\ttest -n \"$strategy\" && strategy=\"--strategy=$strategy\"\n+\ttest -n \"$strategy_opts\" && strategy_opts=\"--strategy-opts=$strategy_opts\"\n+\ttest -n \"$switch_to\" && switch_to=\"--switch-to=$switch_to\"\n+\ttest -n \"$cmd\" && cmd=\"--cmd=$cmd\"\n \n-\tgit rebase--helper --init-basic-state ${upstream:+--upstream \"$upstream\"} \\\n-\t\t${onto:+--onto \"$onto\"} ${head_name:+--head-name \"$head_name\"} \\\n-\t\t${verbose:+--verbose} ${strategy:+--strategy \"$strategy\"} \\\n-\t\t${strategy_opts:+--strategy-opts=\"$strategy_opts\"} \\\n-\t\t\"$allow_rerere_autoupdate\" \"$gpg_sign_opt\" \"$signoff\" || exit\n-\n-\tgit rebase--helper --make-script ${keep_empty:+--keep-empty} \\\n-\t\t${rebase_merges:+--rebase-merges} \\\n-\t\t${rebase_cousins:+--rebase-cousins} \\\n-\t\t${upstream:+--upstream \"$upstream\"} ${onto:+--onto \"$onto\"} \\\n-\t\t${squash_onto:+--squash-onto \"$squash_onto\"} \\\n-\t\t${restrict_revision:+--restrict-revision ^\"$restrict_revision\"} >\"$todo\" ||\n-\tdie \"$(gettext \"Could not generate todo list\")\"\n-\n-\texec git rebase--helper --complete-action \"$onto_name\" \"$cmd\" \\\n-\t\t$allow_empty_message ${autosquash:+--autosquash} ${verbose:+--verbose} \\\n-\t\t${keep_empty:+--keep-empty} ${force_rebase:+--no-ff} \\\n-\t\t${upstream:+--upstream \"$upstream\"} ${onto:+--onto \"$onto\"}\n+\texec git rebase--interactive2 \"$keep_empty\" \"$rebase_merges\" \"$rebase_cousins\" \\\n+\t\t\"$upstream\" \"$onto\" \"$squash_onto\" \"$restrict_revision\" \\\n+\t\t\"$allow_empty_message\" \"$autosquash\" \"$verbose\" \\\n+\t\t\"$force_rebase\" \"$onto_name\" \"$head_name\" \"$strategy\" \\\n+\t\t\"$strategy_opts\" \"$cmd\" \"$switch_to\" \\\n+\t\t\"$allow_rerere_autoupdate\" \"$gpg_sign_opt\" \"$signoff\"\n }\ndiff --git a/git.c b/git.c\nindex 3fded74519..8309fb24a6 100644\n--- a/git.c\n+++ b/git.c\n@@ -518,6 +518,7 @@ static struct cmd_struct commands[] = {\n \t{ \"pull\", cmd_pull, RUN_SETUP | NEED_WORK_TREE },\n \t{ \"push\", cmd_push, RUN_SETUP },\n \t{ \"read-tree\", cmd_read_tree, RUN_SETUP | SUPPORT_SUPER_PREFIX},\n+\t{ \"rebase--interactive2\", cmd_rebase__interactive, RUN_SETUP | NEED_WORK_TREE },\n \t{ \"rebase--helper\", cmd_rebase__helper, RUN_SETUP | NEED_WORK_TREE },\n \t{ \"receive-pack\", cmd_receive_pack },\n \t{ \"reflog\", cmd_reflog, RUN_SETUP },\n-- \n2.18.0\n\n"},{"id":"356675","messageId":"20180828121045.14933-19-alban.gruin@gmail.com","threadId":"48814","inReplyTo":"20180828121045.14933-1-alban.gruin@gmail.com","subject":"[GSoC][PATCH v7 18/20] rebase--interactive2: rewrite the submodes of interactive rebase in C","fromName":"Alban Gruin","fromEmail":"alban.gruin@gmail.com","sentAt":"2018-08-28T12:10:43Z","receivedAt":"2018-08-28T12:11:36Z","isPatch":true,"sender":{"key":"alban.gruin@gmail.com","avatar":"https://avatars.githubusercontent.com/u/6310153?v=4"},"body":"This rewrites the submodes of interactive rebase (`--continue`,\n`--skip`, `--edit-todo`, and `--show-current-patch`) in C.\n\ngit-rebase.sh is then modified to call directly git-rebase--interactive2\ninstead of git-rebase--interactive.sh.\n\nSigned-off-by: Alban Gruin <alban.gruin@gmail.com>\n---\n builtin/rebase--interactive2.c | 51 ++++++++++++++++++++++++++++++----\n git-rebase.sh                  | 45 +++++++++++++++++++++++++++---\n 2 files changed, 86 insertions(+), 10 deletions(-)\n\ndiff --git a/builtin/rebase--interactive2.c b/builtin/rebase--interactive2.c\nindex 038bbf359e..b32621b179 100644\n--- a/builtin/rebase--interactive2.c\n+++ b/builtin/rebase--interactive2.c\n@@ -134,11 +134,14 @@ 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;\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 \tchar *raw_strategies = NULL;\n+\tenum {\n+\t\tNONE = 0, CONTINUE, SKIP, EDIT_TODO, SHOW_CURRENT_PATCH\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@@ -151,6 +154,13 @@ int cmd_rebase__interactive(int argc, const char **argv, const char *prefix)\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_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@@ -197,10 +207,39 @@ 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 (!onto && !upstream)\n-\t\tdie(_(\"a base commit must be provided with --upstream or --onto\"));\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, cmd, autosquash);\n+\t\tbreak;\n+\tcase SKIP: {\n+\t\tstruct string_list merge_rr = STRING_LIST_INIT_DUP;\n+\n+\t\trerere_clear(&merge_rr);\n+\t\t/* fallthrough */\n+\tcase CONTINUE:\n+\t\tret = sequencer_continue(&opts);\n+\t\tbreak;\n+\t}\n+\tcase EDIT_TODO:\n+\t\tret = edit_todo_list(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+\tdefault:\n+\t\tBUG(\"invalid command '%d'\", command);\n+\t}\n \n-\treturn !!do_interactive_rebase(&opts, flags, switch_to, upstream, onto,\n-\t\t\t\t       onto_name, squash_onto, head_name, restrict_revision,\n-\t\t\t\t       raw_strategies, cmd, autosquash);\n+\treturn !!ret;\n }\ndiff --git a/git-rebase.sh b/git-rebase.sh\nindex 51a6db7daa..6e1e413cf2 100755\n--- a/git-rebase.sh\n+++ b/git-rebase.sh\n@@ -200,19 +200,56 @@ finish_rebase () {\n \trm -rf \"$state_dir\"\n }\n \n+run_interactive () {\n+\tGIT_CHERRY_PICK_HELP=\"$resolvemsg\"\n+\texport GIT_CHERRY_PICK_HELP\n+\n+\ttest -n \"$keep_empty\" && keep_empty=\"--keep-empty\"\n+\ttest -n \"$rebase_merges\" && rebase_merges=\"--rebase-merges\"\n+\ttest -n \"$rebase_cousins\" && rebase_cousins=\"--rebase-cousins\"\n+\ttest -n \"$autosquash\" && autosquash=\"--autosquash\"\n+\ttest -n \"$verbose\" && verbose=\"--verbose\"\n+\ttest -n \"$force_rebase\" && force_rebase=\"--no-ff\"\n+\ttest -n \"$restrict_revision\" && \\\n+\t\trestrict_revision=\"--restrict-revision=^$restrict_revision\"\n+\ttest -n \"$upstream\" && upstream=\"--upstream=$upstream\"\n+\ttest -n \"$onto\" && onto=\"--onto=$onto\"\n+\ttest -n \"$squash_onto\" && squash_onto=\"--squash-onto=$squash_onto\"\n+\ttest -n \"$onto_name\" && onto_name=\"--onto-name=$onto_name\"\n+\ttest -n \"$head_name\" && head_name=\"--head-name=$head_name\"\n+\ttest -n \"$strategy\" && strategy=\"--strategy=$strategy\"\n+\ttest -n \"$strategy_opts\" && strategy_opts=\"--strategy-opts=$strategy_opts\"\n+\ttest -n \"$switch_to\" && switch_to=\"--switch-to=$switch_to\"\n+\ttest -n \"$cmd\" && cmd=\"--cmd=$cmd\"\n+\ttest -n \"$action\" && action=\"--$action\"\n+\n+\texec git rebase--interactive2 \"$action\" \"$keep_empty\" \"$rebase_merges\" \"$rebase_cousins\" \\\n+\t\t\"$upstream\" \"$onto\" \"$squash_onto\" \"$restrict_revision\" \\\n+\t\t\"$allow_empty_message\" \"$autosquash\" \"$verbose\" \\\n+\t\t\"$force_rebase\" \"$onto_name\" \"$head_name\" \"$strategy\" \\\n+\t\t\"$strategy_opts\" \"$cmd\" \"$switch_to\" \\\n+\t\t\"$allow_rerere_autoupdate\" \"$gpg_sign_opt\" \"$signoff\"\n+}\n+\n run_specific_rebase () {\n \tif [ \"$interactive_rebase\" = implied ]; then\n \t\tGIT_EDITOR=:\n \t\texport GIT_EDITOR\n \t\tautosquash=\n \tfi\n-\t. git-rebase--$type\n \n-\tif test -z \"$preserve_merges\"\n+\tif test -n \"$interactive_rebase\" -a -z \"$preserve_merges\"\n \tthen\n-\t\tgit_rebase__$type\n+\t\trun_interactive\n \telse\n-\t\tgit_rebase__preserve_merges\n+\t\t. git-rebase--$type\n+\n+\t\tif test -z \"$preserve_merges\"\n+\t\tthen\n+\t\t\tgit_rebase__$type\n+\t\telse\n+\t\t\tgit_rebase__preserve_merges\n+\t\tfi\n \tfi\n \n \tret=$?\n-- \n2.18.0\n\n"},{"id":"356680","messageId":"20180828121045.14933-20-alban.gruin@gmail.com","threadId":"48814","inReplyTo":"20180828121045.14933-1-alban.gruin@gmail.com","subject":"[GSoC][PATCH v7 19/20] rebase -i: remove git-rebase--interactive.sh","fromName":"Alban Gruin","fromEmail":"alban.gruin@gmail.com","sentAt":"2018-08-28T12:10:44Z","receivedAt":"2018-08-28T12:11:38Z","isPatch":true,"sender":{"key":"alban.gruin@gmail.com","avatar":"https://avatars.githubusercontent.com/u/6310153?v=4"},"body":"This removes git-rebase--interactive.sh, as its functionnality has been\nreplaced by git-rebase--interactive2.\n\ngit-rebase--interactive2.c is then renamed to git-rebase--interactive.c.\n\nSigned-off-by: Alban Gruin <alban.gruin@gmail.com>\n---\nNo changes since v6.\n\n .gitignore                                    |  1 -\n Makefile                                      |  4 +-\n ...--interactive2.c => rebase--interactive.c} |  0\n git-rebase--interactive.sh                    | 84 -------------------\n git-rebase.sh                                 |  2 +-\n git.c                                         |  2 +-\n 6 files changed, 3 insertions(+), 90 deletions(-)\n rename builtin/{rebase--interactive2.c => rebase--interactive.c} (100%)\n delete mode 100644 git-rebase--interactive.sh\n\ndiff --git a/.gitignore b/.gitignore\nindex 404c9a8472..3284a1e9b1 100644\n--- a/.gitignore\n+++ b/.gitignore\n@@ -118,7 +118,6 @@\n /git-rebase--am\n /git-rebase--helper\n /git-rebase--interactive\n-/git-rebase--interactive2\n /git-rebase--merge\n /git-rebase--preserve-merges\n /git-receive-pack\ndiff --git a/Makefile b/Makefile\nindex 71f8f45fe5..584834726d 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -619,7 +619,6 @@ SCRIPT_SH += git-web--browse.sh\n SCRIPT_LIB += git-mergetool--lib\n SCRIPT_LIB += git-parse-remote\n SCRIPT_LIB += git-rebase--am\n-SCRIPT_LIB += git-rebase--interactive\n SCRIPT_LIB += git-rebase--preserve-merges\n SCRIPT_LIB += git-rebase--merge\n SCRIPT_LIB += git-sh-setup\n@@ -1060,8 +1059,8 @@ BUILTIN_OBJS += builtin/prune.o\n BUILTIN_OBJS += builtin/pull.o\n BUILTIN_OBJS += builtin/push.o\n BUILTIN_OBJS += builtin/read-tree.o\n-BUILTIN_OBJS += builtin/rebase--interactive2.o\n BUILTIN_OBJS += builtin/rebase--helper.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\n@@ -2400,7 +2399,6 @@ XGETTEXT_FLAGS_PERL = $(XGETTEXT_FLAGS) --language=Perl \\\n LOCALIZED_C = $(C_OBJ:o=c) $(LIB_H) $(GENERATED_H)\n LOCALIZED_SH = $(SCRIPT_SH)\n LOCALIZED_SH += git-parse-remote.sh\n-LOCALIZED_SH += git-rebase--interactive.sh\n LOCALIZED_SH += git-rebase--preserve-merges.sh\n LOCALIZED_SH += git-sh-setup.sh\n LOCALIZED_PERL = $(SCRIPT_PERL)\ndiff --git a/builtin/rebase--interactive2.c b/builtin/rebase--interactive.c\nsimilarity index 100%\nrename from builtin/rebase--interactive2.c\nrename to builtin/rebase--interactive.c\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\ndeleted file mode 100644\nindex e87d708a4d..0000000000\n--- a/git-rebase--interactive.sh\n+++ /dev/null\n@@ -1,84 +0,0 @@\n-# This shell script fragment is sourced by git-rebase to implement\n-# its interactive mode.  \"git rebase --interactive\" makes it easy\n-# to fix up commits in the middle of a series and rearrange commits.\n-#\n-# Copyright (c) 2006 Johannes E. Schindelin\n-#\n-# The original idea comes from Eric W. Biederman, in\n-# https://public-inbox.org/git/m1odwkyuf5.fsf_-_@ebiederm.dsl.xmission.com/\n-#\n-# The file containing rebase commands, comments, and empty lines.\n-# This file is created by \"git rebase -i\" then edited by the user.  As\n-# the lines are processed, they are removed from the front of this\n-# file and written to the tail of $done.\n-todo=\"$state_dir\"/git-rebase-todo\n-\n-GIT_CHERRY_PICK_HELP=\"$resolvemsg\"\n-export GIT_CHERRY_PICK_HELP\n-\n-# Initiate an action. If the cannot be any\n-# further action it  may exec a command\n-# or exit and not return.\n-#\n-# TODO: Consider a cleaner return model so it\n-# never exits and always return 0 if process\n-# is complete.\n-#\n-# Parameter 1 is the action to initiate.\n-#\n-# Returns 0 if the action was able to complete\n-# and if 1 if further processing is required.\n-initiate_action () {\n-\tcase \"$1\" in\n-\tcontinue)\n-\t\texec git rebase--helper ${force_rebase:+--no-ff} $allow_empty_message \\\n-\t\t     --continue\n-\t\t;;\n-\tskip)\n-\t\tgit rerere clear\n-\t\texec git rebase--helper ${force_rebase:+--no-ff} $allow_empty_message \\\n-\t\t     --continue\n-\t\t;;\n-\tedit-todo)\n-\t\texec git rebase--helper --edit-todo\n-\t\t;;\n-\tshow-current-patch)\n-\t\texec git show REBASE_HEAD --\n-\t\t;;\n-\t*)\n-\t\treturn 1 # continue\n-\t\t;;\n-\tesac\n-}\n-\n-git_rebase__interactive () {\n-\tinitiate_action \"$action\"\n-\tret=$?\n-\tif test $ret = 0; then\n-\t\treturn 0\n-\tfi\n-\n-\ttest -n \"$keep_empty\" && keep_empty=\"--keep-empty\"\n-\ttest -n \"$rebase_merges\" && rebase_merges=\"--rebase-merges\"\n-\ttest -n \"$rebase_cousins\" && rebase_cousins=\"--rebase-cousins\"\n-\ttest -n \"$autosquash\" && autosquash=\"--autosquash\"\n-\ttest -n \"$verbose\" && verbose=\"--verbose\"\n-\ttest -n \"$force_rebase\" && force_rebase=\"--no-ff\"\n-\ttest -n \"$restrict_revisions\" && restrict_revisions=\"--restrict-revisions=^$restrict_revisions\"\n-\ttest -n \"$upstream\" && upstream=\"--upstream=$upstream\"\n-\ttest -n \"$onto\" && onto=\"--onto=$onto\"\n-\ttest -n \"$squash_onto\" && squash_onto=\"--squash-onto=$squash_onto\"\n-\ttest -n \"$onto_name\" && onto_name=\"--onto-name=$onto_name\"\n-\ttest -n \"$head_name\" && head_name=\"--head-name=$head_name\"\n-\ttest -n \"$strategy\" && strategy=\"--strategy=$strategy\"\n-\ttest -n \"$strategy_opts\" && strategy_opts=\"--strategy-opts=$strategy_opts\"\n-\ttest -n \"$switch_to\" && switch_to=\"--switch-to=$switch_to\"\n-\ttest -n \"$cmd\" && cmd=\"--cmd=$cmd\"\n-\n-\texec git rebase--interactive2 \"$keep_empty\" \"$rebase_merges\" \"$rebase_cousins\" \\\n-\t\t\"$upstream\" \"$onto\" \"$squash_onto\" \"$restrict_revision\" \\\n-\t\t\"$allow_empty_message\" \"$autosquash\" \"$verbose\" \\\n-\t\t\"$force_rebase\" \"$onto_name\" \"$head_name\" \"$strategy\" \\\n-\t\t\"$strategy_opts\" \"$cmd\" \"$switch_to\" \\\n-\t\t\"$allow_rerere_autoupdate\" \"$gpg_sign_opt\" \"$signoff\"\n-}\ndiff --git a/git-rebase.sh b/git-rebase.sh\nindex 6e1e413cf2..3e7798e07b 100755\n--- a/git-rebase.sh\n+++ b/git-rebase.sh\n@@ -223,7 +223,7 @@ run_interactive () {\n \ttest -n \"$cmd\" && cmd=\"--cmd=$cmd\"\n \ttest -n \"$action\" && action=\"--$action\"\n \n-\texec git rebase--interactive2 \"$action\" \"$keep_empty\" \"$rebase_merges\" \"$rebase_cousins\" \\\n+\texec git rebase--interactive \"$action\" \"$keep_empty\" \"$rebase_merges\" \"$rebase_cousins\" \\\n \t\t\"$upstream\" \"$onto\" \"$squash_onto\" \"$restrict_revision\" \\\n \t\t\"$allow_empty_message\" \"$autosquash\" \"$verbose\" \\\n \t\t\"$force_rebase\" \"$onto_name\" \"$head_name\" \"$strategy\" \\\ndiff --git a/git.c b/git.c\nindex 8309fb24a6..19d0b6e3b8 100644\n--- a/git.c\n+++ b/git.c\n@@ -518,7 +518,7 @@ static struct cmd_struct commands[] = {\n \t{ \"pull\", cmd_pull, RUN_SETUP | NEED_WORK_TREE },\n \t{ \"push\", cmd_push, RUN_SETUP },\n \t{ \"read-tree\", cmd_read_tree, RUN_SETUP | SUPPORT_SUPER_PREFIX},\n-\t{ \"rebase--interactive2\", cmd_rebase__interactive, RUN_SETUP | NEED_WORK_TREE },\n+\t{ \"rebase--interactive\", cmd_rebase__interactive, RUN_SETUP | NEED_WORK_TREE },\n \t{ \"rebase--helper\", cmd_rebase__helper, RUN_SETUP | NEED_WORK_TREE },\n \t{ \"receive-pack\", cmd_receive_pack },\n \t{ \"reflog\", cmd_reflog, RUN_SETUP },\n-- \n2.18.0\n\n"},{"id":"356671","messageId":"20180828121045.14933-21-alban.gruin@gmail.com","threadId":"48814","inReplyTo":"20180828121045.14933-1-alban.gruin@gmail.com","subject":"[GSoC][PATCH v7 20/20] rebase -i: move rebase--helper modes to rebase--interactive","fromName":"Alban Gruin","fromEmail":"alban.gruin@gmail.com","sentAt":"2018-08-28T12:10:45Z","receivedAt":"2018-08-28T12:11:40Z","isPatch":true,"sender":{"key":"alban.gruin@gmail.com","avatar":"https://avatars.githubusercontent.com/u/6310153?v=4"},"body":"This moves the rebase--helper modes still used by\ngit-rebase--preserve-merges.sh (`--shorten-ids`, `--expand-ids`,\n`--check-todo-list`, `--rearrange-squash` and `--add-exec-commands`) to\nrebase--interactive.c.\n\ngit-rebase--preserve-merges.sh is modified accordingly, and\nrebase--helper.c is removed as it is useless now.\n\nSigned-off-by: Alban Gruin <alban.gruin@gmail.com>\n---\nNo changes since v6.\n\n .gitignore                     |   1 -\n Makefile                       |   1 -\n builtin.h                      |   1 -\n builtin/rebase--helper.c       | 226 ---------------------------------\n builtin/rebase--interactive.c  |  27 +++-\n git-rebase--preserve-merges.sh |  10 +-\n git.c                          |   1 -\n 7 files changed, 31 insertions(+), 236 deletions(-)\n delete mode 100644 builtin/rebase--helper.c\n\ndiff --git a/.gitignore b/.gitignore\nindex 3284a1e9b1..406f26d050 100644\n--- a/.gitignore\n+++ b/.gitignore\n@@ -116,7 +116,6 @@\n /git-read-tree\n /git-rebase\n /git-rebase--am\n-/git-rebase--helper\n /git-rebase--interactive\n /git-rebase--merge\n /git-rebase--preserve-merges\ndiff --git a/Makefile b/Makefile\nindex 584834726d..ca3a0888dd 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -1059,7 +1059,6 @@ BUILTIN_OBJS += builtin/prune.o\n BUILTIN_OBJS += builtin/pull.o\n BUILTIN_OBJS += builtin/push.o\n BUILTIN_OBJS += builtin/read-tree.o\n-BUILTIN_OBJS += builtin/rebase--helper.o\n BUILTIN_OBJS += builtin/rebase--interactive.o\n BUILTIN_OBJS += builtin/receive-pack.o\n BUILTIN_OBJS += builtin/reflog.o\ndiff --git a/builtin.h b/builtin.h\nindex ed89b4f495..7feb689d87 100644\n--- a/builtin.h\n+++ b/builtin.h\n@@ -203,7 +203,6 @@ extern int cmd_pull(int argc, const char **argv, const char *prefix);\n extern int cmd_push(int argc, const char **argv, const char *prefix);\n extern int cmd_read_tree(int argc, const char **argv, const char *prefix);\n extern int cmd_rebase__interactive(int argc, const char **argv, const char *prefix);\n-extern int cmd_rebase__helper(int argc, const char **argv, const char *prefix);\n extern int cmd_receive_pack(int argc, const char **argv, const char *prefix);\n extern int cmd_reflog(int argc, const char **argv, const char *prefix);\n extern int cmd_remote(int argc, const char **argv, const char *prefix);\ndiff --git a/builtin/rebase--helper.c b/builtin/rebase--helper.c\ndeleted file mode 100644\nindex f8128037d3..0000000000\n--- a/builtin/rebase--helper.c\n+++ /dev/null\n@@ -1,226 +0,0 @@\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 \"alias.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 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;\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-\n-\tif (revisions)\n-\t\t*revisions = xstrfmt(\"%s...%s\", base_rev, *head_hash);\n-\tif (shortrevisions) {\n-\t\tconst char *shorthead;\n-\n-\t\tshorthead = find_unique_abbrev(&orig_head, DEFAULT_ABBREV);\n-\n-\t\tif (upstream) {\n-\t\t\tconst char *shortrev;\n-\t\t\tstruct object_id rev_oid;\n-\n-\t\t\tget_oid(base_rev, &rev_oid);\n-\t\t\tshortrev = find_unique_abbrev(&rev_oid, DEFAULT_ABBREV);\n-\n-\t\t\t*shortrevisions = xstrfmt(\"%s..%s\", shortrev, shorthead);\n-\t\t} else\n-\t\t\t*shortrevisions = xstrdup(shorthead);\n-\t}\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 const char * const builtin_rebase_helper_usage[] = {\n-\tN_(\"git rebase--helper [<options>]\"),\n-\tNULL\n-};\n-\n-int cmd_rebase__helper(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;\n-\tconst char *head_hash = NULL, *onto = NULL, *restrict_revision = NULL,\n-\t\t*squash_onto = NULL, *upstream = NULL, *head_name = NULL;\n-\tchar *raw_strategies = NULL;\n-\tenum {\n-\t\tCONTINUE = 1, ABORT, MAKE_SCRIPT, SHORTEN_OIDS, EXPAND_OIDS,\n-\t\tCHECK_TODO_LIST, REARRANGE_SQUASH, ADD_EXEC, EDIT_TODO, PREPARE_BRANCH,\n-\t\tCOMPLETE_ACTION, INIT_BASIC_STATE\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\tN_(\"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\tCONTINUE),\n-\t\tOPT_CMDMODE(0, \"abort\", &command, N_(\"abort rebase\"),\n-\t\t\t\tABORT),\n-\t\tOPT_CMDMODE(0, \"make-script\", &command,\n-\t\t\tN_(\"make rebase script\"), MAKE_SCRIPT),\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_CMDMODE(0, \"edit-todo\", &command,\n-\t\t\t    N_(\"edit the todo list during an interactive rebase\"),\n-\t\t\t    EDIT_TODO),\n-\t\tOPT_CMDMODE(0, \"prepare-branch\", &command,\n-\t\t\t    N_(\"prepare the branch to be rebased\"), PREPARE_BRANCH),\n-\t\tOPT_CMDMODE(0, \"complete-action\", &command,\n-\t\t\t    N_(\"complete the action\"), COMPLETE_ACTION),\n-\t\tOPT_CMDMODE(0, \"init-basic-state\", &command,\n-\t\t\t    N_(\"initialise the rebase state\"), INIT_BASIC_STATE),\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\tOPT_STRING('S', \"gpg-sign\", &opts.gpg_sign, N_(\"gpg-sign\"),\n-\t\t\t   N_(\"GPG-sign commits\")),\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_RERERE_AUTOUPDATE(&opts.allow_rerere_auto),\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-\targc = parse_options(argc, argv, NULL, options,\n-\t\t\tbuiltin_rebase_helper_usage, PARSE_OPT_KEEP_ARGV0);\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 (command == CONTINUE && argc == 1)\n-\t\treturn !!sequencer_continue(&opts);\n-\tif (command == ABORT && argc == 1)\n-\t\treturn !!sequencer_remove_state(&opts);\n-\tif (command == MAKE_SCRIPT && argc == 1) {\n-\t\tchar *revisions = NULL;\n-\t\tstruct argv_array make_script_args = ARGV_ARRAY_INIT;\n-\n-\t\tif (!upstream && squash_onto)\n-\t\t\twrite_file(path_squash_onto(), \"%s\\n\", squash_onto);\n-\n-\t\tret = get_revision_ranges(upstream, onto, &head_hash, &revisions, NULL);\n-\t\tif (ret)\n-\t\t\treturn ret;\n-\n-\t\targv_array_pushl(&make_script_args, \"\", revisions, NULL);\n-\t\tif (restrict_revision)\n-\t\t\targv_array_push(&make_script_args, restrict_revision);\n-\n-\t\tret = sequencer_make_script(stdout,\n-\t\t\t\t\t    make_script_args.argc, make_script_args.argv,\n-\t\t\t\t\t    flags);\n-\n-\t\tfree(revisions);\n-\t\targv_array_clear(&make_script_args);\n-\n-\t\treturn !!ret;\n-\t}\n-\tif ((command == SHORTEN_OIDS || command == EXPAND_OIDS) && argc == 1)\n-\t\treturn !!transform_todos(flags);\n-\tif (command == CHECK_TODO_LIST && argc == 1)\n-\t\treturn !!check_todo_list();\n-\tif (command == REARRANGE_SQUASH && argc == 1)\n-\t\treturn !!rearrange_squash();\n-\tif (command == ADD_EXEC && argc == 2)\n-\t\treturn !!sequencer_add_exec_commands(argv[1]);\n-\tif (command == EDIT_TODO && argc == 1)\n-\t\treturn !!edit_todo_list(flags);\n-\tif (command == PREPARE_BRANCH && argc == 2)\n-\t\treturn !!prepare_branch_to_be_rebased(&opts, argv[1]);\n-\tif (command == COMPLETE_ACTION && argc == 3) {\n-\t\tchar *shortrevisions = NULL;\n-\n-\t\tret = get_revision_ranges(upstream, onto, &head_hash, NULL, &shortrevisions);\n-\t\tif (ret)\n-\t\t\treturn ret;\n-\n-\t\tret = complete_action(&opts, flags, shortrevisions, argv[1], onto,\n-\t\t\t\t      head_hash, argv[2], autosquash);\n-\n-\t\tfree(shortrevisions);\n-\t\treturn !!ret;\n-\t}\n-\tif (command == INIT_BASIC_STATE) {\n-\t\tif (raw_strategies)\n-\t\t\tparse_strategy_opts(&opts, raw_strategies);\n-\n-\t\tret = get_revision_ranges(upstream, onto, &head_hash, NULL, NULL);\n-\t\tif (ret)\n-\t\t\treturn ret;\n-\n-\t\treturn !!init_basic_state(&opts, head_name, onto, head_hash);\n-\t}\n-\n-\tusage_with_options(builtin_rebase_helper_usage, options);\n-}\ndiff --git a/builtin/rebase--interactive.c b/builtin/rebase--interactive.c\nindex b32621b179..9c953b55bd 100644\n--- a/builtin/rebase--interactive.c\n+++ b/builtin/rebase--interactive.c\n@@ -140,7 +140,8 @@ int cmd_rebase__interactive(int argc, const char **argv, const char *prefix)\n \t\t*switch_to = NULL, *cmd = NULL;\n \tchar *raw_strategies = NULL;\n \tenum {\n-\t\tNONE = 0, CONTINUE, SKIP, EDIT_TODO, SHOW_CURRENT_PATCH\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@@ -161,6 +162,16 @@ int cmd_rebase__interactive(int argc, const char **argv, const char *prefix)\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@@ -202,6 +213,7 @@ int cmd_rebase__interactive(int argc, const char **argv, const char *prefix)\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@@ -237,6 +249,19 @@ 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+\t\tret = transform_todos(flags);\n+\t\tbreak;\n+\tcase CHECK_TODO_LIST:\n+\t\tret = check_todo_list();\n+\t\tbreak;\n+\tcase REARRANGE_SQUASH:\n+\t\tret = rearrange_squash();\n+\t\tbreak;\n+\tcase ADD_EXEC:\n+\t\tret = sequencer_add_exec_commands(cmd);\n+\t\tbreak;\n \tdefault:\n \t\tBUG(\"invalid command '%d'\", command);\n \t}\ndiff --git a/git-rebase--preserve-merges.sh b/git-rebase--preserve-merges.sh\nindex c214c5e4d6..afbb65765d 100644\n--- a/git-rebase--preserve-merges.sh\n+++ b/git-rebase--preserve-merges.sh\n@@ -711,11 +711,11 @@ do_rest () {\n }\n \n expand_todo_ids() {\n-\tgit rebase--helper --expand-ids\n+\tgit rebase--interactive --expand-ids\n }\n \n collapse_todo_ids() {\n-\tgit rebase--helper --shorten-ids\n+\tgit rebase--interactive --shorten-ids\n }\n \n # Switch to the branch in $into and notify it in the reflog\n@@ -876,8 +876,8 @@ init_revisions_and_shortrevisions () {\n \n complete_action() {\n \ttest -s \"$todo\" || echo noop >> \"$todo\"\n-\ttest -z \"$autosquash\" || git rebase--helper --rearrange-squash || exit\n-\ttest -n \"$cmd\" && git rebase--helper --add-exec-commands \"$cmd\"\n+\ttest -z \"$autosquash\" || git rebase--interactive --rearrange-squash || exit\n+\ttest -n \"$cmd\" && git rebase--interactive --add-exec-commands --cmd \"$cmd\"\n \n \ttodocount=$(git stripspace --strip-comments <\"$todo\" | wc -l)\n \ttodocount=${todocount##* }\n@@ -912,7 +912,7 @@ However, if you remove everything, the rebase will be aborted.\n \thas_action \"$todo\" ||\n \t\treturn 2\n \n-\tgit rebase--helper --check-todo-list || {\n+\tgit rebase--interactive --check-todo-list || {\n \t\tret=$?\n \t\tcheckout_onto\n \t\texit $ret\ndiff --git a/git.c b/git.c\nindex 19d0b6e3b8..81aabd1423 100644\n--- a/git.c\n+++ b/git.c\n@@ -519,7 +519,6 @@ static struct cmd_struct commands[] = {\n \t{ \"push\", cmd_push, RUN_SETUP },\n \t{ \"read-tree\", cmd_read_tree, RUN_SETUP | SUPPORT_SUPER_PREFIX},\n \t{ \"rebase--interactive\", cmd_rebase__interactive, RUN_SETUP | NEED_WORK_TREE },\n-\t{ \"rebase--helper\", cmd_rebase__helper, RUN_SETUP | NEED_WORK_TREE },\n \t{ \"receive-pack\", cmd_receive_pack },\n \t{ \"reflog\", cmd_reflog, RUN_SETUP },\n \t{ \"remote\", cmd_remote, RUN_SETUP },\n-- \n2.18.0\n\n"},{"id":"359127","messageId":"20180927215610.32210-1-alban.gruin@gmail.com","threadId":"48814","inReplyTo":"20180828121045.14933-1-alban.gruin@gmail.com","subject":"[GSoC][PATCH v8 00/20] rebase -i: rewrite in C","fromName":"Alban Gruin","fromEmail":"alban.gruin@gmail.com","sentAt":"2018-09-27T21:55:50Z","receivedAt":"2018-09-27T22:00:30Z","isPatch":true,"sender":{"key":"alban.gruin@gmail.com","avatar":"https://avatars.githubusercontent.com/u/6310153?v=4"},"body":"This patch series rewrite the interactive rebase from shell to C.\n\nThe v7 was based on ffc6fa0e39 (\"Fourth batch for 2.19 cycle\",\n2018-07-24), but this series is based on fe8321ec05 (\"Second batch post\n2.19\", 2017-09-24) due to some conflicts.\n\nChanges since v7:\n\n - [17/20] The optionnal parameter of `-S' was mandatory in\n   rebase--builtin2, making it abort when a signing key is provided to\n   `user.signingkey' and `commit.gpgsign' is set to true.  First\n   reported on github[0], fixed by Johannes Schindelin.\n\n - [2, 5, 19, 20/20] Changes due to the rebase.\n\n - [9, 11/20] Conflict solving.\n\nAlban Gruin (20):\n  sequencer: make three functions and an enum from sequencer.c public\n  rebase -i: rewrite append_todo_help() in C\n  editor: add a function to launch the sequence editor\n  rebase -i: rewrite the edit-todo functionality in C\n  sequencer: add a new function to silence a command, except if it fails\n  rebase -i: rewrite setup_reflog_action() in C\n  rebase -i: rewrite checkout_onto() in C\n  sequencer: refactor append_todo_help() to write its message to a\n    buffer\n  sequencer: change the way skip_unnecessary_picks() returns its result\n  t3404: todo list with commented-out commands only aborts\n  rebase -i: rewrite complete_action() in C\n  rebase -i: remove unused modes and functions\n  rebase -i: implement the logic to initialize $revisions in C\n  rebase -i: rewrite the rest of init_revisions_and_shortrevisions() in\n    C\n  rebase -i: rewrite write_basic_state() in C\n  rebase -i: rewrite init_basic_state() in C\n  rebase -i: implement the main part of interactive rebase as a builtin\n  rebase--interactive2: rewrite the submodes of interactive rebase in C\n  rebase -i: remove git-rebase--interactive.sh\n  rebase -i: move rebase--helper modes to rebase--interactive\n\n .gitignore                     |   1 -\n Makefile                       |   5 +-\n builtin.h                      |   2 +-\n builtin/rebase--helper.c       |  88 ---------\n builtin/rebase--interactive.c  | 271 ++++++++++++++++++++++++++++\n cache.h                        |   1 +\n editor.c                       |  27 ++-\n git-rebase--interactive.sh     | 283 -----------------------------\n git-rebase--preserve-merges.sh |  10 +-\n git-rebase.sh                  |  47 ++++-\n git.c                          |   2 +-\n rebase-interactive.c           |  90 ++++++++++\n rebase-interactive.h           |   8 +\n sequencer.c                    | 320 +++++++++++++++++++++++++++------\n sequencer.h                    |  22 ++-\n strbuf.h                       |   2 +\n t/t3404-rebase-interactive.sh  |  10 ++\n 17 files changed, 740 insertions(+), 449 deletions(-)\n delete mode 100644 builtin/rebase--helper.c\n create mode 100644 builtin/rebase--interactive.c\n delete mode 100644 git-rebase--interactive.sh\n create mode 100644 rebase-interactive.c\n create mode 100644 rebase-interactive.h\n\n-- \n2.19.0\n\n"},{"id":"359128","messageId":"20180927215610.32210-2-alban.gruin@gmail.com","threadId":"48814","inReplyTo":"20180927215610.32210-1-alban.gruin@gmail.com","subject":"[GSoC][PATCH v8 01/20] sequencer: make three functions and an enum from sequencer.c public","fromName":"Alban Gruin","fromEmail":"alban.gruin@gmail.com","sentAt":"2018-09-27T21:55:51Z","receivedAt":"2018-09-27T22:00:33Z","isPatch":true,"sender":{"key":"alban.gruin@gmail.com","avatar":"https://avatars.githubusercontent.com/u/6310153?v=4"},"body":"This makes rebase_path_todo(), get_missing_commit_check_level(),\nwrite_message() and the enum check_level accessible outside sequencer.c,\nrenames check_level to missing_commit_check_level, and prefixes its\nvalue names by MISSING_COMMIT_ to avoid namespace pollution.\n\nThis function and this enum will eventually be moved to\nrebase-interactive.c and become static again, so no special attention\nwas given to the naming.\n\nThis will be needed for the rewrite of append_todo_help() from shell to\nC, as it will be in a new library source file, rebase-interactive.c.\n\nSigned-off-by: Alban Gruin <alban.gruin@gmail.com>\n---\nNo changes since v7.\n\n sequencer.c | 26 +++++++++++---------------\n sequencer.h | 11 +++++++++++\n 2 files changed, 22 insertions(+), 15 deletions(-)\n\ndiff --git a/sequencer.c b/sequencer.c\nindex ddb41a62d9..c24d37dfb1 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -53,7 +53,7 @@ static GIT_PATH_FUNC(rebase_path, \"rebase-merge\")\n  * the lines are processed, they are removed from the front of this\n  * file and written to the tail of 'done'.\n  */\n-static GIT_PATH_FUNC(rebase_path_todo, \"rebase-merge/git-rebase-todo\")\n+GIT_PATH_FUNC(rebase_path_todo, \"rebase-merge/git-rebase-todo\")\n /*\n  * The rebase command lines that have already been processed. A line\n  * is moved here when it is first handled, before any associated user\n@@ -377,8 +377,8 @@ static void print_advice(int show_hint, struct replay_opts *opts)\n \t}\n }\n \n-static int write_message(const void *buf, size_t len, const char *filename,\n-\t\t\t int append_eol)\n+int write_message(const void *buf, size_t len, const char *filename,\n+\t\t  int append_eol)\n {\n \tstruct lock_file msg_file = LOCK_INIT;\n \n@@ -4422,24 +4422,20 @@ int transform_todos(unsigned flags)\n \treturn i;\n }\n \n-enum check_level {\n-\tCHECK_IGNORE = 0, CHECK_WARN, CHECK_ERROR\n-};\n-\n-static enum check_level get_missing_commit_check_level(void)\n+enum missing_commit_check_level get_missing_commit_check_level(void)\n {\n \tconst char *value;\n \n \tif (git_config_get_value(\"rebase.missingcommitscheck\", &value) ||\n \t\t\t!strcasecmp(\"ignore\", value))\n-\t\treturn CHECK_IGNORE;\n+\t\treturn MISSING_COMMIT_CHECK_IGNORE;\n \tif (!strcasecmp(\"warn\", value))\n-\t\treturn CHECK_WARN;\n+\t\treturn MISSING_COMMIT_CHECK_WARN;\n \tif (!strcasecmp(\"error\", value))\n-\t\treturn CHECK_ERROR;\n+\t\treturn MISSING_COMMIT_CHECK_ERROR;\n \twarning(_(\"unrecognized setting %s for option \"\n \t\t  \"rebase.missingCommitsCheck. Ignoring.\"), value);\n-\treturn CHECK_IGNORE;\n+\treturn MISSING_COMMIT_CHECK_IGNORE;\n }\n \n define_commit_slab(commit_seen, unsigned char);\n@@ -4451,7 +4447,7 @@ define_commit_slab(commit_seen, unsigned char);\n  */\n int check_todo_list(void)\n {\n-\tenum check_level check_level = get_missing_commit_check_level();\n+\tenum missing_commit_check_level check_level = get_missing_commit_check_level();\n \tstruct strbuf todo_file = STRBUF_INIT;\n \tstruct todo_list todo_list = TODO_LIST_INIT;\n \tstruct strbuf missing = STRBUF_INIT;\n@@ -4468,7 +4464,7 @@ int check_todo_list(void)\n \tadvise_to_edit_todo = res =\n \t\tparse_insn_buffer(todo_list.buf.buf, &todo_list);\n \n-\tif (res || check_level == CHECK_IGNORE)\n+\tif (res || check_level == MISSING_COMMIT_CHECK_IGNORE)\n \t\tgoto leave_check;\n \n \t/* Mark the commits in git-rebase-todo as seen */\n@@ -4503,7 +4499,7 @@ int check_todo_list(void)\n \tif (!missing.len)\n \t\tgoto leave_check;\n \n-\tif (check_level == CHECK_ERROR)\n+\tif (check_level == MISSING_COMMIT_CHECK_ERROR)\n \t\tadvise_to_edit_todo = res = 1;\n \n \tfprintf(stderr,\ndiff --git a/sequencer.h b/sequencer.h\nindex c986bc8251..579de9127b 100644\n--- a/sequencer.h\n+++ b/sequencer.h\n@@ -8,6 +8,7 @@ struct commit;\n \n const char *git_path_commit_editmsg(void);\n const char *git_path_seq_dir(void);\n+const char *rebase_path_todo(void);\n \n #define APPEND_SIGNOFF_DEDUP (1u << 0)\n \n@@ -62,6 +63,15 @@ struct replay_opts {\n };\n #define REPLAY_OPTS_INIT { .action = -1, .current_fixups = STRBUF_INIT }\n \n+enum missing_commit_check_level {\n+\tMISSING_COMMIT_CHECK_IGNORE = 0,\n+\tMISSING_COMMIT_CHECK_WARN,\n+\tMISSING_COMMIT_CHECK_ERROR\n+};\n+\n+int write_message(const void *buf, size_t len, const char *filename,\n+\t\t  int append_eol);\n+\n /* Call this to setup defaults before parsing command line options */\n void sequencer_init_config(struct replay_opts *opts);\n int sequencer_pick_revisions(struct replay_opts *opts);\n@@ -84,6 +94,7 @@ int sequencer_make_script(FILE *out, int argc, const char **argv,\n \n int sequencer_add_exec_commands(const char *command);\n int transform_todos(unsigned flags);\n+enum missing_commit_check_level get_missing_commit_check_level(void);\n int check_todo_list(void);\n int skip_unnecessary_picks(void);\n int rearrange_squash(void);\n-- \n2.19.0\n\n"},{"id":"359129","messageId":"20180927215610.32210-3-alban.gruin@gmail.com","threadId":"48814","inReplyTo":"20180927215610.32210-1-alban.gruin@gmail.com","subject":"[GSoC][PATCH v8 02/20] rebase -i: rewrite append_todo_help() in C","fromName":"Alban Gruin","fromEmail":"alban.gruin@gmail.com","sentAt":"2018-09-27T21:55:52Z","receivedAt":"2018-09-27T22:00:34Z","isPatch":true,"sender":{"key":"alban.gruin@gmail.com","avatar":"https://avatars.githubusercontent.com/u/6310153?v=4"},"body":"This rewrites append_todo_help() from shell to C. It also incorporates\nsome parts of initiate_action() and complete_action() that also write\nhelp texts to the todo file.\n\nThis also introduces the source file rebase-interactive.c. This file\nwill contain functions necessary for interactive rebase that are too\nspecific for the sequencer, and is part of libgit.a.\n\nTwo flags are added to rebase--helper.c: one to call\nappend_todo_help() (`--append-todo-help`), and another one to tell\nappend_todo_help() to write the help text suited for the edit-todo\nmode (`--write-edit-todo`).\n\nFinally, append_todo_help() is removed from git-rebase--interactive.sh\nto use `rebase--helper --append-todo-help` instead.\n\nSigned-off-by: Alban Gruin <alban.gruin@gmail.com>\n---\nThe changes are due to the rebase, no real changes otherwise.\n\n Makefile                   |  1 +\n builtin/rebase--helper.c   | 11 ++++--\n git-rebase--interactive.sh | 52 ++---------------------------\n rebase-interactive.c       | 68 ++++++++++++++++++++++++++++++++++++++\n rebase-interactive.h       |  6 ++++\n 5 files changed, 86 insertions(+), 52 deletions(-)\n create mode 100644 rebase-interactive.c\n create mode 100644 rebase-interactive.h\n\ndiff --git a/Makefile b/Makefile\nindex 13e1c52478..ff7f01634f 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -942,6 +942,7 @@ LIB_OBJS += quote.o\n LIB_OBJS += range-diff.o\n LIB_OBJS += reachable.o\n LIB_OBJS += read-cache.o\n+LIB_OBJS += rebase-interactive.o\n LIB_OBJS += reflog-walk.o\n LIB_OBJS += refs.o\n LIB_OBJS += refs/files-backend.o\ndiff --git a/builtin/rebase--helper.c b/builtin/rebase--helper.c\nindex f7c2a5fdc8..05e73e71d4 100644\n--- a/builtin/rebase--helper.c\n+++ b/builtin/rebase--helper.c\n@@ -3,6 +3,7 @@\n #include \"config.h\"\n #include \"parse-options.h\"\n #include \"sequencer.h\"\n+#include \"rebase-interactive.h\"\n \n static const char * const builtin_rebase_helper_usage[] = {\n \tN_(\"git rebase--helper [<options>]\"),\n@@ -12,12 +13,12 @@ static const char * const builtin_rebase_helper_usage[] = {\n int cmd_rebase__helper(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;\n+\tunsigned flags = 0, keep_empty = 0, rebase_merges = 0, write_edit_todo = 0;\n \tint abbreviate_commands = 0, rebase_cousins = -1;\n \tenum {\n \t\tCONTINUE = 1, ABORT, MAKE_SCRIPT, SHORTEN_OIDS, EXPAND_OIDS,\n \t\tCHECK_TODO_LIST, SKIP_UNNECESSARY_PICKS, REARRANGE_SQUASH,\n-\t\tADD_EXEC\n+\t\tADD_EXEC, APPEND_TODO_HELP\n \t} command = 0;\n \tstruct option options[] = {\n \t\tOPT_BOOL(0, \"ff\", &opts.allow_ff, N_(\"allow fast-forward\")),\n@@ -27,6 +28,8 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\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, \"write-edit-todo\", &write_edit_todo,\n+\t\t\t N_(\"append the edit-todo message to the todo-list\")),\n \t\tOPT_CMDMODE(0, \"continue\", &command, N_(\"continue rebase\"),\n \t\t\t\tCONTINUE),\n \t\tOPT_CMDMODE(0, \"abort\", &command, N_(\"abort rebase\"),\n@@ -45,6 +48,8 @@ int cmd_rebase__helper(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_CMDMODE(0, \"append-todo-help\", &command,\n+\t\t\t    N_(\"insert the help in the todo list\"), APPEND_TODO_HELP),\n \t\tOPT_END()\n \t};\n \n@@ -84,5 +89,7 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\n \t\treturn !!rearrange_squash();\n \tif (command == ADD_EXEC && argc == 2)\n \t\treturn !!sequencer_add_exec_commands(argv[1]);\n+\tif (command == APPEND_TODO_HELP && argc == 1)\n+\t\treturn !!append_todo_help(write_edit_todo, keep_empty);\n \tusage_with_options(builtin_rebase_helper_usage, options);\n }\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex 299ded2137..94c23a7af2 100644\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -39,38 +39,6 @@ comment_for_reflog () {\n \tesac\n }\n \n-append_todo_help () {\n-\tgettext \"\n-Commands:\n-p, pick <commit> = use commit\n-r, reword <commit> = use commit, but edit the commit message\n-e, edit <commit> = use commit, but stop for amending\n-s, squash <commit> = use commit, but meld into previous commit\n-f, fixup <commit> = like \\\"squash\\\", but discard this commit's log message\n-x, exec <command> = run command (the rest of the line) using shell\n-d, drop <commit> = remove commit\n-l, label <label> = label current HEAD with a name\n-t, reset <label> = reset HEAD to a label\n-m, merge [-C <commit> | -c <commit>] <label> [# <oneline>]\n-.       create a merge commit using the original merge commit's\n-.       message (or the oneline, if no original merge commit was\n-.       specified). Use -c <commit> to reword the commit message.\n-\n-These lines can be re-ordered; they are executed from top to bottom.\n-\" | git stripspace --comment-lines >>\"$todo\"\n-\n-\tif test $(get_missing_commit_check_level) = error\n-\tthen\n-\t\tgettext \"\n-Do not remove any line. Use 'drop' explicitly to remove a commit.\n-\" | git stripspace --comment-lines >>\"$todo\"\n-\telse\n-\t\tgettext \"\n-If you remove a line here THAT COMMIT WILL BE LOST.\n-\" | git stripspace --comment-lines >>\"$todo\"\n-\tfi\n-}\n-\n die_abort () {\n \tapply_autostash\n \trm -rf \"$state_dir\"\n@@ -143,13 +111,7 @@ initiate_action () {\n \t\tgit stripspace --strip-comments <\"$todo\" >\"$todo\".new\n \t\tmv -f \"$todo\".new \"$todo\"\n \t\tcollapse_todo_ids\n-\t\tappend_todo_help\n-\t\tgettext \"\n-You are editing the todo file of an ongoing interactive rebase.\n-To continue rebase after editing, run:\n-    git rebase --continue\n-\n-\" | git stripspace --comment-lines >>\"$todo\"\n+\t\tgit rebase--helper --append-todo-help --write-edit-todo\n \n \t\tgit_sequence_editor \"$todo\" ||\n \t\t\tdie \"$(gettext \"Could not execute editor\")\"\n@@ -220,17 +182,7 @@ $comment_char $(eval_ngettext \\\n \t\"Rebase \\$shortrevisions onto \\$shortonto (\\$todocount commands)\" \\\n \t\"$todocount\")\n EOF\n-\tappend_todo_help\n-\tgettext \"\n-\tHowever, if you remove everything, the rebase will be aborted.\n-\n-\t\" | git stripspace --comment-lines >>\"$todo\"\n-\n-\tif test -z \"$keep_empty\"\n-\tthen\n-\t\tprintf '%s\\n' \"$comment_char $(gettext \"Note that empty commits are commented out\")\" >>\"$todo\"\n-\tfi\n-\n+\tgit rebase--helper --append-todo-help ${keep_empty:+--keep-empty}\n \n \thas_action \"$todo\" ||\n \t\treturn 2\ndiff --git a/rebase-interactive.c b/rebase-interactive.c\nnew file mode 100644\nindex 0000000000..d7996bc8d9\n--- /dev/null\n+++ b/rebase-interactive.c\n@@ -0,0 +1,68 @@\n+#include \"cache.h\"\n+#include \"commit.h\"\n+#include \"rebase-interactive.h\"\n+#include \"sequencer.h\"\n+#include \"strbuf.h\"\n+\n+int append_todo_help(unsigned edit_todo, unsigned keep_empty)\n+{\n+\tstruct strbuf buf = STRBUF_INIT;\n+\tFILE *todo;\n+\tint ret;\n+\tconst char *msg = _(\"\\nCommands:\\n\"\n+\"p, pick <commit> = use commit\\n\"\n+\"r, reword <commit> = use commit, but edit the commit message\\n\"\n+\"e, edit <commit> = use commit, but stop for amending\\n\"\n+\"s, squash <commit> = use commit, but meld into previous commit\\n\"\n+\"f, fixup <commit> = like \\\"squash\\\", but discard this commit's log message\\n\"\n+\"x, exec <command> = run command (the rest of the line) using shell\\n\"\n+\"d, drop <commit> = remove commit\\n\"\n+\"l, label <label> = label current HEAD with a name\\n\"\n+\"t, reset <label> = reset HEAD to a label\\n\"\n+\"m, merge [-C <commit> | -c <commit>] <label> [# <oneline>]\\n\"\n+\".       create a merge commit using the original merge commit's\\n\"\n+\".       message (or the oneline, if no original merge commit was\\n\"\n+\".       specified). Use -c <commit> to reword the commit message.\\n\"\n+\"\\n\"\n+\"These lines can be re-ordered; they are executed from top to bottom.\\n\");\n+\n+\ttodo = fopen_or_warn(rebase_path_todo(), \"a\");\n+\tif (!todo)\n+\t\treturn 1;\n+\n+\tstrbuf_add_commented_lines(&buf, msg, strlen(msg));\n+\n+\tif (get_missing_commit_check_level() == MISSING_COMMIT_CHECK_ERROR)\n+\t\tmsg = _(\"\\nDo not remove any line. Use 'drop' \"\n+\t\t\t \"explicitly to remove a commit.\\n\");\n+\telse\n+\t\tmsg = _(\"\\nIf you remove a line here \"\n+\t\t\t \"THAT COMMIT WILL BE LOST.\\n\");\n+\n+\tstrbuf_add_commented_lines(&buf, msg, strlen(msg));\n+\n+\tif (edit_todo)\n+\t\tmsg = _(\"\\nYou are editing the todo file \"\n+\t\t\t\"of an ongoing interactive rebase.\\n\"\n+\t\t\t\"To continue rebase after editing, run:\\n\"\n+\t\t\t\"    git rebase --continue\\n\\n\");\n+\telse\n+\t\tmsg = _(\"\\nHowever, if you remove everything, \"\n+\t\t\t\"the rebase will be aborted.\\n\\n\");\n+\n+\tstrbuf_add_commented_lines(&buf, msg, strlen(msg));\n+\n+\tif (!keep_empty) {\n+\t\tmsg = _(\"Note that empty commits are commented out\");\n+\t\tstrbuf_add_commented_lines(&buf, msg, strlen(msg));\n+\t}\n+\n+\tret = fputs(buf.buf, todo);\n+\tif (ret < 0)\n+\t\terror_errno(_(\"could not append help text to '%s'\"), rebase_path_todo());\n+\n+\tfclose(todo);\n+\tstrbuf_release(&buf);\n+\n+\treturn ret;\n+}\ndiff --git a/rebase-interactive.h b/rebase-interactive.h\nnew file mode 100644\nindex 0000000000..47372624e0\n--- /dev/null\n+++ b/rebase-interactive.h\n@@ -0,0 +1,6 @@\n+#ifndef REBASE_INTERACTIVE_H\n+#define REBASE_INTERACTIVE_H\n+\n+int append_todo_help(unsigned edit_todo, unsigned keep_empty);\n+\n+#endif\n-- \n2.19.0\n\n"},{"id":"359130","messageId":"20180927215610.32210-4-alban.gruin@gmail.com","threadId":"48814","inReplyTo":"20180927215610.32210-1-alban.gruin@gmail.com","subject":"[GSoC][PATCH v8 03/20] editor: add a function to launch the sequence editor","fromName":"Alban Gruin","fromEmail":"alban.gruin@gmail.com","sentAt":"2018-09-27T21:55:53Z","receivedAt":"2018-09-27T22:00:36Z","isPatch":true,"sender":{"key":"alban.gruin@gmail.com","avatar":"https://avatars.githubusercontent.com/u/6310153?v=4"},"body":"As part of the rewrite of interactive rebase, the sequencer will need to\nopen the sequence editor to allow the user to edit the todo list.\nInstead of duplicating the existing launch_editor() function, this\nrefactors it to a new function, launch_specified_editor(), which takes\nthe editor as a parameter, in addition to the path, the buffer and the\nenvironment variables.  launch_sequence_editor() is then added to launch\nthe sequence editor.\n\nSigned-off-by: Alban Gruin <alban.gruin@gmail.com>\n---\nNo changes since v7.\n\n cache.h  |  1 +\n editor.c | 27 +++++++++++++++++++++++++--\n strbuf.h |  2 ++\n 3 files changed, 28 insertions(+), 2 deletions(-)\n\ndiff --git a/cache.h b/cache.h\nindex d508f3d4f8..a976e26a02 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -1482,6 +1482,7 @@ extern const char *fmt_name(const char *name, const char *email);\n extern const char *ident_default_name(void);\n extern const char *ident_default_email(void);\n extern const char *git_editor(void);\n+extern const char *git_sequence_editor(void);\n extern const char *git_pager(int stdout_is_tty);\n extern int is_terminal_dumb(void);\n extern int git_ident_config(const char *, const char *, void *);\ndiff --git a/editor.c b/editor.c\nindex 9a9b4e12d1..c985eee1f9 100644\n--- a/editor.c\n+++ b/editor.c\n@@ -1,4 +1,5 @@\n #include \"cache.h\"\n+#include \"config.h\"\n #include \"strbuf.h\"\n #include \"run-command.h\"\n #include \"sigchain.h\"\n@@ -34,10 +35,21 @@ const char *git_editor(void)\n \treturn editor;\n }\n \n-int launch_editor(const char *path, struct strbuf *buffer, const char *const *env)\n+const char *git_sequence_editor(void)\n {\n-\tconst char *editor = git_editor();\n+\tconst char *editor = getenv(\"GIT_SEQUENCE_EDITOR\");\n+\n+\tif (!editor)\n+\t\tgit_config_get_string_const(\"sequence.editor\", &editor);\n+\tif (!editor)\n+\t\teditor = git_editor();\n \n+\treturn editor;\n+}\n+\n+static int launch_specified_editor(const char *editor, const char *path,\n+\t\t\t\t   struct strbuf *buffer, const char *const *env)\n+{\n \tif (!editor)\n \t\treturn error(\"Terminal is dumb, but EDITOR unset\");\n \n@@ -95,3 +107,14 @@ int launch_editor(const char *path, struct strbuf *buffer, const char *const *en\n \t\treturn error_errno(\"could not read file '%s'\", path);\n \treturn 0;\n }\n+\n+int launch_editor(const char *path, struct strbuf *buffer, const char *const *env)\n+{\n+\treturn launch_specified_editor(git_editor(), path, buffer, env);\n+}\n+\n+int launch_sequence_editor(const char *path, struct strbuf *buffer,\n+\t\t\t   const char *const *env)\n+{\n+\treturn launch_specified_editor(git_sequence_editor(), path, buffer, env);\n+}\ndiff --git a/strbuf.h b/strbuf.h\nindex 60a35aef16..66da9822fd 100644\n--- a/strbuf.h\n+++ b/strbuf.h\n@@ -575,6 +575,8 @@ extern void strbuf_add_unique_abbrev(struct strbuf *sb,\n  * file's contents are not read into the buffer upon completion.\n  */\n extern int launch_editor(const char *path, struct strbuf *buffer, const char *const *env);\n+extern int launch_sequence_editor(const char *path, struct strbuf *buffer,\n+\t\t\t\t  const char *const *env);\n \n extern void strbuf_add_lines(struct strbuf *sb, const char *prefix, const char *buf, size_t size);\n \n-- \n2.19.0\n\n"},{"id":"359131","messageId":"20180927215610.32210-5-alban.gruin@gmail.com","threadId":"48814","inReplyTo":"20180927215610.32210-1-alban.gruin@gmail.com","subject":"[GSoC][PATCH v8 04/20] rebase -i: rewrite the edit-todo functionality in C","fromName":"Alban Gruin","fromEmail":"alban.gruin@gmail.com","sentAt":"2018-09-27T21:55:54Z","receivedAt":"2018-09-27T22:00:36Z","isPatch":true,"sender":{"key":"alban.gruin@gmail.com","avatar":"https://avatars.githubusercontent.com/u/6310153?v=4"},"body":"This rewrites the edit-todo functionality from shell to C.\n\nTo achieve that, a new command mode, `edit-todo`, is added, and the\n`write-edit-todo` flag is removed, as the shell script does not need to\nwrite the edit todo help message to the todo list anymore.\n\nThe shell version is then stripped in favour of a call to the helper.\n\nSigned-off-by: Alban Gruin <alban.gruin@gmail.com>\n---\nNo changes since v7.\n\n builtin/rebase--helper.c   | 13 ++++++++-----\n git-rebase--interactive.sh | 11 +----------\n rebase-interactive.c       | 27 +++++++++++++++++++++++++++\n rebase-interactive.h       |  1 +\n 4 files changed, 37 insertions(+), 15 deletions(-)\n\ndiff --git a/builtin/rebase--helper.c b/builtin/rebase--helper.c\nindex 05e73e71d4..731a64971d 100644\n--- a/builtin/rebase--helper.c\n+++ b/builtin/rebase--helper.c\n@@ -13,12 +13,12 @@ static const char * const builtin_rebase_helper_usage[] = {\n int cmd_rebase__helper(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, write_edit_todo = 0;\n+\tunsigned flags = 0, keep_empty = 0, rebase_merges = 0;\n \tint abbreviate_commands = 0, rebase_cousins = -1;\n \tenum {\n \t\tCONTINUE = 1, ABORT, MAKE_SCRIPT, SHORTEN_OIDS, EXPAND_OIDS,\n \t\tCHECK_TODO_LIST, SKIP_UNNECESSARY_PICKS, REARRANGE_SQUASH,\n-\t\tADD_EXEC, APPEND_TODO_HELP\n+\t\tADD_EXEC, APPEND_TODO_HELP, EDIT_TODO\n \t} command = 0;\n \tstruct option options[] = {\n \t\tOPT_BOOL(0, \"ff\", &opts.allow_ff, N_(\"allow fast-forward\")),\n@@ -28,8 +28,6 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\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, \"write-edit-todo\", &write_edit_todo,\n-\t\t\t N_(\"append the edit-todo message to the todo-list\")),\n \t\tOPT_CMDMODE(0, \"continue\", &command, N_(\"continue rebase\"),\n \t\t\t\tCONTINUE),\n \t\tOPT_CMDMODE(0, \"abort\", &command, N_(\"abort rebase\"),\n@@ -50,6 +48,9 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\n \t\t\tN_(\"insert exec commands in todo list\"), ADD_EXEC),\n \t\tOPT_CMDMODE(0, \"append-todo-help\", &command,\n \t\t\t    N_(\"insert the help in the todo list\"), APPEND_TODO_HELP),\n+\t\tOPT_CMDMODE(0, \"edit-todo\", &command,\n+\t\t\t    N_(\"edit the todo list during an interactive rebase\"),\n+\t\t\t    EDIT_TODO),\n \t\tOPT_END()\n \t};\n \n@@ -90,6 +91,8 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\n \tif (command == ADD_EXEC && argc == 2)\n \t\treturn !!sequencer_add_exec_commands(argv[1]);\n \tif (command == APPEND_TODO_HELP && argc == 1)\n-\t\treturn !!append_todo_help(write_edit_todo, keep_empty);\n+\t\treturn !!append_todo_help(0, keep_empty);\n+\tif (command == EDIT_TODO && argc == 1)\n+\t\treturn !!edit_todo_list(flags);\n \tusage_with_options(builtin_rebase_helper_usage, options);\n }\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex 94c23a7af2..2defe607f4 100644\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -108,16 +108,7 @@ initiate_action () {\n \t\t     --continue\n \t\t;;\n \tedit-todo)\n-\t\tgit stripspace --strip-comments <\"$todo\" >\"$todo\".new\n-\t\tmv -f \"$todo\".new \"$todo\"\n-\t\tcollapse_todo_ids\n-\t\tgit rebase--helper --append-todo-help --write-edit-todo\n-\n-\t\tgit_sequence_editor \"$todo\" ||\n-\t\t\tdie \"$(gettext \"Could not execute editor\")\"\n-\t\texpand_todo_ids\n-\n-\t\texit\n+\t\texec git rebase--helper --edit-todo\n \t\t;;\n \tshow-current-patch)\n \t\texec git show REBASE_HEAD --\ndiff --git a/rebase-interactive.c b/rebase-interactive.c\nindex d7996bc8d9..3f9468fc69 100644\n--- a/rebase-interactive.c\n+++ b/rebase-interactive.c\n@@ -66,3 +66,30 @@ int append_todo_help(unsigned edit_todo, unsigned keep_empty)\n \n \treturn ret;\n }\n+\n+int edit_todo_list(unsigned flags)\n+{\n+\tstruct strbuf buf = STRBUF_INIT;\n+\tconst char *todo_file = rebase_path_todo();\n+\n+\tif (strbuf_read_file(&buf, todo_file, 0) < 0)\n+\t\treturn error_errno(_(\"could not read '%s'.\"), todo_file);\n+\n+\tstrbuf_stripspace(&buf, 1);\n+\tif (write_message(buf.buf, buf.len, todo_file, 0)) {\n+\t\tstrbuf_release(&buf);\n+\t\treturn -1;\n+\t}\n+\n+\tstrbuf_release(&buf);\n+\n+\ttransform_todos(flags | TODO_LIST_SHORTEN_IDS);\n+\tappend_todo_help(1, 0);\n+\n+\tif (launch_sequence_editor(todo_file, NULL, NULL))\n+\t\treturn -1;\n+\n+\ttransform_todos(flags & ~(TODO_LIST_SHORTEN_IDS));\n+\n+\treturn 0;\n+}\ndiff --git a/rebase-interactive.h b/rebase-interactive.h\nindex 47372624e0..155219e742 100644\n--- a/rebase-interactive.h\n+++ b/rebase-interactive.h\n@@ -2,5 +2,6 @@\n #define REBASE_INTERACTIVE_H\n \n int append_todo_help(unsigned edit_todo, unsigned keep_empty);\n+int edit_todo_list(unsigned flags);\n \n #endif\n-- \n2.19.0\n\n"},{"id":"359132","messageId":"20180927215610.32210-6-alban.gruin@gmail.com","threadId":"48814","inReplyTo":"20180927215610.32210-1-alban.gruin@gmail.com","subject":"[GSoC][PATCH v8 05/20] sequencer: add a new function to silence a command, except if it fails","fromName":"Alban Gruin","fromEmail":"alban.gruin@gmail.com","sentAt":"2018-09-27T21:55:55Z","receivedAt":"2018-09-27T22:00:38Z","isPatch":true,"sender":{"key":"alban.gruin@gmail.com","avatar":"https://avatars.githubusercontent.com/u/6310153?v=4"},"body":"This adds a new function, run_command_silent_on_success(), to\nredirect the stdout and stderr of a command to a strbuf, and then to run\nthat command. This strbuf is printed only if the command fails. It is\nfunctionnaly similar to output() from git-rebase.sh.\n\nrun_git_commit() is then refactored to use of\nrun_command_silent_on_success().\n\nSigned-off-by: Alban Gruin <alban.gruin@gmail.com>\n---\nThe changes are due to the rebase, no real changes otherwise.\n\n sequencer.c | 51 +++++++++++++++++++++++++--------------------------\n 1 file changed, 25 insertions(+), 26 deletions(-)\n\ndiff --git a/sequencer.c b/sequencer.c\nindex c24d37dfb1..5919ad312e 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -804,6 +804,23 @@ N_(\"you have staged changes in your working tree\\n\"\n #define VERIFY_MSG  (1<<4)\n #define CREATE_ROOT_COMMIT (1<<5)\n \n+static int run_command_silent_on_success(struct child_process *cmd)\n+{\n+\tstruct strbuf buf = STRBUF_INIT;\n+\tint rc;\n+\n+\tcmd->stdout_to_stderr = 1;\n+\trc = pipe_command(cmd,\n+\t\t\t  NULL, 0,\n+\t\t\t  NULL, 0,\n+\t\t\t  &buf, 0);\n+\n+\tif (rc)\n+\t\tfputs(buf.buf, stderr);\n+\tstrbuf_release(&buf);\n+\treturn rc;\n+}\n+\n /*\n  * If we are cherry-pick, and if the merge did not result in\n  * hand-editing, we will hit this commit and inherit the original\n@@ -865,18 +882,11 @@ static int run_git_commit(const char *defmsg, struct replay_opts *opts,\n \n \tcmd.git_cmd = 1;\n \n-\tif (is_rebase_i(opts)) {\n-\t\tif (!(flags & EDIT_MSG)) {\n-\t\t\tcmd.stdout_to_stderr = 1;\n-\t\t\tcmd.err = -1;\n-\t\t}\n+\tif (is_rebase_i(opts) && read_env_script(&cmd.env_array)) {\n+\t\tconst char *gpg_opt = gpg_sign_opt_quoted(opts);\n \n-\t\tif (read_env_script(&cmd.env_array)) {\n-\t\t\tconst char *gpg_opt = gpg_sign_opt_quoted(opts);\n-\n-\t\t\treturn error(_(staged_changes_advice),\n-\t\t\t\t     gpg_opt, gpg_opt);\n-\t\t}\n+\t\treturn error(_(staged_changes_advice),\n+\t\t\t     gpg_opt, gpg_opt);\n \t}\n \n \targv_array_push(&cmd.args, \"commit\");\n@@ -906,21 +916,10 @@ static int run_git_commit(const char *defmsg, struct replay_opts *opts,\n \tif (!(flags & EDIT_MSG))\n \t\targv_array_push(&cmd.args, \"--allow-empty-message\");\n \n-\tif (cmd.err == -1) {\n-\t\t/* hide stderr on success */\n-\t\tstruct strbuf buf = STRBUF_INIT;\n-\t\tint rc = pipe_command(&cmd,\n-\t\t\t\t      NULL, 0,\n-\t\t\t\t      /* stdout is already redirected */\n-\t\t\t\t      NULL, 0,\n-\t\t\t\t      &buf, 0);\n-\t\tif (rc)\n-\t\t\tfputs(buf.buf, stderr);\n-\t\tstrbuf_release(&buf);\n-\t\treturn rc;\n-\t}\n-\n-\treturn run_command(&cmd);\n+\tif (is_rebase_i(opts) && !(flags & EDIT_MSG))\n+\t\treturn run_command_silent_on_success(&cmd);\n+\telse\n+\t\treturn run_command(&cmd);\n }\n \n static int rest_is_empty(const struct strbuf *sb, int start)\n-- \n2.19.0\n\n"},{"id":"359133","messageId":"20180927215610.32210-7-alban.gruin@gmail.com","threadId":"48814","inReplyTo":"20180927215610.32210-1-alban.gruin@gmail.com","subject":"[GSoC][PATCH v8 06/20] rebase -i: rewrite setup_reflog_action() in C","fromName":"Alban Gruin","fromEmail":"alban.gruin@gmail.com","sentAt":"2018-09-27T21:55:56Z","receivedAt":"2018-09-27T22:00:39Z","isPatch":true,"sender":{"key":"alban.gruin@gmail.com","avatar":"https://avatars.githubusercontent.com/u/6310153?v=4"},"body":"This rewrites (the misnamed) setup_reflog_action() from shell to C. The\nnew version is called prepare_branch_to_be_rebased().\n\nA new command is added to rebase--helper.c, “checkout-base”, as well as\na new flag, “verbose”, to avoid silencing the output of the checkout\noperation called by checkout_base_commit().\n\nThe function `run_git_checkout()` will also be used in the next commit,\ntherefore its code is not part of `checkout_base_commit()`.\n\nThe shell version is then stripped in favour of a call to the helper.\n\nAs $GIT_REFLOG_ACTION is no longer set at the first call of\ncheckout_onto(), a call to comment_for_reflog() is added at the\nbeginning of this function.\n\nSigned-off-by: Alban Gruin <alban.gruin@gmail.com>\n---\nNo changes since v7.\n\n builtin/rebase--helper.c   |  7 ++++++-\n git-rebase--interactive.sh | 16 ++--------------\n sequencer.c                | 30 ++++++++++++++++++++++++++++++\n sequencer.h                |  2 ++\n 4 files changed, 40 insertions(+), 15 deletions(-)\n\ndiff --git a/builtin/rebase--helper.c b/builtin/rebase--helper.c\nindex 731a64971d..0e76dadba6 100644\n--- a/builtin/rebase--helper.c\n+++ b/builtin/rebase--helper.c\n@@ -18,7 +18,7 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\n \tenum {\n \t\tCONTINUE = 1, ABORT, MAKE_SCRIPT, SHORTEN_OIDS, EXPAND_OIDS,\n \t\tCHECK_TODO_LIST, SKIP_UNNECESSARY_PICKS, REARRANGE_SQUASH,\n-\t\tADD_EXEC, APPEND_TODO_HELP, EDIT_TODO\n+\t\tADD_EXEC, APPEND_TODO_HELP, EDIT_TODO, PREPARE_BRANCH\n \t} command = 0;\n \tstruct option options[] = {\n \t\tOPT_BOOL(0, \"ff\", &opts.allow_ff, N_(\"allow fast-forward\")),\n@@ -28,6 +28,7 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\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__VERBOSE(&opts.verbose, N_(\"be verbose\")),\n \t\tOPT_CMDMODE(0, \"continue\", &command, N_(\"continue rebase\"),\n \t\t\t\tCONTINUE),\n \t\tOPT_CMDMODE(0, \"abort\", &command, N_(\"abort rebase\"),\n@@ -51,6 +52,8 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\n \t\tOPT_CMDMODE(0, \"edit-todo\", &command,\n \t\t\t    N_(\"edit the todo list during an interactive rebase\"),\n \t\t\t    EDIT_TODO),\n+\t\tOPT_CMDMODE(0, \"prepare-branch\", &command,\n+\t\t\t    N_(\"prepare the branch to be rebased\"), PREPARE_BRANCH),\n \t\tOPT_END()\n \t};\n \n@@ -94,5 +97,7 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\n \t\treturn !!append_todo_help(0, keep_empty);\n \tif (command == EDIT_TODO && argc == 1)\n \t\treturn !!edit_todo_list(flags);\n+\tif (command == PREPARE_BRANCH && argc == 2)\n+\t\treturn !!prepare_branch_to_be_rebased(&opts, argv[1]);\n \tusage_with_options(builtin_rebase_helper_usage, options);\n }\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex 2defe607f4..77e972bb6c 100644\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -72,6 +72,7 @@ collapse_todo_ids() {\n \n # Switch to the branch in $into and notify it in the reflog\n checkout_onto () {\n+\tcomment_for_reflog start\n \tGIT_REFLOG_ACTION=\"$GIT_REFLOG_ACTION: checkout $onto_name\"\n \toutput git checkout $onto || die_abort \"$(gettext \"could not detach HEAD\")\"\n \tgit update-ref ORIG_HEAD $orig_head\n@@ -119,19 +120,6 @@ initiate_action () {\n \tesac\n }\n \n-setup_reflog_action () {\n-\tcomment_for_reflog start\n-\n-\tif test ! -z \"$switch_to\"\n-\tthen\n-\t\tGIT_REFLOG_ACTION=\"$GIT_REFLOG_ACTION: checkout $switch_to\"\n-\t\toutput git checkout \"$switch_to\" -- ||\n-\t\t\tdie \"$(eval_gettext \"Could not checkout \\$switch_to\")\"\n-\n-\t\tcomment_for_reflog start\n-\tfi\n-}\n-\n init_basic_state () {\n \torig_head=$(git rev-parse --verify HEAD) || die \"$(gettext \"No HEAD?\")\"\n \tmkdir -p \"$state_dir\" || die \"$(eval_gettext \"Could not create temporary \\$state_dir\")\"\n@@ -211,7 +199,7 @@ git_rebase__interactive () {\n \t\treturn 0\n \tfi\n \n-\tsetup_reflog_action\n+\tgit rebase--helper --prepare-branch \"$switch_to\" ${verbose:+--verbose}\n \tinit_basic_state\n \n \tinit_revisions_and_shortrevisions\ndiff --git a/sequencer.c b/sequencer.c\nindex 5919ad312e..d8a59c50f8 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -3285,6 +3285,36 @@ 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+{\n+\tstruct child_process cmd = CHILD_PROCESS_INIT;\n+\n+\tcmd.git_cmd = 1;\n+\n+\targv_array_push(&cmd.args, \"checkout\");\n+\targv_array_push(&cmd.args, 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+\telse\n+\t\treturn run_command_silent_on_success(&cmd);\n+}\n+\n+int prepare_branch_to_be_rebased(struct replay_opts *opts, 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\t\treturn error(_(\"could not checkout %s\"), commit);\n+\t}\n+\n+\treturn 0;\n+}\n+\n static const char rescheduled_advice[] =\n N_(\"Could not execute the todo command\\n\"\n \"\\n\"\ndiff --git a/sequencer.h b/sequencer.h\nindex 579de9127b..9f0ce21be7 100644\n--- a/sequencer.h\n+++ b/sequencer.h\n@@ -121,6 +121,8 @@ int update_head_with_reflog(const struct commit *old_head,\n void commit_post_rewrite(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+\n #define SUMMARY_INITIAL_COMMIT   (1 << 0)\n #define SUMMARY_SHOW_AUTHOR_DATE (1 << 1)\n void print_commit_summary(const char *prefix, const struct object_id *oid,\n-- \n2.19.0\n\n"},{"id":"359134","messageId":"20180927215610.32210-8-alban.gruin@gmail.com","threadId":"48814","inReplyTo":"20180927215610.32210-1-alban.gruin@gmail.com","subject":"[GSoC][PATCH v8 07/20] rebase -i: rewrite checkout_onto() in C","fromName":"Alban Gruin","fromEmail":"alban.gruin@gmail.com","sentAt":"2018-09-27T21:55:57Z","receivedAt":"2018-09-27T22:00:39Z","isPatch":true,"sender":{"key":"alban.gruin@gmail.com","avatar":"https://avatars.githubusercontent.com/u/6310153?v=4"},"body":"This rewrites checkout_onto() from shell to C.\n\nA new command (“checkout-onto”) is added to rebase--helper.c. The shell\nversion is then stripped.\n\nSigned-off-by: Alban Gruin <alban.gruin@gmail.com>\n---\nNo changes since v7.\n\n builtin/rebase--helper.c   |  7 ++++++-\n git-rebase--interactive.sh | 25 ++++---------------------\n sequencer.c                | 19 +++++++++++++++++++\n sequencer.h                |  3 +++\n 4 files changed, 32 insertions(+), 22 deletions(-)\n\ndiff --git a/builtin/rebase--helper.c b/builtin/rebase--helper.c\nindex 0e76dadba6..7d9426d23c 100644\n--- a/builtin/rebase--helper.c\n+++ b/builtin/rebase--helper.c\n@@ -18,7 +18,8 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\n \tenum {\n \t\tCONTINUE = 1, ABORT, MAKE_SCRIPT, SHORTEN_OIDS, EXPAND_OIDS,\n \t\tCHECK_TODO_LIST, SKIP_UNNECESSARY_PICKS, REARRANGE_SQUASH,\n-\t\tADD_EXEC, APPEND_TODO_HELP, EDIT_TODO, PREPARE_BRANCH\n+\t\tADD_EXEC, APPEND_TODO_HELP, EDIT_TODO, PREPARE_BRANCH,\n+\t\tCHECKOUT_ONTO\n \t} command = 0;\n \tstruct option options[] = {\n \t\tOPT_BOOL(0, \"ff\", &opts.allow_ff, N_(\"allow fast-forward\")),\n@@ -54,6 +55,8 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\n \t\t\t    EDIT_TODO),\n \t\tOPT_CMDMODE(0, \"prepare-branch\", &command,\n \t\t\t    N_(\"prepare the branch to be rebased\"), PREPARE_BRANCH),\n+\t\tOPT_CMDMODE(0, \"checkout-onto\", &command,\n+\t\t\t    N_(\"checkout a commit\"), CHECKOUT_ONTO),\n \t\tOPT_END()\n \t};\n \n@@ -99,5 +102,7 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\n \t\treturn !!edit_todo_list(flags);\n \tif (command == PREPARE_BRANCH && argc == 2)\n \t\treturn !!prepare_branch_to_be_rebased(&opts, argv[1]);\n+\tif (command == CHECKOUT_ONTO && argc == 4)\n+\t\treturn !!checkout_onto(&opts, argv[1], argv[2], argv[3]);\n \tusage_with_options(builtin_rebase_helper_usage, options);\n }\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex 77e972bb6c..b68f108f28 100644\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -28,17 +28,6 @@ case \"$comment_char\" in\n \t;;\n esac\n \n-orig_reflog_action=\"$GIT_REFLOG_ACTION\"\n-\n-comment_for_reflog () {\n-\tcase \"$orig_reflog_action\" in\n-\t''|rebase*)\n-\t\tGIT_REFLOG_ACTION=\"rebase -i ($1)\"\n-\t\texport GIT_REFLOG_ACTION\n-\t\t;;\n-\tesac\n-}\n-\n die_abort () {\n \tapply_autostash\n \trm -rf \"$state_dir\"\n@@ -70,14 +59,6 @@ collapse_todo_ids() {\n \tgit rebase--helper --shorten-ids\n }\n \n-# Switch to the branch in $into and notify it in the reflog\n-checkout_onto () {\n-\tcomment_for_reflog start\n-\tGIT_REFLOG_ACTION=\"$GIT_REFLOG_ACTION: checkout $onto_name\"\n-\toutput git checkout $onto || die_abort \"$(gettext \"could not detach HEAD\")\"\n-\tgit update-ref ORIG_HEAD $orig_head\n-}\n-\n get_missing_commit_check_level () {\n \tcheck_level=$(git config --get rebase.missingCommitsCheck)\n \tcheck_level=${check_level:-ignore}\n@@ -176,7 +157,8 @@ EOF\n \n \tgit rebase--helper --check-todo-list || {\n \t\tret=$?\n-\t\tcheckout_onto\n+\t\tgit rebase--helper --checkout-onto \"$onto_name\" \"$onto\" \\\n+\t\t    \"$orig_head\" ${verbose:+--verbose}\n \t\texit $ret\n \t}\n \n@@ -186,7 +168,8 @@ EOF\n \tonto=\"$(git rebase--helper --skip-unnecessary-picks)\" ||\n \tdie \"Could not skip unnecessary pick commands\"\n \n-\tcheckout_onto\n+\tgit rebase--helper --checkout-onto \"$onto_name\" \"$onto\" \"$orig_head\" \\\n+\t    ${verbose:+--verbose}\n \trequire_clean_work_tree \"rebase\"\n \texec git rebase--helper ${force_rebase:+--no-ff} $allow_empty_message \\\n \t     --continue\ndiff --git a/sequencer.c b/sequencer.c\nindex d8a59c50f8..c7f930ab9c 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -3315,6 +3315,25 @@ int prepare_branch_to_be_rebased(struct replay_opts *opts, const char *commit)\n \treturn 0;\n }\n \n+int checkout_onto(struct replay_opts *opts,\n+\t\t  const char *onto_name, const char *onto,\n+\t\t  const char *orig_head)\n+{\n+\tstruct object_id oid;\n+\tconst char *action = reflog_message(opts, \"start\", \"checkout %s\", onto_name);\n+\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+\t\tapply_autostash(opts);\n+\t\tsequencer_remove_state(opts);\n+\t\treturn error(_(\"could not detach HEAD\"));\n+\t}\n+\n+\treturn update_ref(NULL, \"ORIG_HEAD\", &oid, NULL, 0, UPDATE_REFS_MSG_ON_ERR);\n+}\n+\n static const char rescheduled_advice[] =\n N_(\"Could not execute the todo command\\n\"\n \"\\n\"\ndiff --git a/sequencer.h b/sequencer.h\nindex 9f0ce21be7..5fa89edd3b 100644\n--- a/sequencer.h\n+++ b/sequencer.h\n@@ -122,6 +122,9 @@ void commit_post_rewrite(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 checkout_onto(struct replay_opts *opts,\n+\t\t  const char *onto_name, const char *onto,\n+\t\t  const char *orig_head);\n \n #define SUMMARY_INITIAL_COMMIT   (1 << 0)\n #define SUMMARY_SHOW_AUTHOR_DATE (1 << 1)\n-- \n2.19.0\n\n"},{"id":"359136","messageId":"20180927215610.32210-10-alban.gruin@gmail.com","threadId":"48814","inReplyTo":"20180927215610.32210-1-alban.gruin@gmail.com","subject":"[GSoC][PATCH v8 09/20] sequencer: change the way skip_unnecessary_picks() returns its result","fromName":"Alban Gruin","fromEmail":"alban.gruin@gmail.com","sentAt":"2018-09-27T21:55:59Z","receivedAt":"2018-09-27T22:00:42Z","isPatch":true,"sender":{"key":"alban.gruin@gmail.com","avatar":"https://avatars.githubusercontent.com/u/6310153?v=4"},"body":"Instead of skip_unnecessary_picks() printing its result to stdout, it\nreturns it into a struct object_id, as the rewrite of complete_action()\n(to come in the next commit) will need it.\n\nrebase--helper then is modified to fit this change.\n\nSigned-off-by: Alban Gruin <alban.gruin@gmail.com>\n---\nThe changes are due to conflict resolution, no real changes otherwise.\n\n builtin/rebase--helper.c | 10 ++++++++--\n sequencer.c              | 13 ++++++-------\n sequencer.h              |  2 +-\n 3 files changed, 15 insertions(+), 10 deletions(-)\n\ndiff --git a/builtin/rebase--helper.c b/builtin/rebase--helper.c\nindex 313092c465..bed3dd2b95 100644\n--- a/builtin/rebase--helper.c\n+++ b/builtin/rebase--helper.c\n@@ -90,8 +90,14 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\n \t\treturn !!transform_todos(flags);\n \tif (command == CHECK_TODO_LIST && argc == 1)\n \t\treturn !!check_todo_list();\n-\tif (command == SKIP_UNNECESSARY_PICKS && argc == 1)\n-\t\treturn !!skip_unnecessary_picks();\n+\tif (command == SKIP_UNNECESSARY_PICKS && argc == 1) {\n+\t\tstruct object_id oid;\n+\t\tint ret = skip_unnecessary_picks(&oid);\n+\n+\t\tif (!ret)\n+\t\t\tputs(oid_to_hex(&oid));\n+\t\treturn !!ret;\n+\t}\n \tif (command == REARRANGE_SQUASH && argc == 1)\n \t\treturn !!rearrange_squash();\n \tif (command == ADD_EXEC && argc == 2)\ndiff --git a/sequencer.c b/sequencer.c\nindex c7f930ab9c..f2cda5593d 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -4593,17 +4593,17 @@ static int rewrite_file(const char *path, const char *buf, size_t len)\n }\n \n /* skip picking commits whose parents are unchanged */\n-int skip_unnecessary_picks(void)\n+int skip_unnecessary_picks(struct object_id *output_oid)\n {\n \tconst char *todo_file = rebase_path_todo();\n \tstruct strbuf buf = STRBUF_INIT;\n \tstruct todo_list todo_list = TODO_LIST_INIT;\n-\tstruct object_id onto_oid, *oid = &onto_oid, *parent_oid;\n+\tstruct object_id *parent_oid;\n \tint fd, i;\n \n \tif (!read_oneliner(&buf, rebase_path_onto(), 0))\n \t\treturn error(_(\"could not read 'onto'\"));\n-\tif (get_oid(buf.buf, &onto_oid)) {\n+\tif (get_oid(buf.buf, output_oid)) {\n \t\tstrbuf_release(&buf);\n \t\treturn error(_(\"need a HEAD to fixup\"));\n \t}\n@@ -4633,9 +4633,9 @@ int skip_unnecessary_picks(void)\n \t\tif (item->commit->parents->next)\n \t\t\tbreak; /* merge commit */\n \t\tparent_oid = &item->commit->parents->item->object.oid;\n-\t\tif (!oideq(parent_oid, oid))\n+\t\tif (!oideq(parent_oid, output_oid))\n \t\t\tbreak;\n-\t\toid = &item->commit->object.oid;\n+\t\toidcpy(output_oid, &item->commit->object.oid);\n \t}\n \tif (i > 0) {\n \t\tint offset = get_item_line_offset(&todo_list, i);\n@@ -4664,11 +4664,10 @@ int skip_unnecessary_picks(void)\n \n \t\ttodo_list.current = i;\n \t\tif (is_fixup(peek_command(&todo_list, 0)))\n-\t\t\trecord_in_rewritten(oid, peek_command(&todo_list, 0));\n+\t\t\trecord_in_rewritten(output_oid, peek_command(&todo_list, 0));\n \t}\n \n \ttodo_list_release(&todo_list);\n-\tprintf(\"%s\\n\", oid_to_hex(oid));\n \n \treturn 0;\n }\ndiff --git a/sequencer.h b/sequencer.h\nindex 5fa89edd3b..6b0885db57 100644\n--- a/sequencer.h\n+++ b/sequencer.h\n@@ -96,7 +96,7 @@ int sequencer_add_exec_commands(const char *command);\n int transform_todos(unsigned flags);\n enum missing_commit_check_level get_missing_commit_check_level(void);\n int check_todo_list(void);\n-int skip_unnecessary_picks(void);\n+int skip_unnecessary_picks(struct object_id *output_oid);\n int rearrange_squash(void);\n \n extern const char sign_off_header[];\n-- \n2.19.0\n\n"},{"id":"359139","messageId":"20180927215610.32210-9-alban.gruin@gmail.com","threadId":"48814","inReplyTo":"20180927215610.32210-1-alban.gruin@gmail.com","subject":"[GSoC][PATCH v8 08/20] sequencer: refactor append_todo_help() to write its message to a buffer","fromName":"Alban Gruin","fromEmail":"alban.gruin@gmail.com","sentAt":"2018-09-27T21:55:58Z","receivedAt":"2018-09-27T22:00:42Z","isPatch":true,"sender":{"key":"alban.gruin@gmail.com","avatar":"https://avatars.githubusercontent.com/u/6310153?v=4"},"body":"This refactors append_todo_help() to write its message to a buffer\ninstead of the todo-list.  This is needed for the rewrite of\ncomplete_action(), which will come after the next commit.\n\nAs rebase--helper still needs the file manipulation part of\nappend_todo_help(), it is extracted to a temporary function,\nappend_todo_help_to_file().  This function will go away after the\nrewrite of complete_action().\n\nSigned-off-by: Alban Gruin <alban.gruin@gmail.com>\n---\nNo changes since v7.\n\n builtin/rebase--helper.c |  2 +-\n rebase-interactive.c     | 43 ++++++++++++++++++++++++++++------------\n rebase-interactive.h     |  4 +++-\n 3 files changed, 34 insertions(+), 15 deletions(-)\n\ndiff --git a/builtin/rebase--helper.c b/builtin/rebase--helper.c\nindex 7d9426d23c..313092c465 100644\n--- a/builtin/rebase--helper.c\n+++ b/builtin/rebase--helper.c\n@@ -97,7 +97,7 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\n \tif (command == ADD_EXEC && argc == 2)\n \t\treturn !!sequencer_add_exec_commands(argv[1]);\n \tif (command == APPEND_TODO_HELP && argc == 1)\n-\t\treturn !!append_todo_help(0, keep_empty);\n+\t\treturn !!append_todo_help_to_file(0, keep_empty);\n \tif (command == EDIT_TODO && argc == 1)\n \t\treturn !!edit_todo_list(flags);\n \tif (command == PREPARE_BRANCH && argc == 2)\ndiff --git a/rebase-interactive.c b/rebase-interactive.c\nindex 3f9468fc69..4a9a10eff4 100644\n--- a/rebase-interactive.c\n+++ b/rebase-interactive.c\n@@ -4,11 +4,9 @@\n #include \"sequencer.h\"\n #include \"strbuf.h\"\n \n-int append_todo_help(unsigned edit_todo, unsigned keep_empty)\n+void append_todo_help(unsigned edit_todo, unsigned keep_empty,\n+\t\t      struct strbuf *buf)\n {\n-\tstruct strbuf buf = STRBUF_INIT;\n-\tFILE *todo;\n-\tint ret;\n \tconst char *msg = _(\"\\nCommands:\\n\"\n \"p, pick <commit> = use commit\\n\"\n \"r, reword <commit> = use commit, but edit the commit message\\n\"\n@@ -26,11 +24,7 @@ int append_todo_help(unsigned edit_todo, unsigned keep_empty)\n \"\\n\"\n \"These lines can be re-ordered; they are executed from top to bottom.\\n\");\n \n-\ttodo = fopen_or_warn(rebase_path_todo(), \"a\");\n-\tif (!todo)\n-\t\treturn 1;\n-\n-\tstrbuf_add_commented_lines(&buf, msg, strlen(msg));\n+\tstrbuf_add_commented_lines(buf, msg, strlen(msg));\n \n \tif (get_missing_commit_check_level() == MISSING_COMMIT_CHECK_ERROR)\n \t\tmsg = _(\"\\nDo not remove any line. Use 'drop' \"\n@@ -39,7 +33,7 @@ int append_todo_help(unsigned edit_todo, unsigned keep_empty)\n \t\tmsg = _(\"\\nIf you remove a line here \"\n \t\t\t \"THAT COMMIT WILL BE LOST.\\n\");\n \n-\tstrbuf_add_commented_lines(&buf, msg, strlen(msg));\n+\tstrbuf_add_commented_lines(buf, msg, strlen(msg));\n \n \tif (edit_todo)\n \t\tmsg = _(\"\\nYou are editing the todo file \"\n@@ -50,12 +44,25 @@ int append_todo_help(unsigned edit_todo, unsigned keep_empty)\n \t\tmsg = _(\"\\nHowever, if you remove everything, \"\n \t\t\t\"the rebase will be aborted.\\n\\n\");\n \n-\tstrbuf_add_commented_lines(&buf, msg, strlen(msg));\n+\tstrbuf_add_commented_lines(buf, msg, strlen(msg));\n \n \tif (!keep_empty) {\n \t\tmsg = _(\"Note that empty commits are commented out\");\n-\t\tstrbuf_add_commented_lines(&buf, msg, strlen(msg));\n+\t\tstrbuf_add_commented_lines(buf, msg, strlen(msg));\n \t}\n+}\n+\n+int append_todo_help_to_file(unsigned edit_todo, unsigned keep_empty)\n+{\n+\tstruct strbuf buf = STRBUF_INIT;\n+\tFILE *todo;\n+\tint ret;\n+\n+\ttodo = fopen_or_warn(rebase_path_todo(), \"a\");\n+\tif (!todo)\n+\t\treturn -1;\n+\n+\tappend_todo_help(edit_todo, keep_empty, &buf);\n \n \tret = fputs(buf.buf, todo);\n \tif (ret < 0)\n@@ -84,7 +91,17 @@ int edit_todo_list(unsigned flags)\n \tstrbuf_release(&buf);\n \n \ttransform_todos(flags | TODO_LIST_SHORTEN_IDS);\n-\tappend_todo_help(1, 0);\n+\n+\tif (strbuf_read_file(&buf, todo_file, 0) < 0)\n+\t\treturn error_errno(_(\"could not read '%s'.\"), todo_file);\n+\n+\tappend_todo_help(1, 0, &buf);\n+\tif (write_message(buf.buf, buf.len, todo_file, 0)) {\n+\t\tstrbuf_release(&buf);\n+\t\treturn -1;\n+\t}\n+\n+\tstrbuf_release(&buf);\n \n \tif (launch_sequence_editor(todo_file, NULL, NULL))\n \t\treturn -1;\ndiff --git a/rebase-interactive.h b/rebase-interactive.h\nindex 155219e742..d33f3176b7 100644\n--- a/rebase-interactive.h\n+++ b/rebase-interactive.h\n@@ -1,7 +1,9 @@\n #ifndef REBASE_INTERACTIVE_H\n #define REBASE_INTERACTIVE_H\n \n-int append_todo_help(unsigned edit_todo, unsigned keep_empty);\n+void append_todo_help(unsigned edit_todo, unsigned keep_empty,\n+\t\t      struct strbuf *buf);\n+int append_todo_help_to_file(unsigned edit_todo, unsigned keep_empty);\n int edit_todo_list(unsigned flags);\n \n #endif\n-- \n2.19.0\n\n"},{"id":"359135","messageId":"20180927215610.32210-11-alban.gruin@gmail.com","threadId":"48814","inReplyTo":"20180927215610.32210-1-alban.gruin@gmail.com","subject":"[GSoC][PATCH v8 10/20] t3404: todo list with commented-out commands only aborts","fromName":"Alban Gruin","fromEmail":"alban.gruin@gmail.com","sentAt":"2018-09-27T21:56:00Z","receivedAt":"2018-09-27T22:00:44Z","isPatch":true,"sender":{"key":"alban.gruin@gmail.com","avatar":"https://avatars.githubusercontent.com/u/6310153?v=4"},"body":"If the todo list generated by `--make-script` is empty,\ncomplete_action() writes a noop, but if it has only commented-out\ncommands, it will abort with the message \"Nothing to do\", and does not\nlaunch the editor.  This adds a new test to ensure that\ncomplete_action() behaves this way.\n\nSigned-off-by: Alban Gruin <alban.gruin@gmail.com>\n---\nNo changes since v7.\n\n t/t3404-rebase-interactive.sh | 10 ++++++++++\n 1 file changed, 10 insertions(+)\n\ndiff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh\nindex ff89b6341a..a7fc3cd5be 100755\n--- a/t/t3404-rebase-interactive.sh\n+++ b/t/t3404-rebase-interactive.sh\n@@ -75,6 +75,16 @@ test_expect_success 'rebase --keep-empty' '\n \ttest_line_count = 6 actual\n '\n \n+cat > expect <<EOF\n+Nothing to do\n+EOF\n+\n+test_expect_success 'rebase -i with empty HEAD' '\n+\tset_fake_editor &&\n+\ttest_must_fail env FAKE_LINES=\"1 exec_true\" git rebase -i HEAD^ >actual 2>&1 &&\n+\ttest_i18ncmp expect actual\n+'\n+\n test_expect_success 'rebase -i with the exec command' '\n \tgit checkout master &&\n \t(\n-- \n2.19.0\n\n"},{"id":"359137","messageId":"20180927215610.32210-12-alban.gruin@gmail.com","threadId":"48814","inReplyTo":"20180927215610.32210-1-alban.gruin@gmail.com","subject":"[GSoC][PATCH v8 11/20] rebase -i: rewrite complete_action() in C","fromName":"Alban Gruin","fromEmail":"alban.gruin@gmail.com","sentAt":"2018-09-27T21:56:01Z","receivedAt":"2018-09-27T22:00:46Z","isPatch":true,"sender":{"key":"alban.gruin@gmail.com","avatar":"https://avatars.githubusercontent.com/u/6310153?v=4"},"body":"This rewrites complete_action() from shell to C.\n\nA new mode is added to rebase--helper (`--complete-action`), as well as\na new flag (`--autosquash`).\n\nFinally, complete_action() is stripped from git-rebase--interactive.sh.\n\nThe original complete_action() would return the code 2 when the todo\nlist contained no actions.  This was a special case for rebase -i and\n-p; git-rebase.sh would then apply the autostash, delete the state\ndirectory, and die with the message \"Nothing to do\".  This cleanup is\nrewritten in C instead of returning 2.  As rebase -i no longer returns\n2, the comment describing this behaviour in git-rebase.sh is updated to\nreflect this change.\n\nThe message \"Nothing to do\" is now printed with error(), and so becomes\n\"error: nothing to do\".  Some tests in t3404 check this value, so they\nare updated to fit this change.\n\nThe first check might seem useless as we write \"noop\" to the todo list\nif it is empty.  Actually, the todo list might contain commented\ncommands (ie. empty commits).  In this case, complete_action() won’t\nwrite \"noop\", and will abort without starting the editor.\n\nSigned-off-by: Alban Gruin <alban.gruin@gmail.com>\n---\nThe changes are due to conflict resolution, no real changes otherwise.\n\n builtin/rebase--helper.c      |  12 +++-\n git-rebase--interactive.sh    |  53 ++---------------\n git-rebase.sh                 |   2 +-\n sequencer.c                   | 104 ++++++++++++++++++++++++++++++++++\n sequencer.h                   |   4 ++\n t/t3404-rebase-interactive.sh |   2 +-\n 6 files changed, 124 insertions(+), 53 deletions(-)\n\ndiff --git a/builtin/rebase--helper.c b/builtin/rebase--helper.c\nindex bed3dd2b95..01b3333958 100644\n--- a/builtin/rebase--helper.c\n+++ b/builtin/rebase--helper.c\n@@ -13,13 +13,13 @@ static const char * const builtin_rebase_helper_usage[] = {\n int cmd_rebase__helper(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;\n+\tunsigned flags = 0, keep_empty = 0, rebase_merges = 0, autosquash = 0;\n \tint abbreviate_commands = 0, rebase_cousins = -1;\n \tenum {\n \t\tCONTINUE = 1, ABORT, MAKE_SCRIPT, SHORTEN_OIDS, EXPAND_OIDS,\n \t\tCHECK_TODO_LIST, SKIP_UNNECESSARY_PICKS, REARRANGE_SQUASH,\n \t\tADD_EXEC, APPEND_TODO_HELP, EDIT_TODO, PREPARE_BRANCH,\n-\t\tCHECKOUT_ONTO\n+\t\tCHECKOUT_ONTO, COMPLETE_ACTION\n \t} command = 0;\n \tstruct option options[] = {\n \t\tOPT_BOOL(0, \"ff\", &opts.allow_ff, N_(\"allow fast-forward\")),\n@@ -29,6 +29,8 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\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__VERBOSE(&opts.verbose, N_(\"be verbose\")),\n \t\tOPT_CMDMODE(0, \"continue\", &command, N_(\"continue rebase\"),\n \t\t\t\tCONTINUE),\n@@ -57,6 +59,8 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\n \t\t\t    N_(\"prepare the branch to be rebased\"), PREPARE_BRANCH),\n \t\tOPT_CMDMODE(0, \"checkout-onto\", &command,\n \t\t\t    N_(\"checkout a commit\"), CHECKOUT_ONTO),\n+\t\tOPT_CMDMODE(0, \"complete-action\", &command,\n+\t\t\t    N_(\"complete the action\"), COMPLETE_ACTION),\n \t\tOPT_END()\n \t};\n \n@@ -110,5 +114,9 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\n \t\treturn !!prepare_branch_to_be_rebased(&opts, argv[1]);\n \tif (command == CHECKOUT_ONTO && argc == 4)\n \t\treturn !!checkout_onto(&opts, argv[1], argv[2], argv[3]);\n+\tif (command == COMPLETE_ACTION && argc == 6)\n+\t\treturn !!complete_action(&opts, flags, argv[1], argv[2], argv[3],\n+\t\t\t\t\t argv[4], argv[5], autosquash);\n+\n \tusage_with_options(builtin_rebase_helper_usage, options);\n }\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex b68f108f28..59dc4888a6 100644\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -127,54 +127,6 @@ init_revisions_and_shortrevisions () {\n \tfi\n }\n \n-complete_action() {\n-\ttest -s \"$todo\" || echo noop >> \"$todo\"\n-\ttest -z \"$autosquash\" || git rebase--helper --rearrange-squash || exit\n-\ttest -n \"$cmd\" && git rebase--helper --add-exec-commands \"$cmd\"\n-\n-\ttodocount=$(git stripspace --strip-comments <\"$todo\" | wc -l)\n-\ttodocount=${todocount##* }\n-\n-cat >>\"$todo\" <<EOF\n-\n-$comment_char $(eval_ngettext \\\n-\t\"Rebase \\$shortrevisions onto \\$shortonto (\\$todocount command)\" \\\n-\t\"Rebase \\$shortrevisions onto \\$shortonto (\\$todocount commands)\" \\\n-\t\"$todocount\")\n-EOF\n-\tgit rebase--helper --append-todo-help ${keep_empty:+--keep-empty}\n-\n-\thas_action \"$todo\" ||\n-\t\treturn 2\n-\n-\tcp \"$todo\" \"$todo\".backup\n-\tcollapse_todo_ids\n-\tgit_sequence_editor \"$todo\" ||\n-\t\tdie_abort \"$(gettext \"Could not execute editor\")\"\n-\n-\thas_action \"$todo\" ||\n-\t\treturn 2\n-\n-\tgit rebase--helper --check-todo-list || {\n-\t\tret=$?\n-\t\tgit rebase--helper --checkout-onto \"$onto_name\" \"$onto\" \\\n-\t\t    \"$orig_head\" ${verbose:+--verbose}\n-\t\texit $ret\n-\t}\n-\n-\texpand_todo_ids\n-\n-\ttest -n \"$force_rebase\" ||\n-\tonto=\"$(git rebase--helper --skip-unnecessary-picks)\" ||\n-\tdie \"Could not skip unnecessary pick commands\"\n-\n-\tgit rebase--helper --checkout-onto \"$onto_name\" \"$onto\" \"$orig_head\" \\\n-\t    ${verbose:+--verbose}\n-\trequire_clean_work_tree \"rebase\"\n-\texec git rebase--helper ${force_rebase:+--no-ff} $allow_empty_message \\\n-\t     --continue\n-}\n-\n git_rebase__interactive () {\n \tinitiate_action \"$action\"\n \tret=$?\n@@ -193,5 +145,8 @@ git_rebase__interactive () {\n \t\t$revisions ${restrict_revision+^$restrict_revision} >\"$todo\" ||\n \tdie \"$(gettext \"Could not generate todo list\")\"\n \n-\tcomplete_action\n+\texec git rebase--helper --complete-action \"$shortrevisions\" \"$onto_name\" \\\n+\t\t\"$shortonto\" \"$orig_head\" \"$cmd\" $allow_empty_message \\\n+\t\t${autosquash:+--autosquash} ${keep_empty:+--keep-empty} \\\n+\t\t${verbose:+--verbose} ${force_rebase:+--no-ff}\n }\ndiff --git a/git-rebase.sh b/git-rebase.sh\nindex 7973447645..51a6db7daa 100755\n--- a/git-rebase.sh\n+++ b/git-rebase.sh\n@@ -219,7 +219,7 @@ run_specific_rebase () {\n \tif test $ret -eq 0\n \tthen\n \t\tfinish_rebase\n-\telif test $ret -eq 2 # special exit status for rebase -i\n+\telif test $ret -eq 2 # special exit status for rebase -p\n \tthen\n \t\tapply_autostash &&\n \t\trm -rf \"$state_dir\" &&\ndiff --git a/sequencer.c b/sequencer.c\nindex f2cda5593d..0104c0ad01 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -31,6 +31,7 @@\n #include \"commit-slab.h\"\n #include \"alias.h\"\n #include \"commit-reach.h\"\n+#include \"rebase-interactive.h\"\n \n #define GIT_REFLOG_ACTION \"GIT_REFLOG_ACTION\"\n \n@@ -54,6 +55,9 @@ static GIT_PATH_FUNC(rebase_path, \"rebase-merge\")\n  * file and written to the tail of 'done'.\n  */\n GIT_PATH_FUNC(rebase_path_todo, \"rebase-merge/git-rebase-todo\")\n+static GIT_PATH_FUNC(rebase_path_todo_backup,\n+\t\t     \"rebase-merge/git-rebase-todo.backup\")\n+\n /*\n  * The rebase command lines that have already been processed. A line\n  * is moved here when it is first handled, before any associated user\n@@ -4672,6 +4676,106 @@ int skip_unnecessary_picks(struct object_id *output_oid)\n \treturn 0;\n }\n \n+int complete_action(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, const char *cmd,\n+\t\t    unsigned autosquash)\n+{\n+\tconst char *shortonto, *todo_file = rebase_path_todo();\n+\tstruct todo_list todo_list = TODO_LIST_INIT;\n+\tstruct strbuf *buf = &(todo_list.buf);\n+\tstruct object_id oid;\n+\tstruct stat st;\n+\n+\tget_oid(onto, &oid);\n+\tshortonto = find_unique_abbrev(&oid, DEFAULT_ABBREV);\n+\n+\tif (!lstat(todo_file, &st) && st.st_size == 0 &&\n+\t    write_message(\"noop\\n\", 5, todo_file, 0))\n+\t\treturn -1;\n+\n+\tif (autosquash && rearrange_squash())\n+\t\treturn -1;\n+\n+\tif (cmd && *cmd)\n+\t\tsequencer_add_exec_commands(cmd);\n+\n+\tif (strbuf_read_file(buf, todo_file, 0) < 0)\n+\t\treturn error_errno(_(\"could not read '%s'.\"), todo_file);\n+\n+\tif (parse_insn_buffer(buf->buf, &todo_list)) {\n+\t\ttodo_list_release(&todo_list);\n+\t\treturn error(_(\"unusable todo list: '%s'\"), todo_file);\n+\t}\n+\n+\tif (count_commands(&todo_list) == 0) {\n+\t\tapply_autostash(opts);\n+\t\tsequencer_remove_state(opts);\n+\t\ttodo_list_release(&todo_list);\n+\n+\t\treturn error(_(\"nothing to do\"));\n+\t}\n+\n+\tstrbuf_addch(buf, '\\n');\n+\tstrbuf_commented_addf(buf, Q_(\"Rebase %s onto %s (%d command)\",\n+\t\t\t\t      \"Rebase %s onto %s (%d commands)\",\n+\t\t\t\t      count_commands(&todo_list)),\n+\t\t\t      shortrevisions, shortonto, count_commands(&todo_list));\n+\tappend_todo_help(0, flags & TODO_LIST_KEEP_EMPTY, buf);\n+\n+\tif (write_message(buf->buf, buf->len, todo_file, 0)) {\n+\t\ttodo_list_release(&todo_list);\n+\t\treturn -1;\n+\t}\n+\n+\tif (copy_file(rebase_path_todo_backup(), todo_file, 0666))\n+\t\treturn error(_(\"could not copy '%s' to '%s'.\"), todo_file,\n+\t\t\t     rebase_path_todo_backup());\n+\n+\tif (transform_todos(flags | TODO_LIST_SHORTEN_IDS))\n+\t\treturn error(_(\"could not transform the todo list\"));\n+\n+\tstrbuf_reset(buf);\n+\n+\tif (launch_sequence_editor(todo_file, buf, NULL)) {\n+\t\tapply_autostash(opts);\n+\t\tsequencer_remove_state(opts);\n+\t\ttodo_list_release(&todo_list);\n+\n+\t\treturn -1;\n+\t}\n+\n+\tstrbuf_stripspace(buf, 1);\n+\tif (buf->len == 0) {\n+\t\tapply_autostash(opts);\n+\t\tsequencer_remove_state(opts);\n+\t\ttodo_list_release(&todo_list);\n+\n+\t\treturn error(_(\"nothing to do\"));\n+\t}\n+\n+\ttodo_list_release(&todo_list);\n+\n+\tif (check_todo_list()) {\n+\t\tcheckout_onto(opts, onto_name, onto, orig_head);\n+\t\treturn -1;\n+\t}\n+\n+\tif (transform_todos(flags & ~(TODO_LIST_SHORTEN_IDS)))\n+\t\treturn error(_(\"could not transform the todo list\"));\n+\n+\tif (opts->allow_ff && skip_unnecessary_picks(&oid))\n+\t\treturn error(_(\"could not skip unnecessary pick commands\"));\n+\n+\tif (checkout_onto(opts, onto_name, oid_to_hex(&oid), orig_head))\n+\t\treturn -1;\n+;\n+\tif (require_clean_work_tree(\"rebase\", \"\", 1, 1))\n+\t\treturn -1;\n+\n+\treturn sequencer_continue(opts);\n+}\n+\n struct subject2item_entry {\n \tstruct hashmap_entry entry;\n \tint i;\ndiff --git a/sequencer.h b/sequencer.h\nindex 6b0885db57..d51fe2c576 100644\n--- a/sequencer.h\n+++ b/sequencer.h\n@@ -97,6 +97,10 @@ int transform_todos(unsigned flags);\n enum missing_commit_check_level get_missing_commit_check_level(void);\n int check_todo_list(void);\n int skip_unnecessary_picks(struct object_id *output_oid);\n+int complete_action(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, const char *cmd,\n+\t\t    unsigned autosquash);\n int rearrange_squash(void);\n \n extern const char sign_off_header[];\ndiff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh\nindex a7fc3cd5be..d60e59ecdb 100755\n--- a/t/t3404-rebase-interactive.sh\n+++ b/t/t3404-rebase-interactive.sh\n@@ -76,7 +76,7 @@ test_expect_success 'rebase --keep-empty' '\n '\n \n cat > expect <<EOF\n-Nothing to do\n+error: nothing to do\n EOF\n \n test_expect_success 'rebase -i with empty HEAD' '\n-- \n2.19.0\n\n"},{"id":"359138","messageId":"20180927215610.32210-13-alban.gruin@gmail.com","threadId":"48814","inReplyTo":"20180927215610.32210-1-alban.gruin@gmail.com","subject":"[GSoC][PATCH v8 12/20] rebase -i: remove unused modes and functions","fromName":"Alban Gruin","fromEmail":"alban.gruin@gmail.com","sentAt":"2018-09-27T21:56:02Z","receivedAt":"2018-09-27T22:00:47Z","isPatch":true,"sender":{"key":"alban.gruin@gmail.com","avatar":"https://avatars.githubusercontent.com/u/6310153?v=4"},"body":"This removes the modes `--skip-unnecessary-picks`, `--append-todo-help`,\nand `--checkout-onto` from rebase--helper.c, the functions of\ngit-rebase--interactive.sh that were rendered useless by the rewrite of\ncomplete_action(), and append_todo_help_to_file() from\nrebase-interactive.c.\n\nskip_unnecessary_picks() and checkout_onto() becomes static, as they are\nonly used inside of the sequencer.\n\nSigned-off-by: Alban Gruin <alban.gruin@gmail.com>\n---\nNo changes since v7.\n\n builtin/rebase--helper.c   | 23 ++----------------\n git-rebase--interactive.sh | 50 --------------------------------------\n rebase-interactive.c       | 22 -----------------\n rebase-interactive.h       |  1 -\n sequencer.c                |  8 +++---\n sequencer.h                |  4 ---\n 6 files changed, 6 insertions(+), 102 deletions(-)\n\ndiff --git a/builtin/rebase--helper.c b/builtin/rebase--helper.c\nindex 01b3333958..e1460136f5 100644\n--- a/builtin/rebase--helper.c\n+++ b/builtin/rebase--helper.c\n@@ -17,9 +17,8 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\n \tint abbreviate_commands = 0, rebase_cousins = -1;\n \tenum {\n \t\tCONTINUE = 1, ABORT, MAKE_SCRIPT, SHORTEN_OIDS, EXPAND_OIDS,\n-\t\tCHECK_TODO_LIST, SKIP_UNNECESSARY_PICKS, REARRANGE_SQUASH,\n-\t\tADD_EXEC, APPEND_TODO_HELP, EDIT_TODO, PREPARE_BRANCH,\n-\t\tCHECKOUT_ONTO, COMPLETE_ACTION\n+\t\tCHECK_TODO_LIST, REARRANGE_SQUASH, ADD_EXEC, EDIT_TODO, PREPARE_BRANCH,\n+\t\tCOMPLETE_ACTION\n \t} command = 0;\n \tstruct option options[] = {\n \t\tOPT_BOOL(0, \"ff\", &opts.allow_ff, N_(\"allow fast-forward\")),\n@@ -44,21 +43,15 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\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, \"skip-unnecessary-picks\", &command,\n-\t\t\tN_(\"skip unnecessary picks\"), SKIP_UNNECESSARY_PICKS),\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_CMDMODE(0, \"append-todo-help\", &command,\n-\t\t\t    N_(\"insert the help in the todo list\"), APPEND_TODO_HELP),\n \t\tOPT_CMDMODE(0, \"edit-todo\", &command,\n \t\t\t    N_(\"edit the todo list during an interactive rebase\"),\n \t\t\t    EDIT_TODO),\n \t\tOPT_CMDMODE(0, \"prepare-branch\", &command,\n \t\t\t    N_(\"prepare the branch to be rebased\"), PREPARE_BRANCH),\n-\t\tOPT_CMDMODE(0, \"checkout-onto\", &command,\n-\t\t\t    N_(\"checkout a commit\"), CHECKOUT_ONTO),\n \t\tOPT_CMDMODE(0, \"complete-action\", &command,\n \t\t\t    N_(\"complete the action\"), COMPLETE_ACTION),\n \t\tOPT_END()\n@@ -94,26 +87,14 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\n \t\treturn !!transform_todos(flags);\n \tif (command == CHECK_TODO_LIST && argc == 1)\n \t\treturn !!check_todo_list();\n-\tif (command == SKIP_UNNECESSARY_PICKS && argc == 1) {\n-\t\tstruct object_id oid;\n-\t\tint ret = skip_unnecessary_picks(&oid);\n-\n-\t\tif (!ret)\n-\t\t\tputs(oid_to_hex(&oid));\n-\t\treturn !!ret;\n-\t}\n \tif (command == REARRANGE_SQUASH && argc == 1)\n \t\treturn !!rearrange_squash();\n \tif (command == ADD_EXEC && argc == 2)\n \t\treturn !!sequencer_add_exec_commands(argv[1]);\n-\tif (command == APPEND_TODO_HELP && argc == 1)\n-\t\treturn !!append_todo_help_to_file(0, keep_empty);\n \tif (command == EDIT_TODO && argc == 1)\n \t\treturn !!edit_todo_list(flags);\n \tif (command == PREPARE_BRANCH && argc == 2)\n \t\treturn !!prepare_branch_to_be_rebased(&opts, argv[1]);\n-\tif (command == CHECKOUT_ONTO && argc == 4)\n-\t\treturn !!checkout_onto(&opts, argv[1], argv[2], argv[3]);\n \tif (command == COMPLETE_ACTION && argc == 6)\n \t\treturn !!complete_action(&opts, flags, argv[1], argv[2], argv[3],\n \t\t\t\t\t argv[4], argv[5], autosquash);\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex 59dc4888a6..0d66c0f8b8 100644\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -16,56 +16,6 @@ todo=\"$state_dir\"/git-rebase-todo\n GIT_CHERRY_PICK_HELP=\"$resolvemsg\"\n export GIT_CHERRY_PICK_HELP\n \n-comment_char=$(git config --get core.commentchar 2>/dev/null)\n-case \"$comment_char\" in\n-'' | auto)\n-\tcomment_char=\"#\"\n-\t;;\n-?)\n-\t;;\n-*)\n-\tcomment_char=$(echo \"$comment_char\" | cut -c1)\n-\t;;\n-esac\n-\n-die_abort () {\n-\tapply_autostash\n-\trm -rf \"$state_dir\"\n-\tdie \"$1\"\n-}\n-\n-has_action () {\n-\ttest -n \"$(git stripspace --strip-comments <\"$1\")\"\n-}\n-\n-git_sequence_editor () {\n-\tif test -z \"$GIT_SEQUENCE_EDITOR\"\n-\tthen\n-\t\tGIT_SEQUENCE_EDITOR=\"$(git config sequence.editor)\"\n-\t\tif [ -z \"$GIT_SEQUENCE_EDITOR\" ]\n-\t\tthen\n-\t\t\tGIT_SEQUENCE_EDITOR=\"$(git var GIT_EDITOR)\" || return $?\n-\t\tfi\n-\tfi\n-\n-\teval \"$GIT_SEQUENCE_EDITOR\" '\"$@\"'\n-}\n-\n-expand_todo_ids() {\n-\tgit rebase--helper --expand-ids\n-}\n-\n-collapse_todo_ids() {\n-\tgit rebase--helper --shorten-ids\n-}\n-\n-get_missing_commit_check_level () {\n-\tcheck_level=$(git config --get rebase.missingCommitsCheck)\n-\tcheck_level=${check_level:-ignore}\n-\t# Don't be case sensitive\n-\tprintf '%s' \"$check_level\" | tr 'A-Z' 'a-z'\n-}\n-\n # Initiate an action. If the cannot be any\n # further action it  may exec a command\n # or exit and not return.\ndiff --git a/rebase-interactive.c b/rebase-interactive.c\nindex 4a9a10eff4..0f4119cbae 100644\n--- a/rebase-interactive.c\n+++ b/rebase-interactive.c\n@@ -52,28 +52,6 @@ void append_todo_help(unsigned edit_todo, unsigned keep_empty,\n \t}\n }\n \n-int append_todo_help_to_file(unsigned edit_todo, unsigned keep_empty)\n-{\n-\tstruct strbuf buf = STRBUF_INIT;\n-\tFILE *todo;\n-\tint ret;\n-\n-\ttodo = fopen_or_warn(rebase_path_todo(), \"a\");\n-\tif (!todo)\n-\t\treturn -1;\n-\n-\tappend_todo_help(edit_todo, keep_empty, &buf);\n-\n-\tret = fputs(buf.buf, todo);\n-\tif (ret < 0)\n-\t\terror_errno(_(\"could not append help text to '%s'\"), rebase_path_todo());\n-\n-\tfclose(todo);\n-\tstrbuf_release(&buf);\n-\n-\treturn ret;\n-}\n-\n int edit_todo_list(unsigned flags)\n {\n \tstruct strbuf buf = STRBUF_INIT;\ndiff --git a/rebase-interactive.h b/rebase-interactive.h\nindex d33f3176b7..971da03776 100644\n--- a/rebase-interactive.h\n+++ b/rebase-interactive.h\n@@ -3,7 +3,6 @@\n \n void append_todo_help(unsigned edit_todo, unsigned keep_empty,\n \t\t      struct strbuf *buf);\n-int append_todo_help_to_file(unsigned edit_todo, unsigned keep_empty);\n int edit_todo_list(unsigned flags);\n \n #endif\ndiff --git a/sequencer.c b/sequencer.c\nindex 0104c0ad01..e3de1fbb2d 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -3319,9 +3319,9 @@ int prepare_branch_to_be_rebased(struct replay_opts *opts, const char *commit)\n \treturn 0;\n }\n \n-int checkout_onto(struct replay_opts *opts,\n-\t\t  const char *onto_name, const char *onto,\n-\t\t  const char *orig_head)\n+static int checkout_onto(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 \tstruct object_id oid;\n \tconst char *action = reflog_message(opts, \"start\", \"checkout %s\", onto_name);\n@@ -4597,7 +4597,7 @@ static int rewrite_file(const char *path, const char *buf, size_t len)\n }\n \n /* skip picking commits whose parents are unchanged */\n-int skip_unnecessary_picks(struct object_id *output_oid)\n+static int skip_unnecessary_picks(struct object_id *output_oid)\n {\n \tconst char *todo_file = rebase_path_todo();\n \tstruct strbuf buf = STRBUF_INIT;\ndiff --git a/sequencer.h b/sequencer.h\nindex d51fe2c576..30bd9c12ac 100644\n--- a/sequencer.h\n+++ b/sequencer.h\n@@ -96,7 +96,6 @@ int sequencer_add_exec_commands(const char *command);\n int transform_todos(unsigned flags);\n enum missing_commit_check_level get_missing_commit_check_level(void);\n int check_todo_list(void);\n-int skip_unnecessary_picks(struct object_id *output_oid);\n int complete_action(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, const char *cmd,\n@@ -126,9 +125,6 @@ void commit_post_rewrite(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 checkout_onto(struct replay_opts *opts,\n-\t\t  const char *onto_name, const char *onto,\n-\t\t  const char *orig_head);\n \n #define SUMMARY_INITIAL_COMMIT   (1 << 0)\n #define SUMMARY_SHOW_AUTHOR_DATE (1 << 1)\n-- \n2.19.0\n\n"},{"id":"359140","messageId":"20180927215610.32210-14-alban.gruin@gmail.com","threadId":"48814","inReplyTo":"20180927215610.32210-1-alban.gruin@gmail.com","subject":"[GSoC][PATCH v8 13/20] rebase -i: implement the logic to initialize $revisions in C","fromName":"Alban Gruin","fromEmail":"alban.gruin@gmail.com","sentAt":"2018-09-27T21:56:03Z","receivedAt":"2018-09-27T22:00:49Z","isPatch":true,"sender":{"key":"alban.gruin@gmail.com","avatar":"https://avatars.githubusercontent.com/u/6310153?v=4"},"body":"This rewrites the part of init_revisions_and_shortrevisions() needed by\n`--make-script` from shell to C.  The new version is called\nget_revision_ranges(), and is a static function inside of\nrebase--helper.c.  As this does not initialize $shortrevision, the\noriginal shell version is not yet stripped.\n\nUnlike init_revisions_and_shortrevisions(), get_revision_ranges()\ndoesn’t write $squash_onto to the state directory, it’s done by the\nhandler of `--make-script` instead.\n\nFinally, this drops the $revision argument passed to `--make-script` in\ngit-rebase--interactive.sh, and rebase--helper is changed accordingly.\n\nSigned-off-by: Alban Gruin <alban.gruin@gmail.com>\n---\nNo changes since v7.\n\n builtin/rebase--helper.c   | 56 ++++++++++++++++++++++++++++++++++++--\n git-rebase--interactive.sh |  4 ++-\n 2 files changed, 56 insertions(+), 4 deletions(-)\n\ndiff --git a/builtin/rebase--helper.c b/builtin/rebase--helper.c\nindex e1460136f5..acc71a6f99 100644\n--- a/builtin/rebase--helper.c\n+++ b/builtin/rebase--helper.c\n@@ -4,6 +4,25 @@\n #include \"parse-options.h\"\n #include \"sequencer.h\"\n #include \"rebase-interactive.h\"\n+#include \"argv-array.h\"\n+\n+static GIT_PATH_FUNC(path_squash_onto, \"rebase-merge/squash-onto\")\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)\n+{\n+\tconst char *base_rev = upstream ? upstream : onto;\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+\treturn 0;\n+}\n \n static const char * const builtin_rebase_helper_usage[] = {\n \tN_(\"git rebase--helper [<options>]\"),\n@@ -14,7 +33,9 @@ int cmd_rebase__helper(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;\n+\tint abbreviate_commands = 0, rebase_cousins = -1, ret;\n+\tconst char *head_hash = NULL, *onto = NULL, *restrict_revision = NULL,\n+\t\t*squash_onto = NULL, *upstream = NULL;\n \tenum {\n \t\tCONTINUE = 1, ABORT, MAKE_SCRIPT, SHORTEN_OIDS, EXPAND_OIDS,\n \t\tCHECK_TODO_LIST, REARRANGE_SQUASH, ADD_EXEC, EDIT_TODO, PREPARE_BRANCH,\n@@ -54,6 +75,13 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\n \t\t\t    N_(\"prepare the branch to be rebased\"), PREPARE_BRANCH),\n \t\tOPT_CMDMODE(0, \"complete-action\", &command,\n \t\t\t    N_(\"complete the action\"), COMPLETE_ACTION),\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_END()\n \t};\n \n@@ -81,8 +109,30 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\n \t\treturn !!sequencer_continue(&opts);\n \tif (command == ABORT && argc == 1)\n \t\treturn !!sequencer_remove_state(&opts);\n-\tif (command == MAKE_SCRIPT && argc > 1)\n-\t\treturn !!sequencer_make_script(stdout, argc, argv, flags);\n+\tif (command == MAKE_SCRIPT && argc == 1) {\n+\t\tchar *revisions = NULL;\n+\t\tstruct argv_array make_script_args = ARGV_ARRAY_INIT;\n+\n+\t\tif (!upstream && squash_onto)\n+\t\t\twrite_file(path_squash_onto(), \"%s\\n\", squash_onto);\n+\n+\t\tret = get_revision_ranges(upstream, onto, &head_hash, &revisions);\n+\t\tif (ret)\n+\t\t\treturn ret;\n+\n+\t\targv_array_pushl(&make_script_args, \"\", revisions, NULL);\n+\t\tif (restrict_revision)\n+\t\t\targv_array_push(&make_script_args, restrict_revision);\n+\n+\t\tret = sequencer_make_script(stdout,\n+\t\t\t\t\t    make_script_args.argc, make_script_args.argv,\n+\t\t\t\t\t    flags);\n+\n+\t\tfree(revisions);\n+\t\targv_array_clear(&make_script_args);\n+\n+\t\treturn !!ret;\n+\t}\n \tif ((command == SHORTEN_OIDS || command == EXPAND_OIDS) && argc == 1)\n \t\treturn !!transform_todos(flags);\n \tif (command == CHECK_TODO_LIST && argc == 1)\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex 0d66c0f8b8..4ca47aed1e 100644\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -92,7 +92,9 @@ git_rebase__interactive () {\n \tgit rebase--helper --make-script ${keep_empty:+--keep-empty} \\\n \t\t${rebase_merges:+--rebase-merges} \\\n \t\t${rebase_cousins:+--rebase-cousins} \\\n-\t\t$revisions ${restrict_revision+^$restrict_revision} >\"$todo\" ||\n+\t\t${upstream:+--upstream \"$upstream\"} ${onto:+--onto \"$onto\"} \\\n+\t\t${squash_onto:+--squash-onto \"$squash_onto\"} \\\n+\t\t${restrict_revision:+--restrict-revision ^\"$restrict_revision\"} >\"$todo\" ||\n \tdie \"$(gettext \"Could not generate todo list\")\"\n \n \texec git rebase--helper --complete-action \"$shortrevisions\" \"$onto_name\" \\\n-- \n2.19.0\n\n"},{"id":"359141","messageId":"20180927215610.32210-15-alban.gruin@gmail.com","threadId":"48814","inReplyTo":"20180927215610.32210-1-alban.gruin@gmail.com","subject":"[GSoC][PATCH v8 14/20] rebase -i: rewrite the rest of init_revisions_and_shortrevisions() in C","fromName":"Alban Gruin","fromEmail":"alban.gruin@gmail.com","sentAt":"2018-09-27T21:56:04Z","receivedAt":"2018-09-27T22:00:50Z","isPatch":true,"sender":{"key":"alban.gruin@gmail.com","avatar":"https://avatars.githubusercontent.com/u/6310153?v=4"},"body":"This rewrites the part of init_revisions_and_shortrevisions() needed by\n`--complete-action` (which initialize $shortrevisions) from shell to C.\n\nWhen `upstream` is empty, it means that the user launched a `rebase\n--root`, and `onto` contains the ID of an empty commit.  As a range\nbetween an empty commit and `head` is not really meaningful, `onto` is\nnot used to initialize `shortrevisions` in this case.\n\nThe corresponding arguments passed to `--complete-action` are then\ndropped, and init_revisions_and_shortrevisions() is stripped from\ngit-rebase--interactive.sh\n\nSigned-off-by: Alban Gruin <alban.gruin@gmail.com>\n---\nNo changes since v7.\n\n builtin/rebase--helper.c   | 40 ++++++++++++++++++++++++++++++++------\n git-rebase--interactive.sh | 27 ++++---------------------\n 2 files changed, 38 insertions(+), 29 deletions(-)\n\ndiff --git a/builtin/rebase--helper.c b/builtin/rebase--helper.c\nindex acc71a6f99..0716bbfd78 100644\n--- a/builtin/rebase--helper.c\n+++ b/builtin/rebase--helper.c\n@@ -10,7 +10,7 @@ static GIT_PATH_FUNC(path_squash_onto, \"rebase-merge/squash-onto\")\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)\n+\t\t\t       char **revisions, char **shortrevisions)\n {\n \tconst char *base_rev = upstream ? upstream : onto;\n \tstruct object_id orig_head;\n@@ -19,7 +19,25 @@ static int get_revision_ranges(const char *upstream, const char *onto,\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+\tif (revisions)\n+\t\t*revisions = xstrfmt(\"%s...%s\", base_rev, *head_hash);\n+\tif (shortrevisions) {\n+\t\tconst char *shorthead;\n+\n+\t\tshorthead = find_unique_abbrev(&orig_head, DEFAULT_ABBREV);\n+\n+\t\tif (upstream) {\n+\t\t\tconst char *shortrev;\n+\t\t\tstruct object_id rev_oid;\n+\n+\t\t\tget_oid(base_rev, &rev_oid);\n+\t\t\tshortrev = find_unique_abbrev(&rev_oid, DEFAULT_ABBREV);\n+\n+\t\t\t*shortrevisions = xstrfmt(\"%s..%s\", shortrev, shorthead);\n+\t\t} else\n+\t\t\t*shortrevisions = xstrdup(shorthead);\n+\t}\n \n \treturn 0;\n }\n@@ -116,7 +134,7 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\n \t\tif (!upstream && squash_onto)\n \t\t\twrite_file(path_squash_onto(), \"%s\\n\", squash_onto);\n \n-\t\tret = get_revision_ranges(upstream, onto, &head_hash, &revisions);\n+\t\tret = get_revision_ranges(upstream, onto, &head_hash, &revisions, NULL);\n \t\tif (ret)\n \t\t\treturn ret;\n \n@@ -145,9 +163,19 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\n \t\treturn !!edit_todo_list(flags);\n \tif (command == PREPARE_BRANCH && argc == 2)\n \t\treturn !!prepare_branch_to_be_rebased(&opts, argv[1]);\n-\tif (command == COMPLETE_ACTION && argc == 6)\n-\t\treturn !!complete_action(&opts, flags, argv[1], argv[2], argv[3],\n-\t\t\t\t\t argv[4], argv[5], autosquash);\n+\tif (command == COMPLETE_ACTION && argc == 3) {\n+\t\tchar *shortrevisions = NULL;\n+\n+\t\tret = get_revision_ranges(upstream, onto, &head_hash, NULL, &shortrevisions);\n+\t\tif (ret)\n+\t\t\treturn ret;\n+\n+\t\tret = complete_action(&opts, flags, shortrevisions, argv[1], onto,\n+\t\t\t\t      head_hash, argv[2], autosquash);\n+\n+\t\tfree(shortrevisions);\n+\t\treturn !!ret;\n+\t}\n \n \tusage_with_options(builtin_rebase_helper_usage, options);\n }\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex 4ca47aed1e..08e9a21c2f 100644\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -60,23 +60,6 @@ init_basic_state () {\n \twrite_basic_state\n }\n \n-init_revisions_and_shortrevisions () {\n-\tshorthead=$(git rev-parse --short $orig_head)\n-\tshortonto=$(git rev-parse --short $onto)\n-\tif test -z \"$rebase_root\"\n-\t\t# this is now equivalent to ! -z \"$upstream\"\n-\tthen\n-\t\tshortupstream=$(git rev-parse --short $upstream)\n-\t\trevisions=$upstream...$orig_head\n-\t\tshortrevisions=$shortupstream..$shorthead\n-\telse\n-\t\trevisions=$onto...$orig_head\n-\t\tshortrevisions=$shorthead\n-\t\ttest -z \"$squash_onto\" ||\n-\t\techo \"$squash_onto\" >\"$state_dir\"/squash-onto\n-\tfi\n-}\n-\n git_rebase__interactive () {\n \tinitiate_action \"$action\"\n \tret=$?\n@@ -87,8 +70,6 @@ git_rebase__interactive () {\n \tgit rebase--helper --prepare-branch \"$switch_to\" ${verbose:+--verbose}\n \tinit_basic_state\n \n-\tinit_revisions_and_shortrevisions\n-\n \tgit rebase--helper --make-script ${keep_empty:+--keep-empty} \\\n \t\t${rebase_merges:+--rebase-merges} \\\n \t\t${rebase_cousins:+--rebase-cousins} \\\n@@ -97,8 +78,8 @@ git_rebase__interactive () {\n \t\t${restrict_revision:+--restrict-revision ^\"$restrict_revision\"} >\"$todo\" ||\n \tdie \"$(gettext \"Could not generate todo list\")\"\n \n-\texec git rebase--helper --complete-action \"$shortrevisions\" \"$onto_name\" \\\n-\t\t\"$shortonto\" \"$orig_head\" \"$cmd\" $allow_empty_message \\\n-\t\t${autosquash:+--autosquash} ${keep_empty:+--keep-empty} \\\n-\t\t${verbose:+--verbose} ${force_rebase:+--no-ff}\n+\texec git rebase--helper --complete-action \"$onto_name\" \"$cmd\" \\\n+\t\t$allow_empty_message ${autosquash:+--autosquash} ${verbose:+--verbose} \\\n+\t\t${keep_empty:+--keep-empty} ${force_rebase:+--no-ff} \\\n+\t\t${upstream:+--upstream \"$upstream\"} ${onto:+--onto \"$onto\"}\n }\n-- \n2.19.0\n\n"},{"id":"359142","messageId":"20180927215610.32210-17-alban.gruin@gmail.com","threadId":"48814","inReplyTo":"20180927215610.32210-1-alban.gruin@gmail.com","subject":"[GSoC][PATCH v8 16/20] rebase -i: rewrite init_basic_state() in C","fromName":"Alban Gruin","fromEmail":"alban.gruin@gmail.com","sentAt":"2018-09-27T21:56:06Z","receivedAt":"2018-09-27T22:00:52Z","isPatch":true,"sender":{"key":"alban.gruin@gmail.com","avatar":"https://avatars.githubusercontent.com/u/6310153?v=4"},"body":"This rewrites init_basic_state() from shell to C.  The call to\nwrite_basic_state() in cmd_rebase__helper() is replaced by a call to the\nnew function.\n\nThe shell version is then stripped from git-rebase--interactive.sh.\n\nSigned-off-by: Alban Gruin <alban.gruin@gmail.com>\n---\nNo changes since v7.\n\n builtin/rebase--helper.c   | 23 ++++++++++++++++++++++-\n git-rebase--interactive.sh |  9 ---------\n 2 files changed, 22 insertions(+), 10 deletions(-)\n\ndiff --git a/builtin/rebase--helper.c b/builtin/rebase--helper.c\nindex 63c5086e42..f8128037d3 100644\n--- a/builtin/rebase--helper.c\n+++ b/builtin/rebase--helper.c\n@@ -5,10 +5,13 @@\n #include \"sequencer.h\"\n #include \"rebase-interactive.h\"\n #include \"argv-array.h\"\n+#include \"refs.h\"\n #include \"rerere.h\"\n #include \"alias.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 get_revision_ranges(const char *upstream, const char *onto,\n \t\t\t       const char **head_hash,\n@@ -44,6 +47,24 @@ static int get_revision_ranges(const char *upstream, const char *onto,\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 const char * const builtin_rebase_helper_usage[] = {\n \tN_(\"git rebase--helper [<options>]\"),\n \tNULL\n@@ -198,7 +219,7 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\n \t\tif (ret)\n \t\t\treturn ret;\n \n-\t\treturn !!write_basic_state(&opts, head_name, onto, head_hash);\n+\t\treturn !!init_basic_state(&opts, head_name, onto, head_hash);\n \t}\n \n \tusage_with_options(builtin_rebase_helper_usage, options);\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex 6367da66e2..761be95ed1 100644\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -51,14 +51,6 @@ initiate_action () {\n \tesac\n }\n \n-init_basic_state () {\n-\torig_head=$(git rev-parse --verify HEAD) || die \"$(gettext \"No HEAD?\")\"\n-\tmkdir -p \"$state_dir\" || die \"$(eval_gettext \"Could not create temporary \\$state_dir\")\"\n-\trm -f \"$(git rev-parse --git-path REBASE_HEAD)\"\n-\n-\t: > \"$state_dir\"/interactive || die \"$(gettext \"Could not mark as interactive\")\"\n-}\n-\n git_rebase__interactive () {\n \tinitiate_action \"$action\"\n \tret=$?\n@@ -67,7 +59,6 @@ git_rebase__interactive () {\n \tfi\n \n \tgit rebase--helper --prepare-branch \"$switch_to\" ${verbose:+--verbose}\n-\tinit_basic_state\n \n \tgit rebase--helper --init-basic-state ${upstream:+--upstream \"$upstream\"} \\\n \t\t${onto:+--onto \"$onto\"} ${head_name:+--head-name \"$head_name\"} \\\n-- \n2.19.0\n\n"},{"id":"359143","messageId":"20180927215610.32210-16-alban.gruin@gmail.com","threadId":"48814","inReplyTo":"20180927215610.32210-1-alban.gruin@gmail.com","subject":"[GSoC][PATCH v8 15/20] rebase -i: rewrite write_basic_state() in C","fromName":"Alban Gruin","fromEmail":"alban.gruin@gmail.com","sentAt":"2018-09-27T21:56:05Z","receivedAt":"2018-09-27T22:00:53Z","isPatch":true,"sender":{"key":"alban.gruin@gmail.com","avatar":"https://avatars.githubusercontent.com/u/6310153?v=4"},"body":"This rewrites write_basic_state() from git-rebase.sh in C.  This is the\nfirst step in the conversion of init_basic_state(), hence the mode in\nrebase--helper.c is called INIT_BASIC_STATE.  init_basic_state() will be\nconverted in the next commit.\n\nThe part of read_strategy_opts() that parses the stategy options is\nmoved to a new function to allow its use in rebase--helper.c.\n\nFinally, the call to write_basic_state() is removed from\ngit-rebase--interactive.sh, replaced by a call to `--init-basic-state`.\n\nSigned-off-by: Alban Gruin <alban.gruin@gmail.com>\n---\nNo changes since v7.\n\n builtin/rebase--helper.c   | 28 +++++++++++++-\n git-rebase--interactive.sh |  7 +++-\n sequencer.c                | 77 ++++++++++++++++++++++++++++++++------\n sequencer.h                |  4 ++\n 4 files changed, 102 insertions(+), 14 deletions(-)\n\ndiff --git a/builtin/rebase--helper.c b/builtin/rebase--helper.c\nindex 0716bbfd78..63c5086e42 100644\n--- a/builtin/rebase--helper.c\n+++ b/builtin/rebase--helper.c\n@@ -5,6 +5,8 @@\n #include \"sequencer.h\"\n #include \"rebase-interactive.h\"\n #include \"argv-array.h\"\n+#include \"rerere.h\"\n+#include \"alias.h\"\n \n static GIT_PATH_FUNC(path_squash_onto, \"rebase-merge/squash-onto\")\n \n@@ -53,11 +55,12 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\n \tunsigned flags = 0, keep_empty = 0, rebase_merges = 0, autosquash = 0;\n \tint abbreviate_commands = 0, rebase_cousins = -1, ret;\n \tconst char *head_hash = NULL, *onto = NULL, *restrict_revision = NULL,\n-\t\t*squash_onto = NULL, *upstream = NULL;\n+\t\t*squash_onto = NULL, *upstream = NULL, *head_name = NULL;\n+\tchar *raw_strategies = NULL;\n \tenum {\n \t\tCONTINUE = 1, ABORT, MAKE_SCRIPT, SHORTEN_OIDS, EXPAND_OIDS,\n \t\tCHECK_TODO_LIST, REARRANGE_SQUASH, ADD_EXEC, EDIT_TODO, PREPARE_BRANCH,\n-\t\tCOMPLETE_ACTION\n+\t\tCOMPLETE_ACTION, INIT_BASIC_STATE\n \t} command = 0;\n \tstruct option options[] = {\n \t\tOPT_BOOL(0, \"ff\", &opts.allow_ff, N_(\"allow fast-forward\")),\n@@ -69,6 +72,7 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\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\tCONTINUE),\n@@ -93,6 +97,8 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\n \t\t\t    N_(\"prepare the branch to be rebased\"), PREPARE_BRANCH),\n \t\tOPT_CMDMODE(0, \"complete-action\", &command,\n \t\t\t    N_(\"complete the action\"), COMPLETE_ACTION),\n+\t\tOPT_CMDMODE(0, \"init-basic-state\", &command,\n+\t\t\t    N_(\"initialise the rebase state\"), INIT_BASIC_STATE),\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@@ -100,6 +106,14 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\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\tOPT_STRING('S', \"gpg-sign\", &opts.gpg_sign, N_(\"gpg-sign\"),\n+\t\t\t   N_(\"GPG-sign commits\")),\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_RERERE_AUTOUPDATE(&opts.allow_rerere_auto),\n \t\tOPT_END()\n \t};\n \n@@ -176,6 +190,16 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)\n \t\tfree(shortrevisions);\n \t\treturn !!ret;\n \t}\n+\tif (command == INIT_BASIC_STATE) {\n+\t\tif (raw_strategies)\n+\t\t\tparse_strategy_opts(&opts, raw_strategies);\n+\n+\t\tret = get_revision_ranges(upstream, onto, &head_hash, NULL, NULL);\n+\t\tif (ret)\n+\t\t\treturn ret;\n+\n+\t\treturn !!write_basic_state(&opts, head_name, onto, head_hash);\n+\t}\n \n \tusage_with_options(builtin_rebase_helper_usage, options);\n }\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex 08e9a21c2f..6367da66e2 100644\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -57,7 +57,6 @@ init_basic_state () {\n \trm -f \"$(git rev-parse --git-path REBASE_HEAD)\"\n \n \t: > \"$state_dir\"/interactive || die \"$(gettext \"Could not mark as interactive\")\"\n-\twrite_basic_state\n }\n \n git_rebase__interactive () {\n@@ -70,6 +69,12 @@ git_rebase__interactive () {\n \tgit rebase--helper --prepare-branch \"$switch_to\" ${verbose:+--verbose}\n \tinit_basic_state\n \n+\tgit rebase--helper --init-basic-state ${upstream:+--upstream \"$upstream\"} \\\n+\t\t${onto:+--onto \"$onto\"} ${head_name:+--head-name \"$head_name\"} \\\n+\t\t${verbose:+--verbose} ${strategy:+--strategy \"$strategy\"} \\\n+\t\t${strategy_opts:+--strategy-opts=\"$strategy_opts\"} \\\n+\t\t\"$allow_rerere_autoupdate\" \"$gpg_sign_opt\" \"$signoff\" || exit\n+\n \tgit rebase--helper --make-script ${keep_empty:+--keep-empty} \\\n \t\t${rebase_merges:+--rebase-merges} \\\n \t\t${rebase_cousins:+--rebase-cousins} \\\ndiff --git a/sequencer.c b/sequencer.c\nindex e3de1fbb2d..0a3292d5c4 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -145,7 +145,7 @@ static GIT_PATH_FUNC(rebase_path_refs_to_delete, \"rebase-merge/refs-to-delete\")\n \n /*\n  * The following files are written by git-rebase just after parsing the\n- * command-line (and are only consumed, not modified, by the sequencer).\n+ * command-line.\n  */\n static GIT_PATH_FUNC(rebase_path_gpg_sign_opt, \"rebase-merge/gpg_sign_opt\")\n static GIT_PATH_FUNC(rebase_path_orig_head, \"rebase-merge/orig-head\")\n@@ -157,6 +157,7 @@ static GIT_PATH_FUNC(rebase_path_autostash, \"rebase-merge/autostash\")\n static GIT_PATH_FUNC(rebase_path_strategy, \"rebase-merge/strategy\")\n static GIT_PATH_FUNC(rebase_path_strategy_opts, \"rebase-merge/strategy_opts\")\n static GIT_PATH_FUNC(rebase_path_allow_rerere_autoupdate, \"rebase-merge/allow_rerere_autoupdate\")\n+static GIT_PATH_FUNC(rebase_path_quiet, \"rebase-merge/quiet\")\n \n static int git_sequencer_config(const char *k, const char *v, void *cb)\n {\n@@ -2247,21 +2248,14 @@ static int populate_opts_cb(const char *key, const char *value, void *data)\n \treturn 0;\n }\n \n-static void read_strategy_opts(struct replay_opts *opts, struct strbuf *buf)\n+void parse_strategy_opts(struct replay_opts *opts, char *raw_opts)\n {\n \tint i;\n-\tchar *strategy_opts_string;\n+\tchar *strategy_opts_string = raw_opts;\n \n-\tstrbuf_reset(buf);\n-\tif (!read_oneliner(buf, rebase_path_strategy(), 0))\n-\t\treturn;\n-\topts->strategy = strbuf_detach(buf, NULL);\n-\tif (!read_oneliner(buf, rebase_path_strategy_opts(), 0))\n-\t\treturn;\n-\n-\tstrategy_opts_string = buf->buf;\n \tif (*strategy_opts_string == ' ')\n \t\tstrategy_opts_string++;\n+\n \topts->xopts_nr = split_cmdline(strategy_opts_string,\n \t\t\t\t       (const char ***)&opts->xopts);\n \tfor (i = 0; i < opts->xopts_nr; i++) {\n@@ -2272,6 +2266,18 @@ static void read_strategy_opts(struct replay_opts *opts, struct strbuf *buf)\n \t}\n }\n \n+static void read_strategy_opts(struct replay_opts *opts, struct strbuf *buf)\n+{\n+\tstrbuf_reset(buf);\n+\tif (!read_oneliner(buf, rebase_path_strategy(), 0))\n+\t\treturn;\n+\topts->strategy = strbuf_detach(buf, NULL);\n+\tif (!read_oneliner(buf, rebase_path_strategy_opts(), 0))\n+\t\treturn;\n+\n+\tparse_strategy_opts(opts, buf->buf);\n+}\n+\n static int read_populate_opts(struct replay_opts *opts)\n {\n \tif (is_rebase_i(opts)) {\n@@ -2339,6 +2345,55 @@ static int read_populate_opts(struct replay_opts *opts)\n \treturn 0;\n }\n \n+static void write_strategy_opts(struct replay_opts *opts)\n+{\n+\tint i;\n+\tstruct strbuf buf = STRBUF_INIT;\n+\n+\tfor (i = 0; i < opts->xopts_nr; ++i)\n+\t\tstrbuf_addf(&buf, \" --%s\", opts->xopts[i]);\n+\n+\twrite_file(rebase_path_strategy_opts(), \"%s\\n\", buf.buf);\n+\tstrbuf_release(&buf);\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+{\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+\tif (orig_head)\n+\t\twrite_file(rebase_path_orig_head(), \"%s\\n\", orig_head);\n+\n+\tif (quiet)\n+\t\twrite_file(rebase_path_quiet(), \"%s\\n\", quiet);\n+\telse\n+\t\twrite_file(rebase_path_quiet(), \"\\n\");\n+\n+\tif (opts->verbose)\n+\t\twrite_file(rebase_path_verbose(), \"\");\n+\tif (opts->strategy)\n+\t\twrite_file(rebase_path_strategy(), \"%s\\n\", opts->strategy);\n+\tif (opts->xopts_nr > 0)\n+\t\twrite_strategy_opts(opts);\n+\n+\tif (opts->allow_rerere_auto == RERERE_AUTOUPDATE)\n+\t\twrite_file(rebase_path_allow_rerere_autoupdate(), \"--rerere-autoupdate\\n\");\n+\telse if (opts->allow_rerere_auto == RERERE_NOAUTOUPDATE)\n+\t\twrite_file(rebase_path_allow_rerere_autoupdate(), \"--no-rerere-autoupdate\\n\");\n+\n+\tif (opts->gpg_sign)\n+\t\twrite_file(rebase_path_gpg_sign_opt(), \"-S%s\\n\", opts->gpg_sign);\n+\tif (opts->signoff)\n+\t\twrite_file(rebase_path_signoff(), \"--signoff\\n\");\n+\n+\treturn 0;\n+}\n+\n static int walk_revs_populate_todo(struct todo_list *todo_list,\n \t\t\t\tstruct replay_opts *opts)\n {\ndiff --git a/sequencer.h b/sequencer.h\nindex 30bd9c12ac..660cff5050 100644\n--- a/sequencer.h\n+++ b/sequencer.h\n@@ -131,3 +131,7 @@ int prepare_branch_to_be_rebased(struct replay_opts *opts, const char *commit);\n void print_commit_summary(const char *prefix, const struct object_id *oid,\n \t\t\t  unsigned int flags);\n #endif\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-- \n2.19.0\n\n"},{"id":"359144","messageId":"20180927215610.32210-18-alban.gruin@gmail.com","threadId":"48814","inReplyTo":"20180927215610.32210-1-alban.gruin@gmail.com","subject":"[GSoC][PATCH v8 17/20] rebase -i: implement the main part of interactive rebase as a builtin","fromName":"Alban Gruin","fromEmail":"alban.gruin@gmail.com","sentAt":"2018-09-27T21:56:07Z","receivedAt":"2018-09-27T22:00:54Z","isPatch":true,"sender":{"key":"alban.gruin@gmail.com","avatar":"https://avatars.githubusercontent.com/u/6310153?v=4"},"body":"This rewrites the part of interactive rebase which initializes the\nbasic state, make the script and complete the action, as a buitin, named\ngit-rebase--interactive2 for now.  Others modes (`--continue`,\n`--edit-todo`, etc.) will be rewritten in the next commit.\n\ngit-rebase--interactive.sh is modified to call git-rebase--interactive2\ninstead of git-rebase--helper.\n\nSigned-off-by: Alban Gruin <alban.gruin@gmail.com>\n---\n .gitignore                     |   1 +\n Makefile                       |   1 +\n builtin.h                      |   1 +\n builtin/rebase--interactive2.c | 207 +++++++++++++++++++++++++++++++++\n git-rebase--interactive.sh     |  41 ++++---\n git.c                          |   1 +\n 6 files changed, 233 insertions(+), 19 deletions(-)\n create mode 100644 builtin/rebase--interactive2.c\n\ndiff --git a/.gitignore b/.gitignore\nindex 9d1363a1eb..e33c09d52a 100644\n--- a/.gitignore\n+++ b/.gitignore\n@@ -120,6 +120,7 @@\n /git-rebase--am\n /git-rebase--helper\n /git-rebase--interactive\n+/git-rebase--interactive2\n /git-rebase--merge\n /git-rebase--preserve-merges\n /git-receive-pack\ndiff --git a/Makefile b/Makefile\nindex ff7f01634f..bd10c87075 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -1082,6 +1082,7 @@ BUILTIN_OBJS += builtin/pull.o\n BUILTIN_OBJS += builtin/push.o\n BUILTIN_OBJS += builtin/range-diff.o\n BUILTIN_OBJS += builtin/read-tree.o\n+BUILTIN_OBJS += builtin/rebase--interactive2.o\n BUILTIN_OBJS += builtin/rebase--helper.o\n BUILTIN_OBJS += builtin/receive-pack.o\n BUILTIN_OBJS += builtin/reflog.o\ndiff --git a/builtin.h b/builtin.h\nindex 962f0489ab..b79265d3d4 100644\n--- a/builtin.h\n+++ b/builtin.h\n@@ -204,6 +204,7 @@ extern int cmd_pull(int argc, const char **argv, const char *prefix);\n extern int cmd_push(int argc, const char **argv, const char *prefix);\n extern int cmd_range_diff(int argc, const char **argv, const char *prefix);\n extern int cmd_read_tree(int argc, const char **argv, const char *prefix);\n+extern int cmd_rebase__interactive(int argc, const char **argv, const char *prefix);\n extern int cmd_rebase__helper(int argc, const char **argv, const char *prefix);\n extern int cmd_receive_pack(int argc, const char **argv, const char *prefix);\n extern int cmd_reflog(int argc, const char **argv, const char *prefix);\ndiff --git a/builtin/rebase--interactive2.c b/builtin/rebase--interactive2.c\nnew file mode 100644\nindex 0000000000..45336073a8\n--- /dev/null\n+++ b/builtin/rebase--interactive2.c\n@@ -0,0 +1,207 @@\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 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 const char *cmd, 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+\tFILE *todo_list;\n+\n+\tif (prepare_branch_to_be_rebased(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+\ttodo_list = fopen(rebase_path_todo(), \"w\");\n+\tif (!todo_list) {\n+\t\tfree(revisions);\n+\t\tfree(shortrevisions);\n+\n+\t\treturn error_errno(_(\"could not open %s\"), rebase_path_todo());\n+\t}\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(todo_list,\n+\t\t\t\t    make_script_args.argc, make_script_args.argv,\n+\t\t\t\t    flags);\n+\tfclose(todo_list);\n+\n+\tif (ret)\n+\t\terror(_(\"could not generate todo list\"));\n+\telse {\n+\t\tdiscard_cache();\n+\t\tret = complete_action(opts, flags, shortrevisions, onto_name, onto,\n+\t\t\t\t      head_hash, cmd, autosquash);\n+\t}\n+\n+\tfree(revisions);\n+\tfree(shortrevisions);\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;\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+\tchar *raw_strategies = NULL;\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_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_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+\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 (!onto && !upstream)\n+\t\tdie(_(\"a base commit must be provided with --upstream or --onto\"));\n+\n+\treturn !!do_interactive_rebase(&opts, flags, switch_to, upstream, onto,\n+\t\t\t\t       onto_name, squash_onto, head_name, restrict_revision,\n+\t\t\t\t       raw_strategies, cmd, autosquash);\n+}\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex 761be95ed1..e87d708a4d 100644\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -58,24 +58,27 @@ git_rebase__interactive () {\n \t\treturn 0\n \tfi\n \n-\tgit rebase--helper --prepare-branch \"$switch_to\" ${verbose:+--verbose}\n+\ttest -n \"$keep_empty\" && keep_empty=\"--keep-empty\"\n+\ttest -n \"$rebase_merges\" && rebase_merges=\"--rebase-merges\"\n+\ttest -n \"$rebase_cousins\" && rebase_cousins=\"--rebase-cousins\"\n+\ttest -n \"$autosquash\" && autosquash=\"--autosquash\"\n+\ttest -n \"$verbose\" && verbose=\"--verbose\"\n+\ttest -n \"$force_rebase\" && force_rebase=\"--no-ff\"\n+\ttest -n \"$restrict_revisions\" && restrict_revisions=\"--restrict-revisions=^$restrict_revisions\"\n+\ttest -n \"$upstream\" && upstream=\"--upstream=$upstream\"\n+\ttest -n \"$onto\" && onto=\"--onto=$onto\"\n+\ttest -n \"$squash_onto\" && squash_onto=\"--squash-onto=$squash_onto\"\n+\ttest -n \"$onto_name\" && onto_name=\"--onto-name=$onto_name\"\n+\ttest -n \"$head_name\" && head_name=\"--head-name=$head_name\"\n+\ttest -n \"$strategy\" && strategy=\"--strategy=$strategy\"\n+\ttest -n \"$strategy_opts\" && strategy_opts=\"--strategy-opts=$strategy_opts\"\n+\ttest -n \"$switch_to\" && switch_to=\"--switch-to=$switch_to\"\n+\ttest -n \"$cmd\" && cmd=\"--cmd=$cmd\"\n \n-\tgit rebase--helper --init-basic-state ${upstream:+--upstream \"$upstream\"} \\\n-\t\t${onto:+--onto \"$onto\"} ${head_name:+--head-name \"$head_name\"} \\\n-\t\t${verbose:+--verbose} ${strategy:+--strategy \"$strategy\"} \\\n-\t\t${strategy_opts:+--strategy-opts=\"$strategy_opts\"} \\\n-\t\t\"$allow_rerere_autoupdate\" \"$gpg_sign_opt\" \"$signoff\" || exit\n-\n-\tgit rebase--helper --make-script ${keep_empty:+--keep-empty} \\\n-\t\t${rebase_merges:+--rebase-merges} \\\n-\t\t${rebase_cousins:+--rebase-cousins} \\\n-\t\t${upstream:+--upstream \"$upstream\"} ${onto:+--onto \"$onto\"} \\\n-\t\t${squash_onto:+--squash-onto \"$squash_onto\"} \\\n-\t\t${restrict_revision:+--restrict-revision ^\"$restrict_revision\"} >\"$todo\" ||\n-\tdie \"$(gettext \"Could not generate todo list\")\"\n-\n-\texec git rebase--helper --complete-action \"$onto_name\" \"$cmd\" \\\n-\t\t$allow_empty_message ${autosquash:+--autosquash} ${verbose:+--verbose} \\\n-\t\t${keep_empty:+--keep-empty} ${force_rebase:+--no-ff} \\\n-\t\t${upstream:+--upstream \"$upstream\"} ${onto:+--onto \"$onto\"}\n+\texec git rebase--interactive2 \"$keep_empty\" \"$rebase_merges\" \"$rebase_cousins\" \\\n+\t\t\"$upstream\" \"$onto\" \"$squash_onto\" \"$restrict_revision\" \\\n+\t\t\"$allow_empty_message\" \"$autosquash\" \"$verbose\" \\\n+\t\t\"$force_rebase\" \"$onto_name\" \"$head_name\" \"$strategy\" \\\n+\t\t\"$strategy_opts\" \"$cmd\" \"$switch_to\" \\\n+\t\t\"$allow_rerere_autoupdate\" \"$gpg_sign_opt\" \"$signoff\"\n }\ndiff --git a/git.c b/git.c\nindex a6f4b44af5..3fefa28998 100644\n--- a/git.c\n+++ b/git.c\n@@ -523,6 +523,7 @@ static struct cmd_struct commands[] = {\n \t{ \"push\", cmd_push, RUN_SETUP },\n \t{ \"range-diff\", cmd_range_diff, RUN_SETUP | USE_PAGER },\n \t{ \"read-tree\", cmd_read_tree, RUN_SETUP | SUPPORT_SUPER_PREFIX},\n+\t{ \"rebase--interactive2\", cmd_rebase__interactive, RUN_SETUP | NEED_WORK_TREE },\n \t{ \"rebase--helper\", cmd_rebase__helper, RUN_SETUP | NEED_WORK_TREE },\n \t{ \"receive-pack\", cmd_receive_pack },\n \t{ \"reflog\", cmd_reflog, RUN_SETUP },\n-- \n2.19.0\n\n"},{"id":"359145","messageId":"20180927215610.32210-19-alban.gruin@gmail.com","threadId":"48814","inReplyTo":"20180927215610.32210-1-alban.gruin@gmail.com","subject":"[GSoC][PATCH v8 18/20] rebase--interactive2: rewrite the submodes of interactive rebase in C","fromName":"Alban Gruin","fromEmail":"alban.gruin@gmail.com","sentAt":"2018-09-27T21:56:08Z","receivedAt":"2018-09-27T22:00:55Z","isPatch":true,"sender":{"key":"alban.gruin@gmail.com","avatar":"https://avatars.githubusercontent.com/u/6310153?v=4"},"body":"This rewrites the submodes of interactive rebase (`--continue`,\n`--skip`, `--edit-todo`, and `--show-current-patch`) in C.\n\ngit-rebase.sh is then modified to call directly git-rebase--interactive2\ninstead of git-rebase--interactive.sh.\n\nSigned-off-by: Alban Gruin <alban.gruin@gmail.com>\n---\nNo changes since v7.\n\n builtin/rebase--interactive2.c | 51 ++++++++++++++++++++++++++++++----\n git-rebase.sh                  | 45 +++++++++++++++++++++++++++---\n 2 files changed, 86 insertions(+), 10 deletions(-)\n\ndiff --git a/builtin/rebase--interactive2.c b/builtin/rebase--interactive2.c\nindex 45336073a8..aaf13c9621 100644\n--- a/builtin/rebase--interactive2.c\n+++ b/builtin/rebase--interactive2.c\n@@ -134,11 +134,14 @@ 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;\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 \tchar *raw_strategies = NULL;\n+\tenum {\n+\t\tNONE = 0, CONTINUE, SKIP, EDIT_TODO, SHOW_CURRENT_PATCH\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@@ -151,6 +154,13 @@ int cmd_rebase__interactive(int argc, const char **argv, const char *prefix)\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_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@@ -198,10 +208,39 @@ 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 (!onto && !upstream)\n-\t\tdie(_(\"a base commit must be provided with --upstream or --onto\"));\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, cmd, autosquash);\n+\t\tbreak;\n+\tcase SKIP: {\n+\t\tstruct string_list merge_rr = STRING_LIST_INIT_DUP;\n+\n+\t\trerere_clear(&merge_rr);\n+\t\t/* fallthrough */\n+\tcase CONTINUE:\n+\t\tret = sequencer_continue(&opts);\n+\t\tbreak;\n+\t}\n+\tcase EDIT_TODO:\n+\t\tret = edit_todo_list(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+\tdefault:\n+\t\tBUG(\"invalid command '%d'\", command);\n+\t}\n \n-\treturn !!do_interactive_rebase(&opts, flags, switch_to, upstream, onto,\n-\t\t\t\t       onto_name, squash_onto, head_name, restrict_revision,\n-\t\t\t\t       raw_strategies, cmd, autosquash);\n+\treturn !!ret;\n }\ndiff --git a/git-rebase.sh b/git-rebase.sh\nindex 51a6db7daa..6e1e413cf2 100755\n--- a/git-rebase.sh\n+++ b/git-rebase.sh\n@@ -200,19 +200,56 @@ finish_rebase () {\n \trm -rf \"$state_dir\"\n }\n \n+run_interactive () {\n+\tGIT_CHERRY_PICK_HELP=\"$resolvemsg\"\n+\texport GIT_CHERRY_PICK_HELP\n+\n+\ttest -n \"$keep_empty\" && keep_empty=\"--keep-empty\"\n+\ttest -n \"$rebase_merges\" && rebase_merges=\"--rebase-merges\"\n+\ttest -n \"$rebase_cousins\" && rebase_cousins=\"--rebase-cousins\"\n+\ttest -n \"$autosquash\" && autosquash=\"--autosquash\"\n+\ttest -n \"$verbose\" && verbose=\"--verbose\"\n+\ttest -n \"$force_rebase\" && force_rebase=\"--no-ff\"\n+\ttest -n \"$restrict_revision\" && \\\n+\t\trestrict_revision=\"--restrict-revision=^$restrict_revision\"\n+\ttest -n \"$upstream\" && upstream=\"--upstream=$upstream\"\n+\ttest -n \"$onto\" && onto=\"--onto=$onto\"\n+\ttest -n \"$squash_onto\" && squash_onto=\"--squash-onto=$squash_onto\"\n+\ttest -n \"$onto_name\" && onto_name=\"--onto-name=$onto_name\"\n+\ttest -n \"$head_name\" && head_name=\"--head-name=$head_name\"\n+\ttest -n \"$strategy\" && strategy=\"--strategy=$strategy\"\n+\ttest -n \"$strategy_opts\" && strategy_opts=\"--strategy-opts=$strategy_opts\"\n+\ttest -n \"$switch_to\" && switch_to=\"--switch-to=$switch_to\"\n+\ttest -n \"$cmd\" && cmd=\"--cmd=$cmd\"\n+\ttest -n \"$action\" && action=\"--$action\"\n+\n+\texec git rebase--interactive2 \"$action\" \"$keep_empty\" \"$rebase_merges\" \"$rebase_cousins\" \\\n+\t\t\"$upstream\" \"$onto\" \"$squash_onto\" \"$restrict_revision\" \\\n+\t\t\"$allow_empty_message\" \"$autosquash\" \"$verbose\" \\\n+\t\t\"$force_rebase\" \"$onto_name\" \"$head_name\" \"$strategy\" \\\n+\t\t\"$strategy_opts\" \"$cmd\" \"$switch_to\" \\\n+\t\t\"$allow_rerere_autoupdate\" \"$gpg_sign_opt\" \"$signoff\"\n+}\n+\n run_specific_rebase () {\n \tif [ \"$interactive_rebase\" = implied ]; then\n \t\tGIT_EDITOR=:\n \t\texport GIT_EDITOR\n \t\tautosquash=\n \tfi\n-\t. git-rebase--$type\n \n-\tif test -z \"$preserve_merges\"\n+\tif test -n \"$interactive_rebase\" -a -z \"$preserve_merges\"\n \tthen\n-\t\tgit_rebase__$type\n+\t\trun_interactive\n \telse\n-\t\tgit_rebase__preserve_merges\n+\t\t. git-rebase--$type\n+\n+\t\tif test -z \"$preserve_merges\"\n+\t\tthen\n+\t\t\tgit_rebase__$type\n+\t\telse\n+\t\t\tgit_rebase__preserve_merges\n+\t\tfi\n \tfi\n \n \tret=$?\n-- \n2.19.0\n\n"},{"id":"359146","messageId":"20180927215610.32210-20-alban.gruin@gmail.com","threadId":"48814","inReplyTo":"20180927215610.32210-1-alban.gruin@gmail.com","subject":"[GSoC][PATCH v8 19/20] rebase -i: remove git-rebase--interactive.sh","fromName":"Alban Gruin","fromEmail":"alban.gruin@gmail.com","sentAt":"2018-09-27T21:56:09Z","receivedAt":"2018-09-27T22:00:56Z","isPatch":true,"sender":{"key":"alban.gruin@gmail.com","avatar":"https://avatars.githubusercontent.com/u/6310153?v=4"},"body":"This removes git-rebase--interactive.sh, as its functionnality has been\nreplaced by git-rebase--interactive2.\n\ngit-rebase--interactive2.c is then renamed to git-rebase--interactive.c.\n\nSigned-off-by: Alban Gruin <alban.gruin@gmail.com>\n---\nThe changes are due to the rebase, no real changes otherwise.\n\n .gitignore                                    |  1 -\n Makefile                                      |  4 +-\n ...--interactive2.c => rebase--interactive.c} |  0\n git-rebase--interactive.sh                    | 84 -------------------\n git-rebase.sh                                 |  2 +-\n git.c                                         |  2 +-\n 6 files changed, 3 insertions(+), 90 deletions(-)\n rename builtin/{rebase--interactive2.c => rebase--interactive.c} (100%)\n delete mode 100644 git-rebase--interactive.sh\n\ndiff --git a/.gitignore b/.gitignore\nindex e33c09d52a..9d1363a1eb 100644\n--- a/.gitignore\n+++ b/.gitignore\n@@ -120,7 +120,6 @@\n /git-rebase--am\n /git-rebase--helper\n /git-rebase--interactive\n-/git-rebase--interactive2\n /git-rebase--merge\n /git-rebase--preserve-merges\n /git-receive-pack\ndiff --git a/Makefile b/Makefile\nindex bd10c87075..dc26276747 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -624,7 +624,6 @@ SCRIPT_SH += git-web--browse.sh\n SCRIPT_LIB += git-mergetool--lib\n SCRIPT_LIB += git-parse-remote\n SCRIPT_LIB += git-rebase--am\n-SCRIPT_LIB += git-rebase--interactive\n SCRIPT_LIB += git-rebase--preserve-merges\n SCRIPT_LIB += git-rebase--merge\n SCRIPT_LIB += git-sh-setup\n@@ -1082,8 +1081,8 @@ BUILTIN_OBJS += builtin/pull.o\n BUILTIN_OBJS += builtin/push.o\n BUILTIN_OBJS += builtin/range-diff.o\n BUILTIN_OBJS += builtin/read-tree.o\n-BUILTIN_OBJS += builtin/rebase--interactive2.o\n BUILTIN_OBJS += builtin/rebase--helper.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\n@@ -2422,7 +2421,6 @@ XGETTEXT_FLAGS_PERL = $(XGETTEXT_FLAGS) --language=Perl \\\n LOCALIZED_C = $(C_OBJ:o=c) $(LIB_H) $(GENERATED_H)\n LOCALIZED_SH = $(SCRIPT_SH)\n LOCALIZED_SH += git-parse-remote.sh\n-LOCALIZED_SH += git-rebase--interactive.sh\n LOCALIZED_SH += git-rebase--preserve-merges.sh\n LOCALIZED_SH += git-sh-setup.sh\n LOCALIZED_PERL = $(SCRIPT_PERL)\ndiff --git a/builtin/rebase--interactive2.c b/builtin/rebase--interactive.c\nsimilarity index 100%\nrename from builtin/rebase--interactive2.c\nrename to builtin/rebase--interactive.c\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\ndeleted file mode 100644\nindex e87d708a4d..0000000000\n--- a/git-rebase--interactive.sh\n+++ /dev/null\n@@ -1,84 +0,0 @@\n-# This shell script fragment is sourced by git-rebase to implement\n-# its interactive mode.  \"git rebase --interactive\" makes it easy\n-# to fix up commits in the middle of a series and rearrange commits.\n-#\n-# Copyright (c) 2006 Johannes E. Schindelin\n-#\n-# The original idea comes from Eric W. Biederman, in\n-# https://public-inbox.org/git/m1odwkyuf5.fsf_-_@ebiederm.dsl.xmission.com/\n-#\n-# The file containing rebase commands, comments, and empty lines.\n-# This file is created by \"git rebase -i\" then edited by the user.  As\n-# the lines are processed, they are removed from the front of this\n-# file and written to the tail of $done.\n-todo=\"$state_dir\"/git-rebase-todo\n-\n-GIT_CHERRY_PICK_HELP=\"$resolvemsg\"\n-export GIT_CHERRY_PICK_HELP\n-\n-# Initiate an action. If the cannot be any\n-# further action it  may exec a command\n-# or exit and not return.\n-#\n-# TODO: Consider a cleaner return model so it\n-# never exits and always return 0 if process\n-# is complete.\n-#\n-# Parameter 1 is the action to initiate.\n-#\n-# Returns 0 if the action was able to complete\n-# and if 1 if further processing is required.\n-initiate_action () {\n-\tcase \"$1\" in\n-\tcontinue)\n-\t\texec git rebase--helper ${force_rebase:+--no-ff} $allow_empty_message \\\n-\t\t     --continue\n-\t\t;;\n-\tskip)\n-\t\tgit rerere clear\n-\t\texec git rebase--helper ${force_rebase:+--no-ff} $allow_empty_message \\\n-\t\t     --continue\n-\t\t;;\n-\tedit-todo)\n-\t\texec git rebase--helper --edit-todo\n-\t\t;;\n-\tshow-current-patch)\n-\t\texec git show REBASE_HEAD --\n-\t\t;;\n-\t*)\n-\t\treturn 1 # continue\n-\t\t;;\n-\tesac\n-}\n-\n-git_rebase__interactive () {\n-\tinitiate_action \"$action\"\n-\tret=$?\n-\tif test $ret = 0; then\n-\t\treturn 0\n-\tfi\n-\n-\ttest -n \"$keep_empty\" && keep_empty=\"--keep-empty\"\n-\ttest -n \"$rebase_merges\" && rebase_merges=\"--rebase-merges\"\n-\ttest -n \"$rebase_cousins\" && rebase_cousins=\"--rebase-cousins\"\n-\ttest -n \"$autosquash\" && autosquash=\"--autosquash\"\n-\ttest -n \"$verbose\" && verbose=\"--verbose\"\n-\ttest -n \"$force_rebase\" && force_rebase=\"--no-ff\"\n-\ttest -n \"$restrict_revisions\" && restrict_revisions=\"--restrict-revisions=^$restrict_revisions\"\n-\ttest -n \"$upstream\" && upstream=\"--upstream=$upstream\"\n-\ttest -n \"$onto\" && onto=\"--onto=$onto\"\n-\ttest -n \"$squash_onto\" && squash_onto=\"--squash-onto=$squash_onto\"\n-\ttest -n \"$onto_name\" && onto_name=\"--onto-name=$onto_name\"\n-\ttest -n \"$head_name\" && head_name=\"--head-name=$head_name\"\n-\ttest -n \"$strategy\" && strategy=\"--strategy=$strategy\"\n-\ttest -n \"$strategy_opts\" && strategy_opts=\"--strategy-opts=$strategy_opts\"\n-\ttest -n \"$switch_to\" && switch_to=\"--switch-to=$switch_to\"\n-\ttest -n \"$cmd\" && cmd=\"--cmd=$cmd\"\n-\n-\texec git rebase--interactive2 \"$keep_empty\" \"$rebase_merges\" \"$rebase_cousins\" \\\n-\t\t\"$upstream\" \"$onto\" \"$squash_onto\" \"$restrict_revision\" \\\n-\t\t\"$allow_empty_message\" \"$autosquash\" \"$verbose\" \\\n-\t\t\"$force_rebase\" \"$onto_name\" \"$head_name\" \"$strategy\" \\\n-\t\t\"$strategy_opts\" \"$cmd\" \"$switch_to\" \\\n-\t\t\"$allow_rerere_autoupdate\" \"$gpg_sign_opt\" \"$signoff\"\n-}\ndiff --git a/git-rebase.sh b/git-rebase.sh\nindex 6e1e413cf2..3e7798e07b 100755\n--- a/git-rebase.sh\n+++ b/git-rebase.sh\n@@ -223,7 +223,7 @@ run_interactive () {\n \ttest -n \"$cmd\" && cmd=\"--cmd=$cmd\"\n \ttest -n \"$action\" && action=\"--$action\"\n \n-\texec git rebase--interactive2 \"$action\" \"$keep_empty\" \"$rebase_merges\" \"$rebase_cousins\" \\\n+\texec git rebase--interactive \"$action\" \"$keep_empty\" \"$rebase_merges\" \"$rebase_cousins\" \\\n \t\t\"$upstream\" \"$onto\" \"$squash_onto\" \"$restrict_revision\" \\\n \t\t\"$allow_empty_message\" \"$autosquash\" \"$verbose\" \\\n \t\t\"$force_rebase\" \"$onto_name\" \"$head_name\" \"$strategy\" \\\ndiff --git a/git.c b/git.c\nindex 3fefa28998..2ffafefac3 100644\n--- a/git.c\n+++ b/git.c\n@@ -523,7 +523,7 @@ static struct cmd_struct commands[] = {\n \t{ \"push\", cmd_push, RUN_SETUP },\n \t{ \"range-diff\", cmd_range_diff, RUN_SETUP | USE_PAGER },\n \t{ \"read-tree\", cmd_read_tree, RUN_SETUP | SUPPORT_SUPER_PREFIX},\n-\t{ \"rebase--interactive2\", cmd_rebase__interactive, RUN_SETUP | NEED_WORK_TREE },\n+\t{ \"rebase--interactive\", cmd_rebase__interactive, RUN_SETUP | NEED_WORK_TREE },\n \t{ \"rebase--helper\", cmd_rebase__helper, RUN_SETUP | NEED_WORK_TREE },\n \t{ \"receive-pack\", cmd_receive_pack },\n \t{ \"reflog\", cmd_reflog, RUN_SETUP },\n-- \n2.19.0\n\n"},{"id":"359147","messageId":"20180927215610.32210-21-alban.gruin@gmail.com","threadId":"48814","inReplyTo":"20180927215610.32210-1-alban.gruin@gmail.com","subject":"[GSoC][PATCH v8 20/20] rebase -i: move rebase--helper modes to rebase--interactive","fromName":"Alban Gruin","fromEmail":"alban.gruin@gmail.com","sentAt":"2018-09-27T21:56:10Z","receivedAt":"2018-09-27T22:00:58Z","isPatch":true,"sender":{"key":"alban.gruin@gmail.com","avatar":"https://avatars.githubusercontent.com/u/6310153?v=4"},"body":"This moves the rebase--helper modes still used by\ngit-rebase--preserve-merges.sh (`--shorten-ids`, `--expand-ids`,\n`--check-todo-list`, `--rearrange-squash` and `--add-exec-commands`) to\nrebase--interactive.c.\n\ngit-rebase--preserve-merges.sh is modified accordingly, and\nrebase--helper.c is removed as it is useless now.\n\nSigned-off-by: Alban Gruin <alban.gruin@gmail.com>\n---\nThe changes are due to the rebase, no real changes otherwise.\n\n .gitignore                     |   1 -\n Makefile                       |   1 -\n builtin.h                      |   1 -\n builtin/rebase--helper.c       | 226 ---------------------------------\n builtin/rebase--interactive.c  |  27 +++-\n git-rebase--preserve-merges.sh |  10 +-\n git.c                          |   1 -\n 7 files changed, 31 insertions(+), 236 deletions(-)\n delete mode 100644 builtin/rebase--helper.c\n\ndiff --git a/.gitignore b/.gitignore\nindex 9d1363a1eb..1c0394f576 100644\n--- a/.gitignore\n+++ b/.gitignore\n@@ -118,7 +118,6 @@\n /git-read-tree\n /git-rebase\n /git-rebase--am\n-/git-rebase--helper\n /git-rebase--interactive\n /git-rebase--merge\n /git-rebase--preserve-merges\ndiff --git a/Makefile b/Makefile\nindex dc26276747..ec4ee78b3f 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -1081,7 +1081,6 @@ BUILTIN_OBJS += builtin/pull.o\n BUILTIN_OBJS += builtin/push.o\n BUILTIN_OBJS += builtin/range-diff.o\n BUILTIN_OBJS += builtin/read-tree.o\n-BUILTIN_OBJS += builtin/rebase--helper.o\n BUILTIN_OBJS += builtin/rebase--interactive.o\n BUILTIN_OBJS += builtin/receive-pack.o\n BUILTIN_OBJS += builtin/reflog.o\ndiff --git a/builtin.h b/builtin.h\nindex b79265d3d4..f6a7d82d73 100644\n--- a/builtin.h\n+++ b/builtin.h\n@@ -205,7 +205,6 @@ extern int cmd_push(int argc, const char **argv, const char *prefix);\n extern int cmd_range_diff(int argc, const char **argv, const char *prefix);\n extern int cmd_read_tree(int argc, const char **argv, const char *prefix);\n extern int cmd_rebase__interactive(int argc, const char **argv, const char *prefix);\n-extern int cmd_rebase__helper(int argc, const char **argv, const char *prefix);\n extern int cmd_receive_pack(int argc, const char **argv, const char *prefix);\n extern int cmd_reflog(int argc, const char **argv, const char *prefix);\n extern int cmd_remote(int argc, const char **argv, const char *prefix);\ndiff --git a/builtin/rebase--helper.c b/builtin/rebase--helper.c\ndeleted file mode 100644\nindex f8128037d3..0000000000\n--- a/builtin/rebase--helper.c\n+++ /dev/null\n@@ -1,226 +0,0 @@\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 \"alias.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 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;\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-\n-\tif (revisions)\n-\t\t*revisions = xstrfmt(\"%s...%s\", base_rev, *head_hash);\n-\tif (shortrevisions) {\n-\t\tconst char *shorthead;\n-\n-\t\tshorthead = find_unique_abbrev(&orig_head, DEFAULT_ABBREV);\n-\n-\t\tif (upstream) {\n-\t\t\tconst char *shortrev;\n-\t\t\tstruct object_id rev_oid;\n-\n-\t\t\tget_oid(base_rev, &rev_oid);\n-\t\t\tshortrev = find_unique_abbrev(&rev_oid, DEFAULT_ABBREV);\n-\n-\t\t\t*shortrevisions = xstrfmt(\"%s..%s\", shortrev, shorthead);\n-\t\t} else\n-\t\t\t*shortrevisions = xstrdup(shorthead);\n-\t}\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 const char * const builtin_rebase_helper_usage[] = {\n-\tN_(\"git rebase--helper [<options>]\"),\n-\tNULL\n-};\n-\n-int cmd_rebase__helper(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;\n-\tconst char *head_hash = NULL, *onto = NULL, *restrict_revision = NULL,\n-\t\t*squash_onto = NULL, *upstream = NULL, *head_name = NULL;\n-\tchar *raw_strategies = NULL;\n-\tenum {\n-\t\tCONTINUE = 1, ABORT, MAKE_SCRIPT, SHORTEN_OIDS, EXPAND_OIDS,\n-\t\tCHECK_TODO_LIST, REARRANGE_SQUASH, ADD_EXEC, EDIT_TODO, PREPARE_BRANCH,\n-\t\tCOMPLETE_ACTION, INIT_BASIC_STATE\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\tN_(\"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\tCONTINUE),\n-\t\tOPT_CMDMODE(0, \"abort\", &command, N_(\"abort rebase\"),\n-\t\t\t\tABORT),\n-\t\tOPT_CMDMODE(0, \"make-script\", &command,\n-\t\t\tN_(\"make rebase script\"), MAKE_SCRIPT),\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_CMDMODE(0, \"edit-todo\", &command,\n-\t\t\t    N_(\"edit the todo list during an interactive rebase\"),\n-\t\t\t    EDIT_TODO),\n-\t\tOPT_CMDMODE(0, \"prepare-branch\", &command,\n-\t\t\t    N_(\"prepare the branch to be rebased\"), PREPARE_BRANCH),\n-\t\tOPT_CMDMODE(0, \"complete-action\", &command,\n-\t\t\t    N_(\"complete the action\"), COMPLETE_ACTION),\n-\t\tOPT_CMDMODE(0, \"init-basic-state\", &command,\n-\t\t\t    N_(\"initialise the rebase state\"), INIT_BASIC_STATE),\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\tOPT_STRING('S', \"gpg-sign\", &opts.gpg_sign, N_(\"gpg-sign\"),\n-\t\t\t   N_(\"GPG-sign commits\")),\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_RERERE_AUTOUPDATE(&opts.allow_rerere_auto),\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-\targc = parse_options(argc, argv, NULL, options,\n-\t\t\tbuiltin_rebase_helper_usage, PARSE_OPT_KEEP_ARGV0);\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 (command == CONTINUE && argc == 1)\n-\t\treturn !!sequencer_continue(&opts);\n-\tif (command == ABORT && argc == 1)\n-\t\treturn !!sequencer_remove_state(&opts);\n-\tif (command == MAKE_SCRIPT && argc == 1) {\n-\t\tchar *revisions = NULL;\n-\t\tstruct argv_array make_script_args = ARGV_ARRAY_INIT;\n-\n-\t\tif (!upstream && squash_onto)\n-\t\t\twrite_file(path_squash_onto(), \"%s\\n\", squash_onto);\n-\n-\t\tret = get_revision_ranges(upstream, onto, &head_hash, &revisions, NULL);\n-\t\tif (ret)\n-\t\t\treturn ret;\n-\n-\t\targv_array_pushl(&make_script_args, \"\", revisions, NULL);\n-\t\tif (restrict_revision)\n-\t\t\targv_array_push(&make_script_args, restrict_revision);\n-\n-\t\tret = sequencer_make_script(stdout,\n-\t\t\t\t\t    make_script_args.argc, make_script_args.argv,\n-\t\t\t\t\t    flags);\n-\n-\t\tfree(revisions);\n-\t\targv_array_clear(&make_script_args);\n-\n-\t\treturn !!ret;\n-\t}\n-\tif ((command == SHORTEN_OIDS || command == EXPAND_OIDS) && argc == 1)\n-\t\treturn !!transform_todos(flags);\n-\tif (command == CHECK_TODO_LIST && argc == 1)\n-\t\treturn !!check_todo_list();\n-\tif (command == REARRANGE_SQUASH && argc == 1)\n-\t\treturn !!rearrange_squash();\n-\tif (command == ADD_EXEC && argc == 2)\n-\t\treturn !!sequencer_add_exec_commands(argv[1]);\n-\tif (command == EDIT_TODO && argc == 1)\n-\t\treturn !!edit_todo_list(flags);\n-\tif (command == PREPARE_BRANCH && argc == 2)\n-\t\treturn !!prepare_branch_to_be_rebased(&opts, argv[1]);\n-\tif (command == COMPLETE_ACTION && argc == 3) {\n-\t\tchar *shortrevisions = NULL;\n-\n-\t\tret = get_revision_ranges(upstream, onto, &head_hash, NULL, &shortrevisions);\n-\t\tif (ret)\n-\t\t\treturn ret;\n-\n-\t\tret = complete_action(&opts, flags, shortrevisions, argv[1], onto,\n-\t\t\t\t      head_hash, argv[2], autosquash);\n-\n-\t\tfree(shortrevisions);\n-\t\treturn !!ret;\n-\t}\n-\tif (command == INIT_BASIC_STATE) {\n-\t\tif (raw_strategies)\n-\t\t\tparse_strategy_opts(&opts, raw_strategies);\n-\n-\t\tret = get_revision_ranges(upstream, onto, &head_hash, NULL, NULL);\n-\t\tif (ret)\n-\t\t\treturn ret;\n-\n-\t\treturn !!init_basic_state(&opts, head_name, onto, head_hash);\n-\t}\n-\n-\tusage_with_options(builtin_rebase_helper_usage, options);\n-}\ndiff --git a/builtin/rebase--interactive.c b/builtin/rebase--interactive.c\nindex aaf13c9621..a2ab68ed06 100644\n--- a/builtin/rebase--interactive.c\n+++ b/builtin/rebase--interactive.c\n@@ -140,7 +140,8 @@ int cmd_rebase__interactive(int argc, const char **argv, const char *prefix)\n \t\t*switch_to = NULL, *cmd = NULL;\n \tchar *raw_strategies = NULL;\n \tenum {\n-\t\tNONE = 0, CONTINUE, SKIP, EDIT_TODO, SHOW_CURRENT_PATCH\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@@ -161,6 +162,16 @@ int cmd_rebase__interactive(int argc, const char **argv, const char *prefix)\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@@ -203,6 +214,7 @@ int cmd_rebase__interactive(int argc, const char **argv, const char *prefix)\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@@ -238,6 +250,19 @@ 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+\t\tret = transform_todos(flags);\n+\t\tbreak;\n+\tcase CHECK_TODO_LIST:\n+\t\tret = check_todo_list();\n+\t\tbreak;\n+\tcase REARRANGE_SQUASH:\n+\t\tret = rearrange_squash();\n+\t\tbreak;\n+\tcase ADD_EXEC:\n+\t\tret = sequencer_add_exec_commands(cmd);\n+\t\tbreak;\n \tdefault:\n \t\tBUG(\"invalid command '%d'\", command);\n \t}\ndiff --git a/git-rebase--preserve-merges.sh b/git-rebase--preserve-merges.sh\nindex c214c5e4d6..afbb65765d 100644\n--- a/git-rebase--preserve-merges.sh\n+++ b/git-rebase--preserve-merges.sh\n@@ -711,11 +711,11 @@ do_rest () {\n }\n \n expand_todo_ids() {\n-\tgit rebase--helper --expand-ids\n+\tgit rebase--interactive --expand-ids\n }\n \n collapse_todo_ids() {\n-\tgit rebase--helper --shorten-ids\n+\tgit rebase--interactive --shorten-ids\n }\n \n # Switch to the branch in $into and notify it in the reflog\n@@ -876,8 +876,8 @@ init_revisions_and_shortrevisions () {\n \n complete_action() {\n \ttest -s \"$todo\" || echo noop >> \"$todo\"\n-\ttest -z \"$autosquash\" || git rebase--helper --rearrange-squash || exit\n-\ttest -n \"$cmd\" && git rebase--helper --add-exec-commands \"$cmd\"\n+\ttest -z \"$autosquash\" || git rebase--interactive --rearrange-squash || exit\n+\ttest -n \"$cmd\" && git rebase--interactive --add-exec-commands --cmd \"$cmd\"\n \n \ttodocount=$(git stripspace --strip-comments <\"$todo\" | wc -l)\n \ttodocount=${todocount##* }\n@@ -912,7 +912,7 @@ However, if you remove everything, the rebase will be aborted.\n \thas_action \"$todo\" ||\n \t\treturn 2\n \n-\tgit rebase--helper --check-todo-list || {\n+\tgit rebase--interactive --check-todo-list || {\n \t\tret=$?\n \t\tcheckout_onto\n \t\texit $ret\ndiff --git a/git.c b/git.c\nindex 2ffafefac3..e00e421e6f 100644\n--- a/git.c\n+++ b/git.c\n@@ -524,7 +524,6 @@ static struct cmd_struct commands[] = {\n \t{ \"range-diff\", cmd_range_diff, RUN_SETUP | USE_PAGER },\n \t{ \"read-tree\", cmd_read_tree, RUN_SETUP | SUPPORT_SUPER_PREFIX},\n \t{ \"rebase--interactive\", cmd_rebase__interactive, RUN_SETUP | NEED_WORK_TREE },\n-\t{ \"rebase--helper\", cmd_rebase__helper, RUN_SETUP | NEED_WORK_TREE },\n \t{ \"receive-pack\", cmd_receive_pack },\n \t{ \"reflog\", cmd_reflog, RUN_SETUP },\n \t{ \"remote\", cmd_remote, RUN_SETUP },\n-- \n2.19.0\n\n"}]}