{"thread":{"id":"49073","subject":"[GSoC] [PATCH 00/18] builtin rebase options","startedAt":"2018-08-08T15:22:40Z","lastAt":"2018-10-12T12:01:34Z","messageCount":44,"participants":["Pratik Karki","Duy Nguyen","Johannes Schindelin","Johannes Schindelin via GitGitGadget","Pratik Karki via GitGitGadget","Junio C Hamano"],"isPatch":true,"patchVersion":1,"patchTotal":18},"messages":[{"id":"354824","messageId":"20180808152140.14585-1-predatoramigo@gmail.com","threadId":"49073","inReplyTo":null,"subject":"[GSoC] [PATCH 00/18] builtin rebase options","fromName":"Pratik Karki","fromEmail":"predatoramigo@gmail.com","sentAt":"2018-08-08T15:21:22Z","receivedAt":"2018-08-08T15:22:40Z","isPatch":true,"sender":{"key":"predatoramigo@gmail.com","avatar":"https://avatars.githubusercontent.com/u/12194950?v=4"},"body":"This patch series completes the support for all rebase options in the\nbuiltin rebase. This converts the remaining command-line options.\n\nThe previous patch series taught the builtin rebase to handle different\nactions, this patch series will continue adding functionality to\nbuiltin rebase by teaching it to handle options handled by original rebase\ni.e. `--signoff`, `rerere-autoupdate`, et al.\n\nIt adds the functionality to the previous patch series,\n(https://public-inbox.org/git/20180808150622.9614-1-predatoramigo@gmail.com).\n\nThis is the fourth patch series that brings us more closer to a builtin\n\"git rebase\".\n\nIf you like to view the development branch, you can view\n(https://github.com/git/git/pull/505), where I have kept my commits up to date\nand leveraged Travis(there is sporadic failures in t5520 for macos gcc and\nisn't due to my patches) for extra testing other than my system.\n\nThe next in line patch series which I'll be sending out today are:\n\nbuiltin rebase rest: The builtin rebase will convert all the remaining shell\nscripts from the original rebase to C.\ndefault to builtin rebase: This will turn on the feature-complete builtin\nrebase to on.\n\nThese patch series are built on top of each other, i.e. they depend on this\norder.\n\nPratik Karki (18):\n  builtin rebase: allow selecting the rebase \"backend\"\n  builtin rebase: support --signoff\n  builtin rebase: support --rerere-autoupdate\n  builtin rebase: support --committer-date-is-author-date\n  builtin rebase: support `ignore-whitespace` option\n  builtin rebase: support `ignore-date` option\n  builtin rebase: support `keep-empty` option\n  builtin rebase: support `--autosquash`\n  builtin rebase: support `--gpg-sign` option\n  builtin rebase: support `-C` and `--whitespace=<type>`\n  builtin rebase: support `--autostash` option\n  builtin rebase: support `--exec`\n  builtin rebase: support `--allow-empty-message` option\n  builtin rebase: support --rebase-merges[=[no-]rebase-cousins]\n  merge-base --fork-point: extract libified function\n  builtin rebase: support `fork-point` option\n  builtin rebase: add support for custom merge strategies\n  builtin rebase: support --root\n\n builtin/merge-base.c |  81 +-------\n builtin/rebase.c     | 449 ++++++++++++++++++++++++++++++++++++++++++-\n commit.c             |  81 ++++++++\n commit.h             |   2 +\n 4 files changed, 528 insertions(+), 85 deletions(-)\n\n-- \n2.18.0\n\n"},{"id":"354825","messageId":"20180808152140.14585-2-predatoramigo@gmail.com","threadId":"49073","inReplyTo":"20180808152140.14585-1-predatoramigo@gmail.com","subject":"[PATCH 01/18] builtin rebase: allow selecting the rebase \"backend\"","fromName":"Pratik Karki","fromEmail":"predatoramigo@gmail.com","sentAt":"2018-08-08T15:21:23Z","receivedAt":"2018-08-08T15:22:44Z","isPatch":true,"sender":{"key":"predatoramigo@gmail.com","avatar":"https://avatars.githubusercontent.com/u/12194950?v=4"},"body":"With this commit the builtin rebase supports selecting the \"rebase\nbackends\" (or \"type\") `interactive`, `preserve-merges`, and `merge`.\n\nThe `state_dir` was already handled according to the rebase type in a\nprevious commit.\n\nNote that there is one quirk in the shell script: `--interactive`\nfollowed by `--merge` won't reset the type to \"merge\" but keeps the type\nas \"interactive\". And as t3418 tests this explicitly, we have to support\nit in the builtin rebase, too.\n\nLikewise, `--interactive` followed by `--preserve-merges` makes it an\n\"explicitly interactive\" rebase, i.e. a rebase that should show the todo\nlist, while `--preserve-merges` alone is not interactive (and t5520\ntests for this via `git pull --rebase=preserve`).\n\nSigned-off-by: Pratik Karki <predatoramigo@gmail.com>\n---\n builtin/rebase.c | 37 +++++++++++++++++++++++++++++++++++++\n 1 file changed, 37 insertions(+)\n\ndiff --git a/builtin/rebase.c b/builtin/rebase.c\nindex 75c4ac66e0..fc9b5a8a60 100644\n--- a/builtin/rebase.c\n+++ b/builtin/rebase.c\n@@ -452,6 +452,29 @@ static int can_fast_forward(struct commit *onto, struct object_id *head_oid,\n \treturn res && is_linear_history(onto, head);\n }\n \n+/* -i followed by -m is still -i */\n+static int parse_opt_merge(const struct option *opt, const char *arg, int unset)\n+{\n+\tstruct rebase_options *opts = opt->value;\n+\n+\tif (!is_interactive(opts))\n+\t\topts->type = REBASE_MERGE;\n+\n+\treturn 0;\n+}\n+\n+/* -i followed by -p is still explicitly interactive, but -p alone is not */\n+static int parse_opt_interactive(const struct option *opt, const char *arg,\n+\t\t\t\t int unset)\n+{\n+\tstruct rebase_options *opts = opt->value;\n+\n+\topts->type = REBASE_INTERACTIVE;\n+\topts->flags |= REBASE_INTERACTIVE_EXPLICIT;\n+\n+\treturn 0;\n+}\n+\n int cmd_rebase(int argc, const char **argv, const char *prefix)\n {\n \tstruct rebase_options options = {\n@@ -510,6 +533,17 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \t\tOPT_CMDMODE(0, \"show-current-patch\", &action,\n \t\t\t    N_(\"show the patch file being applied or merged\"),\n \t\t\t    ACTION_SHOW_CURRENT_PATCH),\n+\t\t{ OPTION_CALLBACK, 'm', \"merge\", &options, NULL,\n+\t\t\tN_(\"use merging strategies to rebase\"),\n+\t\t\tPARSE_OPT_NOARG | PARSE_OPT_NONEG,\n+\t\t\tparse_opt_merge },\n+\t\t{ OPTION_CALLBACK, 'i', \"interactive\", &options, NULL,\n+\t\t\tN_(\"let the user edit the list of commits to rebase\"),\n+\t\t\tPARSE_OPT_NOARG | PARSE_OPT_NONEG,\n+\t\t\tparse_opt_interactive },\n+\t\tOPT_SET_INT('p', \"preserve-merges\", &options.type,\n+\t\t\t    N_(\"try to recreate merges instead of ignoring \"\n+\t\t\t       \"them\"), REBASE_PRESERVE_MERGES),\n \t\tOPT_END(),\n \t};\n \n@@ -884,6 +918,9 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \t\tdiff_flush(&opts);\n \t}\n \n+\tif (is_interactive(&options))\n+\t\tgoto run_rebase;\n+\n \t/* Detach HEAD and reset the tree */\n \tif (options.flags & REBASE_NO_QUIET)\n \t\tprintf(_(\"First, rewinding head to replay your work on top of \"\n-- \n2.18.0\n\n"},{"id":"354827","messageId":"20180808152140.14585-3-predatoramigo@gmail.com","threadId":"49073","inReplyTo":"20180808152140.14585-1-predatoramigo@gmail.com","subject":"[PATCH 02/18] builtin rebase: support --signoff","fromName":"Pratik Karki","fromEmail":"predatoramigo@gmail.com","sentAt":"2018-08-08T15:21:24Z","receivedAt":"2018-08-08T15:22:47Z","isPatch":true,"sender":{"key":"predatoramigo@gmail.com","avatar":"https://avatars.githubusercontent.com/u/12194950?v=4"},"body":"This commit adds support for `--signoff` which is used to add a\n`Signed-off-by` trailer to all the rebased commits. The actual\nhandling is left to the rebase backends.\n\nSigned-off-by: Pratik Karki <predatoramigo@gmail.com>\n---\n builtin/rebase.c | 17 +++++++++++++++++\n 1 file changed, 17 insertions(+)\n\ndiff --git a/builtin/rebase.c b/builtin/rebase.c\nindex fc9b5a8a60..a491481120 100644\n--- a/builtin/rebase.c\n+++ b/builtin/rebase.c\n@@ -93,6 +93,7 @@ struct rebase_options {\n \t} flags;\n \tstruct strbuf git_am_opt;\n \tconst char *action;\n+\tint signoff;\n };\n \n static int is_interactive(struct rebase_options *opts)\n@@ -168,6 +169,11 @@ static int read_basic_state(struct rebase_options *opts)\n \tif (file_exists(state_dir_path(\"verbose\", opts)))\n \t\topts->flags |= REBASE_VERBOSE;\n \n+\tif (file_exists(state_dir_path(\"signoff\", opts))) {\n+\t\topts->signoff = 1;\n+\t\topts->flags |= REBASE_FORCE;\n+\t}\n+\n \tstrbuf_release(&buf);\n \n \treturn 0;\n@@ -249,6 +255,7 @@ static int run_specific_rebase(struct rebase_options *opts)\n \tif (opts->switch_to)\n \t\tadd_var(&script_snippet, \"switch_to\", opts->switch_to);\n \tadd_var(&script_snippet, \"action\", opts->action ? opts->action : \"\");\n+\tadd_var(&script_snippet, \"signoff\", opts->signoff ? \"--signoff\" : \"\");\n \n \tswitch (opts->type) {\n \tcase REBASE_AM:\n@@ -513,6 +520,8 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \t\t{OPTION_NEGBIT, 'n', \"no-stat\", &options.flags, NULL,\n \t\t\tN_(\"do not show diffstat of what changed upstream\"),\n \t\t\tPARSE_OPT_NOARG, NULL, REBASE_DIFFSTAT },\n+\t\tOPT_BOOL(0, \"signoff\", &options.signoff,\n+\t\t\t N_(\"add a Signed-off-by: line to each commit\")),\n \t\tOPT_BIT('f', \"force-rebase\", &options.flags,\n \t\t\tN_(\"cherry-pick all commits, even if unchanged\"),\n \t\t\tREBASE_FORCE),\n@@ -745,6 +754,14 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \t\tbreak;\n \t}\n \n+\tif (options.signoff) {\n+\t\tif (options.type == REBASE_PRESERVE_MERGES)\n+\t\t\tdie(\"cannot combine '--signoff' with \"\n+\t\t\t    \"'--preserve-merges'\");\n+\t\tstrbuf_addstr(&options.git_am_opt, \" --signoff\");\n+\t\toptions.flags |= REBASE_FORCE;\n+\t}\n+\n \tif (!options.root) {\n \t\tif (argc < 1)\n \t\t\tdie(\"TODO: handle @{upstream}\");\n-- \n2.18.0\n\n"},{"id":"354828","messageId":"20180808152140.14585-4-predatoramigo@gmail.com","threadId":"49073","inReplyTo":"20180808152140.14585-1-predatoramigo@gmail.com","subject":"[PATCH 03/18] builtin rebase: support --rerere-autoupdate","fromName":"Pratik Karki","fromEmail":"predatoramigo@gmail.com","sentAt":"2018-08-08T15:21:25Z","receivedAt":"2018-08-08T15:22:51Z","isPatch":true,"sender":{"key":"predatoramigo@gmail.com","avatar":"https://avatars.githubusercontent.com/u/12194950?v=4"},"body":"The `--rerere-autoupdate` option allows rerere to update the index with\nresolved conflicts. This commit follows closely the equivalent part of\n`git-legacy-rebase.sh`.\n\nSigned-off-by: Pratik Karki <predatoramigo@gmail.com>\n---\n builtin/rebase.c | 25 +++++++++++++++++++++++++\n 1 file changed, 25 insertions(+)\n\ndiff --git a/builtin/rebase.c b/builtin/rebase.c\nindex a491481120..1729d2d9e2 100644\n--- a/builtin/rebase.c\n+++ b/builtin/rebase.c\n@@ -94,6 +94,7 @@ struct rebase_options {\n \tstruct strbuf git_am_opt;\n \tconst char *action;\n \tint signoff;\n+\tint allow_rerere_autoupdate;\n };\n \n static int is_interactive(struct rebase_options *opts)\n@@ -174,6 +175,21 @@ static int read_basic_state(struct rebase_options *opts)\n \t\topts->flags |= REBASE_FORCE;\n \t}\n \n+\tif (file_exists(state_dir_path(\"allow_rerere_autoupdate\", opts))) {\n+\t\tstrbuf_reset(&buf);\n+\t\tif (read_one(state_dir_path(\"allow_rerere_autoupdate\", opts),\n+\t\t\t    &buf))\n+\t\t\treturn -1;\n+\t\tif (!strcmp(buf.buf, \"--rerere-autoupdate\"))\n+\t\t\topts->allow_rerere_autoupdate = 1;\n+\t\telse if (!strcmp(buf.buf, \"--no-rerere-autoupdate\"))\n+\t\t\topts->allow_rerere_autoupdate = 0;\n+\t\telse\n+\t\t\twarning(_(\"ignoring invalid allow_rerere_autoupdate: \"\n+\t\t\t\t  \"'%s'\"), buf.buf);\n+\t} else\n+\t\topts->allow_rerere_autoupdate = -1;\n+\n \tstrbuf_release(&buf);\n \n \treturn 0;\n@@ -256,6 +272,10 @@ static int run_specific_rebase(struct rebase_options *opts)\n \t\tadd_var(&script_snippet, \"switch_to\", opts->switch_to);\n \tadd_var(&script_snippet, \"action\", opts->action ? opts->action : \"\");\n \tadd_var(&script_snippet, \"signoff\", opts->signoff ? \"--signoff\" : \"\");\n+\tadd_var(&script_snippet, \"allow_rerere_autoupdate\",\n+\t\topts->allow_rerere_autoupdate < 0 ? \"\" :\n+\t\topts->allow_rerere_autoupdate ?\n+\t\t\"--rerere-autoupdate\" : \"--no-rerere-autoupdate\");\n \n \tswitch (opts->type) {\n \tcase REBASE_AM:\n@@ -488,6 +508,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \t\t.type = REBASE_UNSPECIFIED,\n \t\t.flags = REBASE_NO_QUIET,\n \t\t.git_am_opt = STRBUF_INIT,\n+\t\t.allow_rerere_autoupdate  = -1,\n \t};\n \tconst char *branch_name;\n \tint ret, flags, total_argc, in_progress = 0;\n@@ -553,6 +574,10 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \t\tOPT_SET_INT('p', \"preserve-merges\", &options.type,\n \t\t\t    N_(\"try to recreate merges instead of ignoring \"\n \t\t\t       \"them\"), REBASE_PRESERVE_MERGES),\n+\t\tOPT_BOOL(0, \"rerere-autoupdate\",\n+\t\t\t &options.allow_rerere_autoupdate,\n+\t\t\t N_(\"allow rerere to update index  with resolved \"\n+\t\t\t    \"conflict\")),\n \t\tOPT_END(),\n \t};\n \n-- \n2.18.0\n\n"},{"id":"354829","messageId":"20180808152140.14585-5-predatoramigo@gmail.com","threadId":"49073","inReplyTo":"20180808152140.14585-1-predatoramigo@gmail.com","subject":"[PATCH 04/18] builtin rebase: support --committer-date-is-author-date","fromName":"Pratik Karki","fromEmail":"predatoramigo@gmail.com","sentAt":"2018-08-08T15:21:26Z","receivedAt":"2018-08-08T15:22:55Z","isPatch":true,"sender":{"key":"predatoramigo@gmail.com","avatar":"https://avatars.githubusercontent.com/u/12194950?v=4"},"body":"This option is simply handed down to `git am` by way of setting the\n`git_am_opt` variable that is handled by the `git-rebase--am` backend.\n\nSigned-off-by: Pratik Karki <predatoramigo@gmail.com>\n---\n builtin/rebase.c | 10 ++++++++++\n 1 file changed, 10 insertions(+)\n\ndiff --git a/builtin/rebase.c b/builtin/rebase.c\nindex 1729d2d9e2..eef16206c2 100644\n--- a/builtin/rebase.c\n+++ b/builtin/rebase.c\n@@ -526,6 +526,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \t\tACTION_EDIT_TODO,\n \t\tACTION_SHOW_CURRENT_PATCH,\n \t} action = NO_ACTION;\n+\tint committer_date_is_author_date = 0;\n \tstruct option builtin_rebase_options[] = {\n \t\tOPT_STRING(0, \"onto\", &options.onto_name,\n \t\t\t   N_(\"revision\"),\n@@ -543,6 +544,9 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \t\t\tPARSE_OPT_NOARG, NULL, REBASE_DIFFSTAT },\n \t\tOPT_BOOL(0, \"signoff\", &options.signoff,\n \t\t\t N_(\"add a Signed-off-by: line to each commit\")),\n+\t\tOPT_BOOL(0, \"committer-date-is-author-date\",\n+\t\t\t &committer_date_is_author_date,\n+\t\t\t N_(\"passed to 'git am'\")),\n \t\tOPT_BIT('f', \"force-rebase\", &options.flags,\n \t\t\tN_(\"cherry-pick all commits, even if unchanged\"),\n \t\t\tREBASE_FORCE),\n@@ -763,6 +767,12 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \tif (!(options.flags & REBASE_NO_QUIET))\n \t\tstrbuf_addstr(&options.git_am_opt, \" -q\");\n \n+\tif (committer_date_is_author_date) {\n+\t\tstrbuf_addstr(&options.git_am_opt,\n+\t\t\t      \" --committer-date-is-author-date\");\n+\t\toptions.flags |= REBASE_FORCE;\n+\t}\n+\n \tswitch (options.type) {\n \tcase REBASE_MERGE:\n \tcase REBASE_INTERACTIVE:\n-- \n2.18.0\n\n"},{"id":"354830","messageId":"20180808152140.14585-6-predatoramigo@gmail.com","threadId":"49073","inReplyTo":"20180808152140.14585-1-predatoramigo@gmail.com","subject":"[PATCH 05/18] builtin rebase: support `ignore-whitespace` option","fromName":"Pratik Karki","fromEmail":"predatoramigo@gmail.com","sentAt":"2018-08-08T15:21:27Z","receivedAt":"2018-08-08T15:22:58Z","isPatch":true,"sender":{"key":"predatoramigo@gmail.com","avatar":"https://avatars.githubusercontent.com/u/12194950?v=4"},"body":"This commit adds support for the `--ignore-whitespace` option\nof the rebase command. This option is simply passed to the\n`--am` backend.\n\nSigned-off-by: Pratik Karki <predatoramigo@gmail.com>\n---\n builtin/rebase.c | 6 ++++++\n 1 file changed, 6 insertions(+)\n\ndiff --git a/builtin/rebase.c b/builtin/rebase.c\nindex eef16206c2..7490d215ef 100644\n--- a/builtin/rebase.c\n+++ b/builtin/rebase.c\n@@ -527,6 +527,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \t\tACTION_SHOW_CURRENT_PATCH,\n \t} action = NO_ACTION;\n \tint committer_date_is_author_date = 0;\n+\tint ignore_whitespace = 0;\n \tstruct option builtin_rebase_options[] = {\n \t\tOPT_STRING(0, \"onto\", &options.onto_name,\n \t\t\t   N_(\"revision\"),\n@@ -542,6 +543,8 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \t\t{OPTION_NEGBIT, 'n', \"no-stat\", &options.flags, NULL,\n \t\t\tN_(\"do not show diffstat of what changed upstream\"),\n \t\t\tPARSE_OPT_NOARG, NULL, REBASE_DIFFSTAT },\n+\t\tOPT_BOOL(0, \"ignore-whitespace\", &ignore_whitespace,\n+\t\t\t N_(\"passed to 'git apply'\")),\n \t\tOPT_BOOL(0, \"signoff\", &options.signoff,\n \t\t\t N_(\"add a Signed-off-by: line to each commit\")),\n \t\tOPT_BOOL(0, \"committer-date-is-author-date\",\n@@ -773,6 +776,9 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \t\toptions.flags |= REBASE_FORCE;\n \t}\n \n+\tif (ignore_whitespace)\n+\t\tstrbuf_addstr(&options.git_am_opt, \" --ignore-whitespace\");\n+\n \tswitch (options.type) {\n \tcase REBASE_MERGE:\n \tcase REBASE_INTERACTIVE:\n-- \n2.18.0\n\n"},{"id":"354831","messageId":"20180808152140.14585-7-predatoramigo@gmail.com","threadId":"49073","inReplyTo":"20180808152140.14585-1-predatoramigo@gmail.com","subject":"[PATCH 06/18] builtin rebase: support `ignore-date` option","fromName":"Pratik Karki","fromEmail":"predatoramigo@gmail.com","sentAt":"2018-08-08T15:21:28Z","receivedAt":"2018-08-08T15:23:02Z","isPatch":true,"sender":{"key":"predatoramigo@gmail.com","avatar":"https://avatars.githubusercontent.com/u/12194950?v=4"},"body":"This commit adds support for `--ignore-date` which is passed to `git am`\nto easily change the dates of the rebased commits.\n\nSigned-off-by: Pratik Karki <predatoramigo@gmail.com>\n---\n builtin/rebase.c | 8 ++++++++\n 1 file changed, 8 insertions(+)\n\ndiff --git a/builtin/rebase.c b/builtin/rebase.c\nindex 7490d215ef..42ee040da3 100644\n--- a/builtin/rebase.c\n+++ b/builtin/rebase.c\n@@ -527,6 +527,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \t\tACTION_SHOW_CURRENT_PATCH,\n \t} action = NO_ACTION;\n \tint committer_date_is_author_date = 0;\n+\tint ignore_date = 0;\n \tint ignore_whitespace = 0;\n \tstruct option builtin_rebase_options[] = {\n \t\tOPT_STRING(0, \"onto\", &options.onto_name,\n@@ -550,6 +551,8 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \t\tOPT_BOOL(0, \"committer-date-is-author-date\",\n \t\t\t &committer_date_is_author_date,\n \t\t\t N_(\"passed to 'git am'\")),\n+\t\tOPT_BOOL(0, \"ignore-date\", &ignore_date,\n+\t\t\t N_(\"passed to 'git am'\")),\n \t\tOPT_BIT('f', \"force-rebase\", &options.flags,\n \t\t\tN_(\"cherry-pick all commits, even if unchanged\"),\n \t\t\tREBASE_FORCE),\n@@ -779,6 +782,11 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \tif (ignore_whitespace)\n \t\tstrbuf_addstr(&options.git_am_opt, \" --ignore-whitespace\");\n \n+\tif (ignore_date) {\n+\t\tstrbuf_addstr(&options.git_am_opt, \" --ignore-date\");\n+\t\toptions.flags |= REBASE_FORCE;\n+\t}\n+\n \tswitch (options.type) {\n \tcase REBASE_MERGE:\n \tcase REBASE_INTERACTIVE:\n-- \n2.18.0\n\n"},{"id":"354832","messageId":"20180808152140.14585-8-predatoramigo@gmail.com","threadId":"49073","inReplyTo":"20180808152140.14585-1-predatoramigo@gmail.com","subject":"[PATCH 07/18] builtin rebase: support `keep-empty` option","fromName":"Pratik Karki","fromEmail":"predatoramigo@gmail.com","sentAt":"2018-08-08T15:21:29Z","receivedAt":"2018-08-08T15:23:06Z","isPatch":true,"sender":{"key":"predatoramigo@gmail.com","avatar":"https://avatars.githubusercontent.com/u/12194950?v=4"},"body":"The `--keep-empty` option can be used to keep the commits that do not\nchange anything from its parents in the result.\n\nWhile the scripted version uses `interactive_rebase=implied` to indicate\nthat the rebase needs to use the `git-rebase--interactive` backend in\nnon-interactive mode as fallback when figuring out which backend to use,\nthe C version needs to use a different route because the backend will\nalready be chosen during the `parse_options()` call.\n\nSigned-off-by: Pratik Karki <predatoramigo@gmail.com>\n---\n builtin/rebase.c | 24 ++++++++++++++++++++++++\n 1 file changed, 24 insertions(+)\n\ndiff --git a/builtin/rebase.c b/builtin/rebase.c\nindex 42ee040da3..fd9ad8efae 100644\n--- a/builtin/rebase.c\n+++ b/builtin/rebase.c\n@@ -95,6 +95,7 @@ struct rebase_options {\n \tconst char *action;\n \tint signoff;\n \tint allow_rerere_autoupdate;\n+\tint keep_empty;\n };\n \n static int is_interactive(struct rebase_options *opts)\n@@ -103,6 +104,23 @@ static int is_interactive(struct rebase_options *opts)\n \t\topts->type == REBASE_PRESERVE_MERGES;\n }\n \n+static void imply_interactive(struct rebase_options *opts, const char *option)\n+{\n+\tswitch (opts->type) {\n+\tcase REBASE_AM:\n+\t\tdie(_(\"%s requires an interactive rebase\"), option);\n+\t\tbreak;\n+\tcase REBASE_INTERACTIVE:\n+\tcase REBASE_PRESERVE_MERGES:\n+\t\tbreak;\n+\tcase REBASE_MERGE:\n+\t\t/* we silently *upgrade* --merge to --interactive if needed */\n+\tdefault:\n+\t\topts->type = REBASE_INTERACTIVE; /* implied */\n+\t\tbreak;\n+\t}\n+}\n+\n /* Returns the filename prefixed by the state_dir */\n static const char *state_dir_path(const char *filename, struct rebase_options *opts)\n {\n@@ -276,6 +294,7 @@ static int run_specific_rebase(struct rebase_options *opts)\n \t\topts->allow_rerere_autoupdate < 0 ? \"\" :\n \t\topts->allow_rerere_autoupdate ?\n \t\t\"--rerere-autoupdate\" : \"--no-rerere-autoupdate\");\n+\tadd_var(&script_snippet, \"keep_empty\", opts->keep_empty ? \"yes\" : \"\");\n \n \tswitch (opts->type) {\n \tcase REBASE_AM:\n@@ -588,6 +607,8 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \t\t\t &options.allow_rerere_autoupdate,\n \t\t\t N_(\"allow rerere to update index  with resolved \"\n \t\t\t    \"conflict\")),\n+\t\tOPT_BOOL(0, \"keep-empty\", &options.keep_empty,\n+\t\t\t N_(\"preserve empty commits during rebase\")),\n \t\tOPT_END(),\n \t};\n \n@@ -787,6 +808,9 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \t\toptions.flags |= REBASE_FORCE;\n \t}\n \n+\tif (options.keep_empty)\n+\t\timply_interactive(&options, \"--keep-empty\");\n+\n \tswitch (options.type) {\n \tcase REBASE_MERGE:\n \tcase REBASE_INTERACTIVE:\n-- \n2.18.0\n\n"},{"id":"354833","messageId":"20180808152140.14585-9-predatoramigo@gmail.com","threadId":"49073","inReplyTo":"20180808152140.14585-1-predatoramigo@gmail.com","subject":"[PATCH 08/18] builtin rebase: support `--autosquash`","fromName":"Pratik Karki","fromEmail":"predatoramigo@gmail.com","sentAt":"2018-08-08T15:21:30Z","receivedAt":"2018-08-08T15:23:10Z","isPatch":true,"sender":{"key":"predatoramigo@gmail.com","avatar":"https://avatars.githubusercontent.com/u/12194950?v=4"},"body":"This commit adds support for the `--autosquash` option which is used to\nautomatically squash the commits marked as `squash` or `fixup` in their\nmessages. This is converted following `git-legacy-rebase.sh` closely.\n\nThis option can also be configured via the Git config setting\nrebase.autosquash. To support this, we also add a custom\nrebase_config() function in this commit that will be used instead (and\nfalls back to) git_default_config().\n\nSigned-off-by: Pratik Karki <predatoramigo@gmail.com>\n---\n builtin/rebase.c | 10 ++++++++++\n 1 file changed, 10 insertions(+)\n\ndiff --git a/builtin/rebase.c b/builtin/rebase.c\nindex fd9ad8efae..79ba65fd75 100644\n--- a/builtin/rebase.c\n+++ b/builtin/rebase.c\n@@ -96,6 +96,7 @@ struct rebase_options {\n \tint signoff;\n \tint allow_rerere_autoupdate;\n \tint keep_empty;\n+\tint autosquash;\n };\n \n static int is_interactive(struct rebase_options *opts)\n@@ -295,6 +296,7 @@ static int run_specific_rebase(struct rebase_options *opts)\n \t\topts->allow_rerere_autoupdate ?\n \t\t\"--rerere-autoupdate\" : \"--no-rerere-autoupdate\");\n \tadd_var(&script_snippet, \"keep_empty\", opts->keep_empty ? \"yes\" : \"\");\n+\tadd_var(&script_snippet, \"autosquash\", opts->autosquash ? \"t\" : \"\");\n \n \tswitch (opts->type) {\n \tcase REBASE_AM:\n@@ -455,6 +457,11 @@ static int rebase_config(const char *var, const char *value, void *data)\n \t\treturn 0;\n \t}\n \n+\tif (!strcmp(var, \"rebase.autosquash\")) {\n+\t\topts->autosquash = git_config_bool(var, value);\n+\t\treturn 0;\n+\t}\n+\n \treturn git_default_config(var, value, data);\n }\n \n@@ -609,6 +616,9 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \t\t\t    \"conflict\")),\n \t\tOPT_BOOL(0, \"keep-empty\", &options.keep_empty,\n \t\t\t N_(\"preserve empty commits during rebase\")),\n+\t\tOPT_BOOL(0, \"autosquash\", &options.autosquash,\n+\t\t\t N_(\"move commits that begin with \"\n+\t\t\t    \"squash!/fixup! under -i\")),\n \t\tOPT_END(),\n \t};\n \n-- \n2.18.0\n\n"},{"id":"354834","messageId":"20180808152140.14585-10-predatoramigo@gmail.com","threadId":"49073","inReplyTo":"20180808152140.14585-1-predatoramigo@gmail.com","subject":"[PATCH 09/18] builtin rebase: support `--gpg-sign` option","fromName":"Pratik Karki","fromEmail":"predatoramigo@gmail.com","sentAt":"2018-08-08T15:21:31Z","receivedAt":"2018-08-08T15:23:14Z","isPatch":true,"sender":{"key":"predatoramigo@gmail.com","avatar":"https://avatars.githubusercontent.com/u/12194950?v=4"},"body":"This commit introduces support for `--gpg-sign` option which is used\nto GPG-sign commits.\n\nSigned-off-by: Pratik Karki <predatoramigo@gmail.com>\n---\n builtin/rebase.c | 27 +++++++++++++++++++++++++++\n 1 file changed, 27 insertions(+)\n\ndiff --git a/builtin/rebase.c b/builtin/rebase.c\nindex 79ba65fd75..cd9caf4841 100644\n--- a/builtin/rebase.c\n+++ b/builtin/rebase.c\n@@ -97,6 +97,7 @@ struct rebase_options {\n \tint allow_rerere_autoupdate;\n \tint keep_empty;\n \tint autosquash;\n+\tchar *gpg_sign_opt;\n };\n \n static int is_interactive(struct rebase_options *opts)\n@@ -209,6 +210,15 @@ static int read_basic_state(struct rebase_options *opts)\n \t} else\n \t\topts->allow_rerere_autoupdate = -1;\n \n+\tif (file_exists(state_dir_path(\"gpg_sign_opt\", opts))) {\n+\t\tstrbuf_reset(&buf);\n+\t\tif (read_one(state_dir_path(\"gpg_sign_opt\", opts),\n+\t\t\t    &buf))\n+\t\t\treturn -1;\n+\t\tfree(opts->gpg_sign_opt);\n+\t\topts->gpg_sign_opt = xstrdup(buf.buf);\n+\t}\n+\n \tstrbuf_release(&buf);\n \n \treturn 0;\n@@ -297,6 +307,7 @@ static int run_specific_rebase(struct rebase_options *opts)\n \t\t\"--rerere-autoupdate\" : \"--no-rerere-autoupdate\");\n \tadd_var(&script_snippet, \"keep_empty\", opts->keep_empty ? \"yes\" : \"\");\n \tadd_var(&script_snippet, \"autosquash\", opts->autosquash ? \"t\" : \"\");\n+\tadd_var(&script_snippet, \"gpg_sign_opt\", opts->gpg_sign_opt);\n \n \tswitch (opts->type) {\n \tcase REBASE_AM:\n@@ -462,6 +473,13 @@ static int rebase_config(const char *var, const char *value, void *data)\n \t\treturn 0;\n \t}\n \n+\tif (!strcmp(var, \"commit.gpgsign\")) {\n+\t\tfree(opts->gpg_sign_opt);\n+\t\topts->gpg_sign_opt = git_config_bool(var, value) ?\n+\t\t\txstrdup(\"-S\") : NULL;\n+\t\treturn 0;\n+\t}\n+\n \treturn git_default_config(var, value, data);\n }\n \n@@ -555,6 +573,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \tint committer_date_is_author_date = 0;\n \tint ignore_date = 0;\n \tint ignore_whitespace = 0;\n+\tconst char *gpg_sign = NULL;\n \tstruct option builtin_rebase_options[] = {\n \t\tOPT_STRING(0, \"onto\", &options.onto_name,\n \t\t\t   N_(\"revision\"),\n@@ -619,6 +638,8 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \t\tOPT_BOOL(0, \"autosquash\", &options.autosquash,\n \t\t\t N_(\"move commits that begin with \"\n \t\t\t    \"squash!/fixup! under -i\")),\n+\t\tOPT_STRING('S', \"gpg-sign\", &gpg_sign,\n+\t\t\t   N_(\"gpg-sign?\"), N_(\"GPG-sign commits\")),\n \t\tOPT_END(),\n \t};\n \n@@ -821,6 +842,11 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \tif (options.keep_empty)\n \t\timply_interactive(&options, \"--keep-empty\");\n \n+\tif (gpg_sign) {\n+\t\tfree(options.gpg_sign_opt);\n+\t\toptions.gpg_sign_opt = xstrfmt(\"-S%s\", gpg_sign);\n+\t}\n+\n \tswitch (options.type) {\n \tcase REBASE_MERGE:\n \tcase REBASE_INTERACTIVE:\n@@ -1046,5 +1072,6 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n cleanup:\n \tstrbuf_release(&revisions);\n \tfree(options.head_name);\n+\tfree(options.gpg_sign_opt);\n \treturn ret;\n }\n-- \n2.18.0\n\n"},{"id":"354835","messageId":"20180808152140.14585-11-predatoramigo@gmail.com","threadId":"49073","inReplyTo":"20180808152140.14585-1-predatoramigo@gmail.com","subject":"[PATCH 10/18] builtin rebase: support `-C` and `--whitespace=<type>`","fromName":"Pratik Karki","fromEmail":"predatoramigo@gmail.com","sentAt":"2018-08-08T15:21:32Z","receivedAt":"2018-08-08T15:23:18Z","isPatch":true,"sender":{"key":"predatoramigo@gmail.com","avatar":"https://avatars.githubusercontent.com/u/12194950?v=4"},"body":"This commit converts more code from the shell script version to the\nbuiltin rebase. In this instance, we just have to be careful to\nkeep support for passing multiple `--whitespace` options, as the\nshell script version does so, too.\n\nSigned-off-by: Pratik Karki <predatoramigo@gmail.com>\n---\n builtin/rebase.c | 23 +++++++++++++++++++++++\n 1 file changed, 23 insertions(+)\n\ndiff --git a/builtin/rebase.c b/builtin/rebase.c\nindex cd9caf4841..4437c86513 100644\n--- a/builtin/rebase.c\n+++ b/builtin/rebase.c\n@@ -574,6 +574,8 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \tint ignore_date = 0;\n \tint ignore_whitespace = 0;\n \tconst char *gpg_sign = NULL;\n+\tint opt_c = -1;\n+\tstruct string_list whitespace = STRING_LIST_INIT_NODUP;\n \tstruct option builtin_rebase_options[] = {\n \t\tOPT_STRING(0, \"onto\", &options.onto_name,\n \t\t\t   N_(\"revision\"),\n@@ -640,6 +642,10 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \t\t\t    \"squash!/fixup! under -i\")),\n \t\tOPT_STRING('S', \"gpg-sign\", &gpg_sign,\n \t\t\t   N_(\"gpg-sign?\"), N_(\"GPG-sign commits\")),\n+\t\tOPT_STRING_LIST(0, \"whitespace\", &whitespace,\n+\t\t\t\tN_(\"whitespace\"), N_(\"passed to 'git apply'\")),\n+\t\tOPT_SET_INT('C', 0, &opt_c, N_(\"passed to 'git apply'\"),\n+\t\t\t    REBASE_AM),\n \t\tOPT_END(),\n \t};\n \n@@ -847,6 +853,23 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \t\toptions.gpg_sign_opt = xstrfmt(\"-S%s\", gpg_sign);\n \t}\n \n+\tif (opt_c >= 0)\n+\t\tstrbuf_addf(&options.git_am_opt, \" -C%d\", opt_c);\n+\n+\tif (whitespace.nr) {\n+\t\tint i;\n+\n+\t\tfor (i = 0; i < whitespace.nr; i++) {\n+\t\t\tconst char *item = whitespace.items[i].string;\n+\n+\t\t\tstrbuf_addf(&options.git_am_opt, \" --whitespace=%s\",\n+\t\t\t\t    item);\n+\n+\t\t\tif ((!strcmp(item, \"fix\")) || (!strcmp(item, \"strip\")))\n+\t\t\t\toptions.flags |= REBASE_FORCE;\n+\t\t}\n+\t}\n+\n \tswitch (options.type) {\n \tcase REBASE_MERGE:\n \tcase REBASE_INTERACTIVE:\n-- \n2.18.0\n\n"},{"id":"354836","messageId":"20180808152140.14585-12-predatoramigo@gmail.com","threadId":"49073","inReplyTo":"20180808152140.14585-1-predatoramigo@gmail.com","subject":"[PATCH 11/18] builtin rebase: support `--autostash` option","fromName":"Pratik Karki","fromEmail":"predatoramigo@gmail.com","sentAt":"2018-08-08T15:21:33Z","receivedAt":"2018-08-08T15:23:21Z","isPatch":true,"sender":{"key":"predatoramigo@gmail.com","avatar":"https://avatars.githubusercontent.com/u/12194950?v=4"},"body":"To support `--autostash` we introduce a function `apply_autostash()`\njust like in `git-legacy-rebase.sh`.\n\nRather than refactoring and using the same function that exists in\n`sequencer.c`, we go a different route here, to avoid clashes with\nthe sister GSoC project that turns the interactive rebase into a\nbuiltin.\n\nSigned-off-by: Pratik Karki <predatoramigo@gmail.com>\n---\n builtin/rebase.c | 117 +++++++++++++++++++++++++++++++++++++++++++----\n 1 file changed, 109 insertions(+), 8 deletions(-)\n\ndiff --git a/builtin/rebase.c b/builtin/rebase.c\nindex 4437c86513..a6bfa73915 100644\n--- a/builtin/rebase.c\n+++ b/builtin/rebase.c\n@@ -63,12 +63,6 @@ static int use_builtin_rebase(void)\n \treturn ret;\n }\n \n-static int apply_autostash(void)\n-{\n-\twarning(\"TODO\");\n-\treturn 0;\n-}\n-\n struct rebase_options {\n \tenum rebase_type type;\n \tconst char *state_dir;\n@@ -98,6 +92,7 @@ struct rebase_options {\n \tint keep_empty;\n \tint autosquash;\n \tchar *gpg_sign_opt;\n+\tint autostash;\n };\n \n static int is_interactive(struct rebase_options *opts)\n@@ -224,13 +219,56 @@ static int read_basic_state(struct rebase_options *opts)\n \treturn 0;\n }\n \n+static int apply_autostash(struct rebase_options *opts)\n+{\n+\tconst char *path = state_dir_path(\"autostash\", opts);\n+\tstruct strbuf autostash = STRBUF_INIT;\n+\tstruct child_process stash_apply = CHILD_PROCESS_INIT;\n+\n+\tif (!file_exists(path))\n+\t\treturn 0;\n+\n+\tif (read_one(state_dir_path(\"autostash\", opts), &autostash))\n+\t\treturn error(_(\"Could not read '%s'\"), path);\n+\targv_array_pushl(&stash_apply.args,\n+\t\t\t \"stash\", \"apply\", autostash.buf, NULL);\n+\tstash_apply.git_cmd = 1;\n+\tstash_apply.no_stderr = stash_apply.no_stdout =\n+\t\tstash_apply.no_stdin = 1;\n+\tif (!run_command(&stash_apply))\n+\t\tprintf(\"Applied autostash.\\n\");\n+\telse {\n+\t\tstruct argv_array args = ARGV_ARRAY_INIT;\n+\t\tint res = 0;\n+\n+\t\targv_array_pushl(&args,\n+\t\t\t\t \"stash\", \"store\", \"-m\", \"autostash\", \"-q\",\n+\t\t\t\t autostash.buf, NULL);\n+\t\tif (run_command_v_opt(args.argv, RUN_GIT_CMD))\n+\t\t\tres = error(_(\"Cannot store %s\"), autostash.buf);\n+\t\targv_array_clear(&args);\n+\t\tstrbuf_release(&autostash);\n+\t\tif (res)\n+\t\t\treturn res;\n+\n+\t\tfprintf(stderr,\n+\t\t\t_(\"Applying autostash resulted in conflicts.\\n\"\n+\t\t\t  \"Your changes are safe in the stash.\\n\"\n+\t\t\t  \"You can run \\\"git stash pop\\\" or \\\"git stash drop\\\" \"\n+\t\t\t  \"at any time.\\n\"));\n+\t}\n+\n+\tstrbuf_release(&autostash);\n+\treturn 0;\n+}\n+\n static int finish_rebase(struct rebase_options *opts)\n {\n \tstruct strbuf dir = STRBUF_INIT;\n \tconst char *argv_gc_auto[] = { \"gc\", \"--auto\", NULL };\n \n \tdelete_ref(NULL, \"REBASE_HEAD\", NULL, REF_NO_DEREF);\n-\tapply_autostash();\n+\tapply_autostash(opts);\n \tclose_all_packs(the_repository->objects);\n \t/*\n \t * We ignore errors in 'gc --auto', since the\n@@ -345,7 +383,7 @@ static int run_specific_rebase(struct rebase_options *opts)\n \t} else if (status == 2) {\n \t\tstruct strbuf dir = STRBUF_INIT;\n \n-\t\tapply_autostash();\n+\t\tapply_autostash(opts);\n \t\tstrbuf_addstr(&dir, opts->state_dir);\n \t\tremove_dir_recursively(&dir, 0);\n \t\tstrbuf_release(&dir);\n@@ -480,6 +518,11 @@ static int rebase_config(const char *var, const char *value, void *data)\n \t\treturn 0;\n \t}\n \n+\tif (!strcmp(var, \"rebase.autostash\")) {\n+\t\topts->autostash = git_config_bool(var, value);\n+\t\treturn 0;\n+\t}\n+\n \treturn git_default_config(var, value, data);\n }\n \n@@ -646,6 +689,8 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \t\t\t\tN_(\"whitespace\"), N_(\"passed to 'git apply'\")),\n \t\tOPT_SET_INT('C', 0, &opt_c, N_(\"passed to 'git apply'\"),\n \t\t\t    REBASE_AM),\n+\t\tOPT_BOOL(0, \"autostash\", &options.autostash,\n+\t\t\t N_(\"automatically stash/stash pop before and after\")),\n \t\tOPT_END(),\n \t};\n \n@@ -975,6 +1020,62 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \tif (read_index(the_repository->index) < 0)\n \t\tdie(_(\"could not read index\"));\n \n+\tif (options.autostash) {\n+\t\tstruct lock_file lock_file = LOCK_INIT;\n+\t\tint fd;\n+\n+\t\tfd = hold_locked_index(&lock_file, 0);\n+\t\trefresh_cache(REFRESH_QUIET);\n+\t\tif (0 <= fd)\n+\t\t\tupdate_index_if_able(&the_index, &lock_file);\n+\t\trollback_lock_file(&lock_file);\n+\n+\t\tif (has_unstaged_changes(0) || has_uncommitted_changes(0)) {\n+\t\t\tconst char *autostash =\n+\t\t\t\tstate_dir_path(\"autostash\", &options);\n+\t\t\tstruct child_process stash = CHILD_PROCESS_INIT;\n+\t\t\tstruct object_id oid;\n+\t\t\tstruct commit *head =\n+\t\t\t\tlookup_commit_reference(the_repository,\n+\t\t\t\t\t\t\t&options.orig_head);\n+\n+\t\t\targv_array_pushl(&stash.args,\n+\t\t\t\t\t \"stash\", \"create\", \"autostash\", NULL);\n+\t\t\tstash.git_cmd = 1;\n+\t\t\tstash.no_stdin = 1;\n+\t\t\tstrbuf_reset(&buf);\n+\t\t\tif (capture_command(&stash, &buf, GIT_MAX_HEXSZ))\n+\t\t\t\tdie(_(\"Cannot autostash\"));\n+\t\t\tstrbuf_trim_trailing_newline(&buf);\n+\t\t\tif (get_oid(buf.buf, &oid))\n+\t\t\t\tdie(_(\"Unexpected stash response: '%s'\"),\n+\t\t\t\t    buf.buf);\n+\t\t\tstrbuf_reset(&buf);\n+\t\t\tstrbuf_add_unique_abbrev(&buf, &oid, DEFAULT_ABBREV);\n+\n+\t\t\tif (safe_create_leading_directories_const(autostash))\n+\t\t\t\tdie(_(\"Could not create directory for '%s'\"),\n+\t\t\t\t    options.state_dir);\n+\t\t\twrite_file(autostash, \"%s\", buf.buf);\n+\t\t\tprintf(_(\"Created autostash: %s\\n\"), buf.buf);\n+\t\t\tif (reset_head(&head->object.oid, \"reset --hard\",\n+\t\t\t\t       NULL, 0) < 0)\n+\t\t\t\tdie(_(\"could not reset --hard\"));\n+\t\t\tprintf(_(\"HEAD is now at %s\"),\n+\t\t\t       find_unique_abbrev(&head->object.oid,\n+\t\t\t\t\t\t  DEFAULT_ABBREV));\n+\t\t\tstrbuf_reset(&buf);\n+\t\t\tpp_commit_easy(CMIT_FMT_ONELINE, head, &buf);\n+\t\t\tif (buf.len > 0)\n+\t\t\t\tprintf(\" %s\", buf.buf);\n+\t\t\tputchar('\\n');\n+\n+\t\t\tif (discard_index(the_repository->index) < 0 ||\n+\t\t\t\tread_index(the_repository->index) < 0)\n+\t\t\t\tdie(_(\"could not read index\"));\n+\t\t}\n+\t}\n+\n \tif (require_clean_work_tree(\"rebase\",\n \t\t\t\t    _(\"Please commit or stash them.\"), 1, 1)) {\n \t\tret = 1;\n-- \n2.18.0\n\n"},{"id":"354837","messageId":"20180808152140.14585-13-predatoramigo@gmail.com","threadId":"49073","inReplyTo":"20180808152140.14585-1-predatoramigo@gmail.com","subject":"[PATCH 12/18] builtin rebase: support `--exec`","fromName":"Pratik Karki","fromEmail":"predatoramigo@gmail.com","sentAt":"2018-08-08T15:21:34Z","receivedAt":"2018-08-08T15:23:24Z","isPatch":true,"sender":{"key":"predatoramigo@gmail.com","avatar":"https://avatars.githubusercontent.com/u/12194950?v=4"},"body":"This commit adds support for the `--exec` option which takes a shell\ncommand-line as argument. This argument will be appended as an `exec\n<cmd>` command after each line in the todo list that creates a commit in\nthe final history.  commands.\n\nNote: while the shell script version of `git rebase` assigned the empty\nstring to `cmd` by default, we *unset* it here because the code looks\nnicer and it does not change the behavior.\n\nThe `--exec` option requires `--interactive` machinery.\n\nSigned-off-by: Pratik Karki <predatoramigo@gmail.com>\n---\n builtin/rebase.c | 18 ++++++++++++++++++\n 1 file changed, 18 insertions(+)\n\ndiff --git a/builtin/rebase.c b/builtin/rebase.c\nindex a6bfa73915..c9e992b526 100644\n--- a/builtin/rebase.c\n+++ b/builtin/rebase.c\n@@ -93,6 +93,7 @@ struct rebase_options {\n \tint autosquash;\n \tchar *gpg_sign_opt;\n \tint autostash;\n+\tchar *cmd;\n };\n \n static int is_interactive(struct rebase_options *opts)\n@@ -346,6 +347,7 @@ static int run_specific_rebase(struct rebase_options *opts)\n \tadd_var(&script_snippet, \"keep_empty\", opts->keep_empty ? \"yes\" : \"\");\n \tadd_var(&script_snippet, \"autosquash\", opts->autosquash ? \"t\" : \"\");\n \tadd_var(&script_snippet, \"gpg_sign_opt\", opts->gpg_sign_opt);\n+\tadd_var(&script_snippet, \"cmd\", opts->cmd);\n \n \tswitch (opts->type) {\n \tcase REBASE_AM:\n@@ -619,6 +621,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \tconst char *gpg_sign = NULL;\n \tint opt_c = -1;\n \tstruct string_list whitespace = STRING_LIST_INIT_NODUP;\n+\tstruct string_list exec = STRING_LIST_INIT_NODUP;\n \tstruct option builtin_rebase_options[] = {\n \t\tOPT_STRING(0, \"onto\", &options.onto_name,\n \t\t\t   N_(\"revision\"),\n@@ -691,6 +694,9 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \t\t\t    REBASE_AM),\n \t\tOPT_BOOL(0, \"autostash\", &options.autostash,\n \t\t\t N_(\"automatically stash/stash pop before and after\")),\n+\t\tOPT_STRING_LIST('x', \"exec\", &exec, N_(\"exec\"),\n+\t\t\t\tN_(\"add exec lines after each commit of the \"\n+\t\t\t\t   \"editable list\")),\n \t\tOPT_END(),\n \t};\n \n@@ -915,6 +921,17 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \t\t}\n \t}\n \n+\tif (exec.nr) {\n+\t\tint i;\n+\n+\t\timply_interactive(&options, \"--exec\");\n+\n+\t\tstrbuf_reset(&buf);\n+\t\tfor (i = 0; i < exec.nr; i++)\n+\t\t\tstrbuf_addf(&buf, \"exec %s\\n\", exec.items[i].string);\n+\t\toptions.cmd = xstrdup(buf.buf);\n+\t}\n+\n \tswitch (options.type) {\n \tcase REBASE_MERGE:\n \tcase REBASE_INTERACTIVE:\n@@ -1197,5 +1214,6 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \tstrbuf_release(&revisions);\n \tfree(options.head_name);\n \tfree(options.gpg_sign_opt);\n+\tfree(options.cmd);\n \treturn ret;\n }\n-- \n2.18.0\n\n"},{"id":"354838","messageId":"20180808152140.14585-14-predatoramigo@gmail.com","threadId":"49073","inReplyTo":"20180808152140.14585-1-predatoramigo@gmail.com","subject":"[PATCH 13/18] builtin rebase: support `--allow-empty-message` option","fromName":"Pratik Karki","fromEmail":"predatoramigo@gmail.com","sentAt":"2018-08-08T15:21:35Z","receivedAt":"2018-08-08T15:23:28Z","isPatch":true,"sender":{"key":"predatoramigo@gmail.com","avatar":"https://avatars.githubusercontent.com/u/12194950?v=4"},"body":"This commit introduces the `--allow-empty-message` option to\n`builtin/rebase.c`. The motivation behind this option is: if there are\nempty messages (which is not allowed in Git by default, but can be\nimported from different version control systems), the rebase will fail.\n\nUsing `--allow-empty-message` overrides that behaviour which will allow\nthe commits having empty messages to continue in rebase operation.\n\nNote: a very recent change made this the default in the shell scripted\n`git rebase`, therefore the builtin rebase does the same.\n\nSigned-off-by: Pratik Karki <predatoramigo@gmail.com>\n---\n builtin/rebase.c | 7 +++++++\n 1 file changed, 7 insertions(+)\n\ndiff --git a/builtin/rebase.c b/builtin/rebase.c\nindex c9e992b526..dfb1e6c25b 100644\n--- a/builtin/rebase.c\n+++ b/builtin/rebase.c\n@@ -94,6 +94,7 @@ struct rebase_options {\n \tchar *gpg_sign_opt;\n \tint autostash;\n \tchar *cmd;\n+\tint allow_empty_message;\n };\n \n static int is_interactive(struct rebase_options *opts)\n@@ -348,6 +349,8 @@ static int run_specific_rebase(struct rebase_options *opts)\n \tadd_var(&script_snippet, \"autosquash\", opts->autosquash ? \"t\" : \"\");\n \tadd_var(&script_snippet, \"gpg_sign_opt\", opts->gpg_sign_opt);\n \tadd_var(&script_snippet, \"cmd\", opts->cmd);\n+\tadd_var(&script_snippet, \"allow_empty_message\",\n+\t\topts->allow_empty_message ?  \"--allow-empty-message\" : \"\");\n \n \tswitch (opts->type) {\n \tcase REBASE_AM:\n@@ -598,6 +601,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \t\t.flags = REBASE_NO_QUIET,\n \t\t.git_am_opt = STRBUF_INIT,\n \t\t.allow_rerere_autoupdate  = -1,\n+\t\t.allow_empty_message = 1,\n \t};\n \tconst char *branch_name;\n \tint ret, flags, total_argc, in_progress = 0;\n@@ -697,6 +701,9 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \t\tOPT_STRING_LIST('x', \"exec\", &exec, N_(\"exec\"),\n \t\t\t\tN_(\"add exec lines after each commit of the \"\n \t\t\t\t   \"editable list\")),\n+\t\tOPT_BOOL(0, \"allow-empty-message\",\n+\t\t\t &options.allow_empty_message,\n+\t\t\t N_(\"allow rebasing commits with empty messages\")),\n \t\tOPT_END(),\n \t};\n \n-- \n2.18.0\n\n"},{"id":"354839","messageId":"20180808152140.14585-15-predatoramigo@gmail.com","threadId":"49073","inReplyTo":"20180808152140.14585-1-predatoramigo@gmail.com","subject":"[PATCH 14/18] builtin rebase: support --rebase-merges[=[no-]rebase-cousins]","fromName":"Pratik Karki","fromEmail":"predatoramigo@gmail.com","sentAt":"2018-08-08T15:21:36Z","receivedAt":"2018-08-08T15:23:32Z","isPatch":true,"sender":{"key":"predatoramigo@gmail.com","avatar":"https://avatars.githubusercontent.com/u/12194950?v=4"},"body":"The mode to rebase non-linear branches is now supported by the builtin\nrebase, too.\n\nSigned-off-by: Pratik Karki <predatoramigo@gmail.com>\n---\n builtin/rebase.c | 21 +++++++++++++++++++++\n 1 file changed, 21 insertions(+)\n\ndiff --git a/builtin/rebase.c b/builtin/rebase.c\nindex dfb1e6c25b..0b94d2daaa 100644\n--- a/builtin/rebase.c\n+++ b/builtin/rebase.c\n@@ -95,6 +95,7 @@ struct rebase_options {\n \tint autostash;\n \tchar *cmd;\n \tint allow_empty_message;\n+\tint rebase_merges, rebase_cousins;\n };\n \n static int is_interactive(struct rebase_options *opts)\n@@ -351,6 +352,10 @@ static int run_specific_rebase(struct rebase_options *opts)\n \tadd_var(&script_snippet, \"cmd\", opts->cmd);\n \tadd_var(&script_snippet, \"allow_empty_message\",\n \t\topts->allow_empty_message ?  \"--allow-empty-message\" : \"\");\n+\tadd_var(&script_snippet, \"rebase_merges\",\n+\t\topts->rebase_merges ? \"t\" : \"\");\n+\tadd_var(&script_snippet, \"rebase_cousins\",\n+\t\topts->rebase_cousins ? \"t\" : \"\");\n \n \tswitch (opts->type) {\n \tcase REBASE_AM:\n@@ -626,6 +631,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \tint opt_c = -1;\n \tstruct string_list whitespace = STRING_LIST_INIT_NODUP;\n \tstruct string_list exec = STRING_LIST_INIT_NODUP;\n+\tconst char *rebase_merges = NULL;\n \tstruct option builtin_rebase_options[] = {\n \t\tOPT_STRING(0, \"onto\", &options.onto_name,\n \t\t\t   N_(\"revision\"),\n@@ -704,6 +710,10 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \t\tOPT_BOOL(0, \"allow-empty-message\",\n \t\t\t &options.allow_empty_message,\n \t\t\t N_(\"allow rebasing commits with empty messages\")),\n+\t\t{OPTION_STRING, 'r', \"rebase-merges\", &rebase_merges,\n+\t\t\tN_(\"mode\"),\n+\t\t\tN_(\"try to rebase merges instead of skipping them\"),\n+\t\t\tPARSE_OPT_OPTARG, NULL, (intptr_t)\"\"},\n \t\tOPT_END(),\n \t};\n \n@@ -939,6 +949,17 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \t\toptions.cmd = xstrdup(buf.buf);\n \t}\n \n+\tif (rebase_merges) {\n+\t\tif (!*rebase_merges)\n+\t\t\t; /* default mode; do nothing */\n+\t\telse if (!strcmp(\"rebase-cousins\", rebase_merges))\n+\t\t\toptions.rebase_cousins = 1;\n+\t\telse if (strcmp(\"no-rebase-cousins\", rebase_merges))\n+\t\t\tdie(_(\"Unknown mode: %s\"), rebase_merges);\n+\t\toptions.rebase_merges = 1;\n+\t\timply_interactive(&options, \"--rebase-merges\");\n+\t}\n+\n \tswitch (options.type) {\n \tcase REBASE_MERGE:\n \tcase REBASE_INTERACTIVE:\n-- \n2.18.0\n\n"},{"id":"354840","messageId":"20180808152140.14585-16-predatoramigo@gmail.com","threadId":"49073","inReplyTo":"20180808152140.14585-1-predatoramigo@gmail.com","subject":"[PATCH 15/18] merge-base --fork-point: extract libified function","fromName":"Pratik Karki","fromEmail":"predatoramigo@gmail.com","sentAt":"2018-08-08T15:21:37Z","receivedAt":"2018-08-08T15:23:36Z","isPatch":true,"sender":{"key":"predatoramigo@gmail.com","avatar":"https://avatars.githubusercontent.com/u/12194950?v=4"},"body":"We need this functionality in the builtin rebase.\n\nNote: to make this function truly reusable, we have to switch the call\nget_merges_many_dirty() to get_merges_many() because we want the commit\nflags to be reset (otherwise, subsequent get_merge_bases() calls would\nobtain incorrect results). This did not matter when the function was\ncalled in `git rev-parse --fork-point` because in that command, the\nprocess definitely did not traverse any commits before exiting.\n\nSigned-off-by: Pratik Karki <predatoramigo@gmail.com>\n---\n builtin/merge-base.c | 81 ++++----------------------------------------\n commit.c             | 81 ++++++++++++++++++++++++++++++++++++++++++++\n commit.h             |  2 ++\n 3 files changed, 89 insertions(+), 75 deletions(-)\n\ndiff --git a/builtin/merge-base.c b/builtin/merge-base.c\nindex 08d91b1f0c..790ceaeed6 100644\n--- a/builtin/merge-base.c\n+++ b/builtin/merge-base.c\n@@ -110,54 +110,12 @@ static int handle_is_ancestor(int argc, const char **argv)\n \t\treturn 1;\n }\n \n-struct rev_collect {\n-\tstruct commit **commit;\n-\tint nr;\n-\tint alloc;\n-\tunsigned int initial : 1;\n-};\n-\n-static void add_one_commit(struct object_id *oid, struct rev_collect *revs)\n-{\n-\tstruct commit *commit;\n-\n-\tif (is_null_oid(oid))\n-\t\treturn;\n-\n-\tcommit = lookup_commit(the_repository, oid);\n-\tif (!commit ||\n-\t    (commit->object.flags & TMP_MARK) ||\n-\t    parse_commit(commit))\n-\t\treturn;\n-\n-\tALLOC_GROW(revs->commit, revs->nr + 1, revs->alloc);\n-\trevs->commit[revs->nr++] = commit;\n-\tcommit->object.flags |= TMP_MARK;\n-}\n-\n-static int collect_one_reflog_ent(struct object_id *ooid, struct object_id *noid,\n-\t\t\t\t  const char *ident, timestamp_t timestamp,\n-\t\t\t\t  int tz, const char *message, void *cbdata)\n-{\n-\tstruct rev_collect *revs = cbdata;\n-\n-\tif (revs->initial) {\n-\t\trevs->initial = 0;\n-\t\tadd_one_commit(ooid, revs);\n-\t}\n-\tadd_one_commit(noid, revs);\n-\treturn 0;\n-}\n-\n static int handle_fork_point(int argc, const char **argv)\n {\n \tstruct object_id oid;\n \tchar *refname;\n+\tstruct commit *derived, *fork_point;\n \tconst char *commitname;\n-\tstruct rev_collect revs;\n-\tstruct commit *derived;\n-\tstruct commit_list *bases;\n-\tint i, ret = 0;\n \n \tswitch (dwim_ref(argv[0], strlen(argv[0]), &oid, &refname)) {\n \tcase 0:\n@@ -173,41 +131,14 @@ static int handle_fork_point(int argc, const char **argv)\n \t\tdie(\"Not a valid object name: '%s'\", commitname);\n \n \tderived = lookup_commit_reference(the_repository, &oid);\n-\tmemset(&revs, 0, sizeof(revs));\n-\trevs.initial = 1;\n-\tfor_each_reflog_ent(refname, collect_one_reflog_ent, &revs);\n \n-\tif (!revs.nr && !get_oid(refname, &oid))\n-\t\tadd_one_commit(&oid, &revs);\n+\tfork_point = get_fork_point(refname, derived);\n \n-\tfor (i = 0; i < revs.nr; i++)\n-\t\trevs.commit[i]->object.flags &= ~TMP_MARK;\n-\n-\tbases = get_merge_bases_many_dirty(derived, revs.nr, revs.commit);\n-\n-\t/*\n-\t * There should be one and only one merge base, when we found\n-\t * a common ancestor among reflog entries.\n-\t */\n-\tif (!bases || bases->next) {\n-\t\tret = 1;\n-\t\tgoto cleanup_return;\n-\t}\n-\n-\t/* And the found one must be one of the reflog entries */\n-\tfor (i = 0; i < revs.nr; i++)\n-\t\tif (&bases->item->object == &revs.commit[i]->object)\n-\t\t\tbreak; /* found */\n-\tif (revs.nr <= i) {\n-\t\tret = 1; /* not found */\n-\t\tgoto cleanup_return;\n-\t}\n-\n-\tprintf(\"%s\\n\", oid_to_hex(&bases->item->object.oid));\n+\tif (!fork_point)\n+\t\treturn 1;\n \n-cleanup_return:\n-\tfree_commit_list(bases);\n-\treturn ret;\n+\tprintf(\"%s\\n\", oid_to_hex(&fork_point->object.oid));\n+\treturn 0;\n }\n \n int cmd_merge_base(int argc, const char **argv, const char *prefix)\ndiff --git a/commit.c b/commit.c\nindex 30d1af2b20..a3fc77a4eb 100644\n--- a/commit.c\n+++ b/commit.c\n@@ -17,6 +17,7 @@\n #include \"sha1-lookup.h\"\n #include \"wt-status.h\"\n #include \"advice.h\"\n+#include \"refs.h\"\n \n static struct commit_extra_header *read_commit_extra_header_lines(const char *buf, size_t len, const char **);\n \n@@ -958,6 +959,86 @@ static struct commit_list *merge_bases_many(struct commit *one, int n, struct co\n \treturn result;\n }\n \n+struct rev_collect {\n+\tstruct commit **commit;\n+\tint nr;\n+\tint alloc;\n+\tunsigned int initial : 1;\n+};\n+\n+static void add_one_commit(struct object_id *oid, struct rev_collect *revs)\n+{\n+\tstruct commit *commit;\n+\n+\tif (is_null_oid(oid))\n+\t\treturn;\n+\n+\tcommit = lookup_commit(the_repository, oid);\n+\tif (!commit ||\n+\t    (commit->object.flags & TMP_MARK) ||\n+\t    parse_commit(commit))\n+\t\treturn;\n+\n+\tALLOC_GROW(revs->commit, revs->nr + 1, revs->alloc);\n+\trevs->commit[revs->nr++] = commit;\n+\tcommit->object.flags |= TMP_MARK;\n+}\n+\n+static int collect_one_reflog_ent(struct object_id *ooid, struct object_id *noid,\n+\t\t\t\t  const char *ident, timestamp_t timestamp,\n+\t\t\t\t  int tz, const char *message, void *cbdata)\n+{\n+\tstruct rev_collect *revs = cbdata;\n+\n+\tif (revs->initial) {\n+\t\trevs->initial = 0;\n+\t\tadd_one_commit(ooid, revs);\n+\t}\n+\tadd_one_commit(noid, revs);\n+\treturn 0;\n+}\n+\n+struct commit *get_fork_point(const char *refname, struct commit *commit)\n+{\n+\tstruct object_id oid;\n+\tstruct rev_collect revs;\n+\tstruct commit_list *bases;\n+\tint i;\n+\tstruct commit *ret = NULL;\n+\n+\tmemset(&revs, 0, sizeof(revs));\n+\trevs.initial = 1;\n+\tfor_each_reflog_ent(refname, collect_one_reflog_ent, &revs);\n+\n+\tif (!revs.nr && !get_oid(refname, &oid))\n+\t\tadd_one_commit(&oid, &revs);\n+\n+\tfor (i = 0; i < revs.nr; i++)\n+\t\trevs.commit[i]->object.flags &= ~TMP_MARK;\n+\n+\tbases = get_merge_bases_many(commit, revs.nr, revs.commit);\n+\n+\t/*\n+\t * There should be one and only one merge base, when we found\n+\t * a common ancestor among reflog entries.\n+\t */\n+\tif (!bases || bases->next)\n+\t\tgoto cleanup_return;\n+\n+\t/* And the found one must be one of the reflog entries */\n+\tfor (i = 0; i < revs.nr; i++)\n+\t\tif (&bases->item->object == &revs.commit[i]->object)\n+\t\t\tbreak; /* found */\n+\tif (revs.nr <= i)\n+\t\tgoto cleanup_return;\n+\n+\tret = bases->item;\n+\n+cleanup_return:\n+\tfree_commit_list(bases);\n+\treturn ret;\n+}\n+\n struct commit_list *get_octopus_merge_bases(struct commit_list *in)\n {\n \tstruct commit_list *i, *j, *k, *ret = NULL;\ndiff --git a/commit.h b/commit.h\nindex da0db36eba..b34240017f 100644\n--- a/commit.h\n+++ b/commit.h\n@@ -211,6 +211,8 @@ extern struct commit_list *get_octopus_merge_bases(struct commit_list *in);\n /* To be used only when object flags after this call no longer matter */\n extern struct commit_list *get_merge_bases_many_dirty(struct commit *one, int n, struct commit **twos);\n \n+struct commit *get_fork_point(const char *refname, struct commit *commit);\n+\n /* largest positive number a signed 32-bit integer can contain */\n #define INFINITE_DEPTH 0x7fffffff\n \n-- \n2.18.0\n\n"},{"id":"354841","messageId":"20180808152140.14585-17-predatoramigo@gmail.com","threadId":"49073","inReplyTo":"20180808152140.14585-1-predatoramigo@gmail.com","subject":"[PATCH 16/18] builtin rebase: support `fork-point` option","fromName":"Pratik Karki","fromEmail":"predatoramigo@gmail.com","sentAt":"2018-08-08T15:21:38Z","receivedAt":"2018-08-08T15:23:40Z","isPatch":true,"sender":{"key":"predatoramigo@gmail.com","avatar":"https://avatars.githubusercontent.com/u/12194950?v=4"},"body":"This commit adds support for `--fork-point` and `--no-fork-point`.\nThis is converted as-is from `git-legacy-rebase.sh`.\n\nSigned-off-by: Pratik Karki <predatoramigo@gmail.com>\n---\n builtin/rebase.c | 11 +++++++++++\n 1 file changed, 11 insertions(+)\n\ndiff --git a/builtin/rebase.c b/builtin/rebase.c\nindex 0b94d2daaa..72e64868b2 100644\n--- a/builtin/rebase.c\n+++ b/builtin/rebase.c\n@@ -632,6 +632,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \tstruct string_list whitespace = STRING_LIST_INIT_NODUP;\n \tstruct string_list exec = STRING_LIST_INIT_NODUP;\n \tconst char *rebase_merges = NULL;\n+\tint fork_point = -1;\n \tstruct option builtin_rebase_options[] = {\n \t\tOPT_STRING(0, \"onto\", &options.onto_name,\n \t\t\t   N_(\"revision\"),\n@@ -714,6 +715,8 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \t\t\tN_(\"mode\"),\n \t\t\tN_(\"try to rebase merges instead of skipping them\"),\n \t\t\tPARSE_OPT_OPTARG, NULL, (intptr_t)\"\"},\n+\t\tOPT_BOOL(0, \"fork-point\", &fork_point,\n+\t\t\t N_(\"use 'merge-base --fork-point' to refine upstream\")),\n \t\tOPT_END(),\n \t};\n \n@@ -1062,6 +1065,14 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \t} else\n \t\tBUG(\"unexpected number of arguments left to parse\");\n \n+\tif (fork_point > 0) {\n+\t\tstruct commit *head =\n+\t\t\tlookup_commit_reference(the_repository,\n+\t\t\t\t\t\t&options.orig_head);\n+\t\toptions.restrict_revision =\n+\t\t\tget_fork_point(options.upstream_name, head);\n+\t}\n+\n \tif (read_index(the_repository->index) < 0)\n \t\tdie(_(\"could not read index\"));\n \n-- \n2.18.0\n\n"},{"id":"354842","messageId":"20180808152140.14585-18-predatoramigo@gmail.com","threadId":"49073","inReplyTo":"20180808152140.14585-1-predatoramigo@gmail.com","subject":"[PATCH 17/18] builtin rebase: add support for custom merge strategies","fromName":"Pratik Karki","fromEmail":"predatoramigo@gmail.com","sentAt":"2018-08-08T15:21:39Z","receivedAt":"2018-08-08T15:23:44Z","isPatch":true,"sender":{"key":"predatoramigo@gmail.com","avatar":"https://avatars.githubusercontent.com/u/12194950?v=4"},"body":"When running a rebase in non-am mode, it uses the recursive merge to\ncherry-pick the commits, and the rebase command allows to configure\nthe merge strategy to be used in this operation.\n\nThis commit adds that support to the builtin rebase.\n\nSigned-off-by: Pratik Karki <predatoramigo@gmail.com>\n---\n builtin/rebase.c | 57 ++++++++++++++++++++++++++++++++++++++++++++++++\n 1 file changed, 57 insertions(+)\n\ndiff --git a/builtin/rebase.c b/builtin/rebase.c\nindex 72e64868b2..65e7be1c48 100644\n--- a/builtin/rebase.c\n+++ b/builtin/rebase.c\n@@ -96,6 +96,7 @@ struct rebase_options {\n \tchar *cmd;\n \tint allow_empty_message;\n \tint rebase_merges, rebase_cousins;\n+\tchar *strategy, *strategy_opts;\n };\n \n static int is_interactive(struct rebase_options *opts)\n@@ -217,6 +218,22 @@ static int read_basic_state(struct rebase_options *opts)\n \t\topts->gpg_sign_opt = xstrdup(buf.buf);\n \t}\n \n+\tif (file_exists(state_dir_path(\"strategy\", opts))) {\n+\t\tstrbuf_reset(&buf);\n+\t\tif (read_one(state_dir_path(\"strategy\", opts), &buf))\n+\t\t\treturn -1;\n+\t\tfree(opts->strategy);\n+\t\topts->strategy = xstrdup(buf.buf);\n+\t}\n+\n+\tif (file_exists(state_dir_path(\"strategy_opts\", opts))) {\n+\t\tstrbuf_reset(&buf);\n+\t\tif (read_one(state_dir_path(\"strategy_opts\", opts), &buf))\n+\t\t\treturn -1;\n+\t\tfree(opts->strategy_opts);\n+\t\topts->strategy_opts = xstrdup(buf.buf);\n+\t}\n+\n \tstrbuf_release(&buf);\n \n \treturn 0;\n@@ -356,6 +373,8 @@ static int run_specific_rebase(struct rebase_options *opts)\n \t\topts->rebase_merges ? \"t\" : \"\");\n \tadd_var(&script_snippet, \"rebase_cousins\",\n \t\topts->rebase_cousins ? \"t\" : \"\");\n+\tadd_var(&script_snippet, \"strategy\", opts->strategy);\n+\tadd_var(&script_snippet, \"strategy_opts\", opts->strategy_opts);\n \n \tswitch (opts->type) {\n \tcase REBASE_AM:\n@@ -633,6 +652,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \tstruct string_list exec = STRING_LIST_INIT_NODUP;\n \tconst char *rebase_merges = NULL;\n \tint fork_point = -1;\n+\tstruct string_list strategy_options = STRING_LIST_INIT_NODUP;\n \tstruct option builtin_rebase_options[] = {\n \t\tOPT_STRING(0, \"onto\", &options.onto_name,\n \t\t\t   N_(\"revision\"),\n@@ -717,6 +737,12 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \t\t\tPARSE_OPT_OPTARG, NULL, (intptr_t)\"\"},\n \t\tOPT_BOOL(0, \"fork-point\", &fork_point,\n \t\t\t N_(\"use 'merge-base --fork-point' to refine upstream\")),\n+\t\tOPT_STRING('s', \"strategy\", &options.strategy,\n+\t\t\t   N_(\"strategy\"), N_(\"use the given merge strategy\")),\n+\t\tOPT_STRING_LIST('X', \"strategy-option\", &strategy_options,\n+\t\t\t\tN_(\"option\"),\n+\t\t\t\tN_(\"pass the argument through to the merge \"\n+\t\t\t\t   \"strategy\")),\n \t\tOPT_END(),\n \t};\n \n@@ -963,6 +989,37 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \t\timply_interactive(&options, \"--rebase-merges\");\n \t}\n \n+\tif (strategy_options.nr) {\n+\t\tint i;\n+\n+\t\tif (!options.strategy)\n+\t\t\toptions.strategy = \"recursive\";\n+\n+\t\tstrbuf_reset(&buf);\n+\t\tfor (i = 0; i < strategy_options.nr; i++)\n+\t\t\tstrbuf_addf(&buf, \" --%s\",\n+\t\t\t\t    strategy_options.items[i].string);\n+\t\toptions.strategy_opts = xstrdup(buf.buf);\n+\t}\n+\n+\tif (options.strategy) {\n+\t\toptions.strategy = xstrdup(options.strategy);\n+\t\tswitch (options.type) {\n+\t\tcase REBASE_AM:\n+\t\t\tdie(_(\"--strategy requires --merge or --interactive\"));\n+\t\tcase REBASE_MERGE:\n+\t\tcase REBASE_INTERACTIVE:\n+\t\tcase REBASE_PRESERVE_MERGES:\n+\t\t\t/* compatible */\n+\t\t\tbreak;\n+\t\tcase REBASE_UNSPECIFIED:\n+\t\t\toptions.type = REBASE_MERGE;\n+\t\t\tbreak;\n+\t\tdefault:\n+\t\t\tBUG(\"unhandled rebase type (%d)\", options.type);\n+\t\t}\n+\t}\n+\n \tswitch (options.type) {\n \tcase REBASE_MERGE:\n \tcase REBASE_INTERACTIVE:\n-- \n2.18.0\n\n"},{"id":"354843","messageId":"20180808152140.14585-19-predatoramigo@gmail.com","threadId":"49073","inReplyTo":"20180808152140.14585-1-predatoramigo@gmail.com","subject":"[PATCH 18/18] builtin rebase: support --root","fromName":"Pratik Karki","fromEmail":"predatoramigo@gmail.com","sentAt":"2018-08-08T15:21:40Z","receivedAt":"2018-08-08T15:23:47Z","isPatch":true,"sender":{"key":"predatoramigo@gmail.com","avatar":"https://avatars.githubusercontent.com/u/12194950?v=4"},"body":"This option allows to rebase entire histories up to, and including, the\nroot commit.\n\nThe conversion from the shell script is straight-forward, apart from\nthe fact that we do not have to write an empty tree in C.\n\nSigned-off-by: Pratik Karki <predatoramigo@gmail.com>\n---\n builtin/rebase.c | 31 +++++++++++++++++++++++++++++--\n 1 file changed, 29 insertions(+), 2 deletions(-)\n\ndiff --git a/builtin/rebase.c b/builtin/rebase.c\nindex 65e7be1c48..94abaaa890 100644\n--- a/builtin/rebase.c\n+++ b/builtin/rebase.c\n@@ -76,6 +76,7 @@ struct rebase_options {\n \tconst char *revisions;\n \tconst char *switch_to;\n \tint root;\n+\tstruct object_id *squash_onto;\n \tstruct commit *restrict_revision;\n \tint dont_finish_rebase;\n \tenum {\n@@ -375,6 +376,9 @@ static int run_specific_rebase(struct rebase_options *opts)\n \t\topts->rebase_cousins ? \"t\" : \"\");\n \tadd_var(&script_snippet, \"strategy\", opts->strategy);\n \tadd_var(&script_snippet, \"strategy_opts\", opts->strategy_opts);\n+\tadd_var(&script_snippet, \"rebase_root\", opts->root ? \"t\" : \"\");\n+\tadd_var(&script_snippet, \"squash_onto\",\n+\t\topts->squash_onto ? oid_to_hex(opts->squash_onto) : \"\");\n \n \tswitch (opts->type) {\n \tcase REBASE_AM:\n@@ -653,6 +657,8 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \tconst char *rebase_merges = NULL;\n \tint fork_point = -1;\n \tstruct string_list strategy_options = STRING_LIST_INIT_NODUP;\n+\tstruct object_id squash_onto;\n+\tchar *squash_onto_name = NULL;\n \tstruct option builtin_rebase_options[] = {\n \t\tOPT_STRING(0, \"onto\", &options.onto_name,\n \t\t\t   N_(\"revision\"),\n@@ -743,6 +749,8 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \t\t\t\tN_(\"option\"),\n \t\t\t\tN_(\"pass the argument through to the merge \"\n \t\t\t\t   \"strategy\")),\n+\t\tOPT_BOOL(0, \"root\", &options.root,\n+\t\t\t N_(\"rebase all reachable commits up to the root(s)\")),\n \t\tOPT_END(),\n \t};\n \n@@ -1020,6 +1028,9 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \t\t}\n \t}\n \n+\tif (options.root && !options.onto_name)\n+\t\timply_interactive(&options, \"--root without --onto\");\n+\n \tswitch (options.type) {\n \tcase REBASE_MERGE:\n \tcase REBASE_INTERACTIVE:\n@@ -1058,8 +1069,22 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \t\tif (!options.upstream)\n \t\t\tdie(_(\"invalid upstream '%s'\"), options.upstream_name);\n \t\toptions.upstream_arg = options.upstream_name;\n-\t} else\n-\t\tdie(\"TODO: upstream for --root\");\n+\t} else {\n+\t\tif (!options.onto_name) {\n+\t\t\tif (commit_tree(\"\", 0, the_hash_algo->empty_tree, NULL,\n+\t\t\t\t\t&squash_onto, NULL, NULL) < 0)\n+\t\t\t\tdie(_(\"Could not create new root commit\"));\n+\t\t\toptions.squash_onto = &squash_onto;\n+\t\t\toptions.onto_name = squash_onto_name =\n+\t\t\t\txstrdup(oid_to_hex(&squash_onto));\n+\t\t}\n+\t\toptions.upstream_name = NULL;\n+\t\toptions.upstream = NULL;\n+\t\tif (argc > 1)\n+\t\t\tusage_with_options(builtin_rebase_usage,\n+\t\t\t\t\t   builtin_rebase_options);\n+\t\toptions.upstream_arg = \"--root\";\n+\t}\n \n \t/* Make sure the branch to rebase onto is valid. */\n \tif (!options.onto_name)\n@@ -1207,6 +1232,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \t */\n \tif (can_fast_forward(options.onto, &options.orig_head, &merge_base) &&\n \t    !is_interactive(&options) && !options.restrict_revision &&\n+\t    options.upstream &&\n \t    !oidcmp(&options.upstream->object.oid, &options.onto->object.oid)) {\n \t\tint flag;\n \n@@ -1311,5 +1337,6 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \tfree(options.head_name);\n \tfree(options.gpg_sign_opt);\n \tfree(options.cmd);\n+\tfree(squash_onto_name);\n \treturn ret;\n }\n-- \n2.18.0\n\n"},{"id":"355991","messageId":"CACsJy8CS5aABuQrqWxdfLOTbFRhQDQ+tFO+wOCLTdeJG8mH0hw@mail.gmail.com","threadId":"49073","inReplyTo":"20180808152140.14585-12-predatoramigo@gmail.com","subject":"Re: [PATCH 11/18] builtin rebase: support `--autostash` option","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2018-08-18T15:59:41Z","receivedAt":"2018-08-18T16:00:09Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Wed, Aug 8, 2018 at 5:26 PM Pratik Karki <predatoramigo@gmail.com> wrote:\n> @@ -224,13 +219,56 @@ static int read_basic_state(struct rebase_options *opts)\n>         return 0;\n>  }\n>\n> +static int apply_autostash(struct rebase_options *opts)\n> +{\n> +       const char *path = state_dir_path(\"autostash\", opts);\n> +       struct strbuf autostash = STRBUF_INIT;\n> +       struct child_process stash_apply = CHILD_PROCESS_INIT;\n> +\n> +       if (!file_exists(path))\n> +               return 0;\n> +\n> +       if (read_one(state_dir_path(\"autostash\", opts), &autostash))\n> +               return error(_(\"Could not read '%s'\"), path);\n> +       argv_array_pushl(&stash_apply.args,\n> +                        \"stash\", \"apply\", autostash.buf, NULL);\n> +       stash_apply.git_cmd = 1;\n> +       stash_apply.no_stderr = stash_apply.no_stdout =\n> +               stash_apply.no_stdin = 1;\n> +       if (!run_command(&stash_apply))\n> +               printf(\"Applied autostash.\\n\");\n\nI think you need _() here.\n\n> +       else {\n> +               struct argv_array args = ARGV_ARRAY_INIT;\n> +               int res = 0;\n> +\n> +               argv_array_pushl(&args,\n> +                                \"stash\", \"store\", \"-m\", \"autostash\", \"-q\",\n> +                                autostash.buf, NULL);\n> +               if (run_command_v_opt(args.argv, RUN_GIT_CMD))\n> +                       res = error(_(\"Cannot store %s\"), autostash.buf);\n> +               argv_array_clear(&args);\n> +               strbuf_release(&autostash);\n> +               if (res)\n> +                       return res;\n> +\n> +               fprintf(stderr,\n> +                       _(\"Applying autostash resulted in conflicts.\\n\"\n> +                         \"Your changes are safe in the stash.\\n\"\n> +                         \"You can run \\\"git stash pop\\\" or \\\"git stash drop\\\" \"\n> +                         \"at any time.\\n\"));\n> +       }\n> +\n> +       strbuf_release(&autostash);\n> +       return 0;\n> +}\n> +\n>  static int finish_rebase(struct rebase_options *opts)\n>  {\n>         struct strbuf dir = STRBUF_INIT;\n>         const char *argv_gc_auto[] = { \"gc\", \"--auto\", NULL };\n>\n>         delete_ref(NULL, \"REBASE_HEAD\", NULL, REF_NO_DEREF);\n> -       apply_autostash();\n> +       apply_autostash(opts);\n>         close_all_packs(the_repository->objects);\n>         /*\n>          * We ignore errors in 'gc --auto', since the\n-- \nDuy\n"},{"id":"356472","messageId":"nycvar.QRO.7.76.6.1808241803100.73@tvgsbejvaqbjf.bet","threadId":"49073","inReplyTo":"20180808152140.14585-8-predatoramigo@gmail.com","subject":"Re: [PATCH 07/18] builtin rebase: support `keep-empty` option","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2018-08-24T16:04:22Z","receivedAt":"2018-08-24T16:04:32Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Wed, 8 Aug 2018, Pratik Karki wrote:\n\n> diff --git a/builtin/rebase.c b/builtin/rebase.c\n> index 42ee040da3..fd9ad8efae 100644\n> --- a/builtin/rebase.c\n> +++ b/builtin/rebase.c\n> @@ -588,6 +607,8 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n>  \t\t\t &options.allow_rerere_autoupdate,\n>  \t\t\t N_(\"allow rerere to update index  with resolved \"\n>  \t\t\t    \"conflict\")),\n> +\t\tOPT_BOOL(0, \"keep-empty\", &options.keep_empty,\n> +\t\t\t N_(\"preserve empty commits during rebase\")),\n>  \t\tOPT_END(),\n\nThis forgets the short option `-k`, I just noticed. I then looked at the\nrest of the options, and they seem not to forget the short option\nanywhere.\n\nI will fix this before sending v2.\n\nCiao,\nDscho\n"},{"id":"356473","messageId":"nycvar.QRO.7.76.6.1808241805550.73@tvgsbejvaqbjf.bet","threadId":"49073","inReplyTo":"CACsJy8CS5aABuQrqWxdfLOTbFRhQDQ+tFO+wOCLTdeJG8mH0hw@mail.gmail.com","subject":"Re: [PATCH 11/18] builtin rebase: support `--autostash` option","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2018-08-24T16:06:56Z","receivedAt":"2018-08-24T16:07:03Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Duy,\n\nOn Sat, 18 Aug 2018, Duy Nguyen wrote:\n\n> On Wed, Aug 8, 2018 at 5:26 PM Pratik Karki <predatoramigo@gmail.com> wrote:\n> > @@ -224,13 +219,56 @@ static int read_basic_state(struct rebase_options *opts)\n> >         return 0;\n> >  }\n> >\n> > +static int apply_autostash(struct rebase_options *opts)\n> > +{\n> > +       const char *path = state_dir_path(\"autostash\", opts);\n> > +       struct strbuf autostash = STRBUF_INIT;\n> > +       struct child_process stash_apply = CHILD_PROCESS_INIT;\n> > +\n> > +       if (!file_exists(path))\n> > +               return 0;\n> > +\n> > +       if (read_one(state_dir_path(\"autostash\", opts), &autostash))\n> > +               return error(_(\"Could not read '%s'\"), path);\n> > +       argv_array_pushl(&stash_apply.args,\n> > +                        \"stash\", \"apply\", autostash.buf, NULL);\n> > +       stash_apply.git_cmd = 1;\n> > +       stash_apply.no_stderr = stash_apply.no_stdout =\n> > +               stash_apply.no_stdin = 1;\n> > +       if (!run_command(&stash_apply))\n> > +               printf(\"Applied autostash.\\n\");\n> \n> I think you need _() here.\n\nGood catch.\n\nWill fix before sending v2,\nDscho\n\n> \n> > +       else {\n> > +               struct argv_array args = ARGV_ARRAY_INIT;\n> > +               int res = 0;\n> > +\n> > +               argv_array_pushl(&args,\n> > +                                \"stash\", \"store\", \"-m\", \"autostash\", \"-q\",\n> > +                                autostash.buf, NULL);\n> > +               if (run_command_v_opt(args.argv, RUN_GIT_CMD))\n> > +                       res = error(_(\"Cannot store %s\"), autostash.buf);\n> > +               argv_array_clear(&args);\n> > +               strbuf_release(&autostash);\n> > +               if (res)\n> > +                       return res;\n> > +\n> > +               fprintf(stderr,\n> > +                       _(\"Applying autostash resulted in conflicts.\\n\"\n> > +                         \"Your changes are safe in the stash.\\n\"\n> > +                         \"You can run \\\"git stash pop\\\" or \\\"git stash drop\\\" \"\n> > +                         \"at any time.\\n\"));\n> > +       }\n> > +\n> > +       strbuf_release(&autostash);\n> > +       return 0;\n> > +}\n> > +\n> >  static int finish_rebase(struct rebase_options *opts)\n> >  {\n> >         struct strbuf dir = STRBUF_INIT;\n> >         const char *argv_gc_auto[] = { \"gc\", \"--auto\", NULL };\n> >\n> >         delete_ref(NULL, \"REBASE_HEAD\", NULL, REF_NO_DEREF);\n> > -       apply_autostash();\n> > +       apply_autostash(opts);\n> >         close_all_packs(the_repository->objects);\n> >         /*\n> >          * We ignore errors in 'gc --auto', since the\n> -- \n> Duy\n> \n"},{"id":"357364","messageId":"pull.33.v2.git.gitgitgadget@gmail.com","threadId":"49073","inReplyTo":"20180808152140.14585-1-predatoramigo@gmail.com","subject":"[PATCH v2 00/18] builtin rebase options","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2018-09-04T21:59:47Z","receivedAt":"2018-09-04T21:59:51Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"This patch series completes the support for all rebase options in the\nbuiltin rebase, e.g. --signoff, rerere-autoupdate, etc.\n\nIt is based on pk/rebase -in-c-3-acts.\n\nChanges since v1:\n\n * Added the forgotten -k short option for --keep-empty (and verified that\n   no other short options were forgotten).\n * The \"Applied autostash\" message is now translated (as was the original in\n   the shell script version).\n\nPratik Karki (18):\n  builtin rebase: allow selecting the rebase \"backend\"\n  builtin rebase: support --signoff\n  builtin rebase: support --rerere-autoupdate\n  builtin rebase: support --committer-date-is-author-date\n  builtin rebase: support `ignore-whitespace` option\n  builtin rebase: support `ignore-date` option\n  builtin rebase: support `keep-empty` option\n  builtin rebase: support `--autosquash`\n  builtin rebase: support `--gpg-sign` option\n  builtin rebase: support `-C` and `--whitespace=<type>`\n  builtin rebase: support `--autostash` option\n  builtin rebase: support `--exec`\n  builtin rebase: support `--allow-empty-message` option\n  builtin rebase: support --rebase-merges[=[no-]rebase-cousins]\n  merge-base --fork-point: extract libified function\n  builtin rebase: support `fork-point` option\n  builtin rebase: add support for custom merge strategies\n  builtin rebase: support --root\n\n builtin/merge-base.c |  81 +-------\n builtin/rebase.c     | 449 ++++++++++++++++++++++++++++++++++++++++++-\n commit.c             |  81 ++++++++\n commit.h             |   2 +\n 4 files changed, 528 insertions(+), 85 deletions(-)\n\n\nbase-commit: e01f72be63e6cb58243124abb2491f9d5dbcdbef\nPublished-As: https://github.com/gitgitgadget/git/releases/tags/pr-33%2Fdscho%2Frebase-in-c-4-opts-v2\nFetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-33/dscho/rebase-in-c-4-opts-v2\nPull-Request: https://github.com/gitgitgadget/git/pull/33\n\nRange-diff vs v1:\n\n  1:  22a65191f8 !  1:  7f751c6ce1 builtin rebase: allow selecting the rebase \"backend\"\n     @@ -19,6 +19,7 @@\n          tests for this via `git pull --rebase=preserve`).\n      \n          Signed-off-by: Pratik Karki <predatoramigo@gmail.com>\n     +    Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n      \n      diff --git a/builtin/rebase.c b/builtin/rebase.c\n      --- a/builtin/rebase.c\n  2:  cb9129890b !  2:  1e2ce4b34e builtin rebase: support --signoff\n     @@ -7,6 +7,7 @@\n          handling is left to the rebase backends.\n      \n          Signed-off-by: Pratik Karki <predatoramigo@gmail.com>\n     +    Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n      \n      diff --git a/builtin/rebase.c b/builtin/rebase.c\n      --- a/builtin/rebase.c\n  3:  99ff1fc128 !  3:  a301ef6bbd builtin rebase: support --rerere-autoupdate\n     @@ -7,6 +7,7 @@\n          `git-legacy-rebase.sh`.\n      \n          Signed-off-by: Pratik Karki <predatoramigo@gmail.com>\n     +    Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n      \n      diff --git a/builtin/rebase.c b/builtin/rebase.c\n      --- a/builtin/rebase.c\n  4:  cb6596ea93 !  4:  8f67a3969d builtin rebase: support --committer-date-is-author-date\n     @@ -6,6 +6,7 @@\n          `git_am_opt` variable that is handled by the `git-rebase--am` backend.\n      \n          Signed-off-by: Pratik Karki <predatoramigo@gmail.com>\n     +    Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n      \n      diff --git a/builtin/rebase.c b/builtin/rebase.c\n      --- a/builtin/rebase.c\n  5:  bf3279c2d5 !  5:  f04394a500 builtin rebase: support `ignore-whitespace` option\n     @@ -7,6 +7,7 @@\n          `--am` backend.\n      \n          Signed-off-by: Pratik Karki <predatoramigo@gmail.com>\n     +    Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n      \n      diff --git a/builtin/rebase.c b/builtin/rebase.c\n      --- a/builtin/rebase.c\n  6:  804e1969c2 !  6:  83bb277509 builtin rebase: support `ignore-date` option\n     @@ -6,6 +6,7 @@\n          to easily change the dates of the rebased commits.\n      \n          Signed-off-by: Pratik Karki <predatoramigo@gmail.com>\n     +    Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n      \n      diff --git a/builtin/rebase.c b/builtin/rebase.c\n      --- a/builtin/rebase.c\n  7:  fcf2243476 !  7:  a8f12bf01f builtin rebase: support `keep-empty` option\n     @@ -12,6 +12,7 @@\n          already be chosen during the `parse_options()` call.\n      \n          Signed-off-by: Pratik Karki <predatoramigo@gmail.com>\n     +    Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n      \n      diff --git a/builtin/rebase.c b/builtin/rebase.c\n      --- a/builtin/rebase.c\n     @@ -60,7 +61,7 @@\n       \t\t\t &options.allow_rerere_autoupdate,\n       \t\t\t N_(\"allow rerere to update index  with resolved \"\n       \t\t\t    \"conflict\")),\n     -+\t\tOPT_BOOL(0, \"keep-empty\", &options.keep_empty,\n     ++\t\tOPT_BOOL('k', \"keep-empty\", &options.keep_empty,\n      +\t\t\t N_(\"preserve empty commits during rebase\")),\n       \t\tOPT_END(),\n       \t};\n  8:  b4ecffc8f1 !  8:  1b6851e5e1 builtin rebase: support `--autosquash`\n     @@ -12,6 +12,7 @@\n          falls back to) git_default_config().\n      \n          Signed-off-by: Pratik Karki <predatoramigo@gmail.com>\n     +    Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n      \n      diff --git a/builtin/rebase.c b/builtin/rebase.c\n      --- a/builtin/rebase.c\n     @@ -46,7 +47,7 @@\n       \n      @@\n       \t\t\t    \"conflict\")),\n     - \t\tOPT_BOOL(0, \"keep-empty\", &options.keep_empty,\n     + \t\tOPT_BOOL('k', \"keep-empty\", &options.keep_empty,\n       \t\t\t N_(\"preserve empty commits during rebase\")),\n      +\t\tOPT_BOOL(0, \"autosquash\", &options.autosquash,\n      +\t\t\t N_(\"move commits that begin with \"\n  9:  e2a26f10e5 !  9:  b8055fb258 builtin rebase: support `--gpg-sign` option\n     @@ -6,6 +6,7 @@\n          to GPG-sign commits.\n      \n          Signed-off-by: Pratik Karki <predatoramigo@gmail.com>\n     +    Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n      \n      diff --git a/builtin/rebase.c b/builtin/rebase.c\n      --- a/builtin/rebase.c\n 10:  a1f3245250 ! 10:  98908573ce builtin rebase: support `-C` and `--whitespace=<type>`\n     @@ -8,6 +8,7 @@\n          shell script version does so, too.\n      \n          Signed-off-by: Pratik Karki <predatoramigo@gmail.com>\n     +    Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n      \n      diff --git a/builtin/rebase.c b/builtin/rebase.c\n      --- a/builtin/rebase.c\n 11:  7b3c0dbbd9 ! 11:  5e5e5cb758 builtin rebase: support `--autostash` option\n     @@ -11,6 +11,7 @@\n          builtin.\n      \n          Signed-off-by: Pratik Karki <predatoramigo@gmail.com>\n     +    Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n      \n      diff --git a/builtin/rebase.c b/builtin/rebase.c\n      --- a/builtin/rebase.c\n     @@ -57,7 +58,7 @@\n      +\tstash_apply.no_stderr = stash_apply.no_stdout =\n      +\t\tstash_apply.no_stdin = 1;\n      +\tif (!run_command(&stash_apply))\n     -+\t\tprintf(\"Applied autostash.\\n\");\n     ++\t\tprintf(_(\"Applied autostash.\\n\"));\n      +\telse {\n      +\t\tstruct argv_array args = ARGV_ARRAY_INIT;\n      +\t\tint res = 0;\n 12:  6f6b3d9339 ! 12:  01e5cb3e91 builtin rebase: support `--exec`\n     @@ -14,6 +14,7 @@\n          The `--exec` option requires `--interactive` machinery.\n      \n          Signed-off-by: Pratik Karki <predatoramigo@gmail.com>\n     +    Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n      \n      diff --git a/builtin/rebase.c b/builtin/rebase.c\n      --- a/builtin/rebase.c\n 13:  fa643c4b3f ! 13:  1c723ad592 builtin rebase: support `--allow-empty-message` option\n     @@ -14,6 +14,7 @@\n          `git rebase`, therefore the builtin rebase does the same.\n      \n          Signed-off-by: Pratik Karki <predatoramigo@gmail.com>\n     +    Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n      \n      diff --git a/builtin/rebase.c b/builtin/rebase.c\n      --- a/builtin/rebase.c\n 14:  00d7ccd356 ! 14:  1bebcde41c builtin rebase: support --rebase-merges[=[no-]rebase-cousins]\n     @@ -6,6 +6,7 @@\n          rebase, too.\n      \n          Signed-off-by: Pratik Karki <predatoramigo@gmail.com>\n     +    Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n      \n      diff --git a/builtin/rebase.c b/builtin/rebase.c\n      --- a/builtin/rebase.c\n 15:  1cf16f416e ! 15:  05652bccfe merge-base --fork-point: extract libified function\n     @@ -12,6 +12,7 @@\n          process definitely did not traverse any commits before exiting.\n      \n          Signed-off-by: Pratik Karki <predatoramigo@gmail.com>\n     +    Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n      \n      diff --git a/builtin/merge-base.c b/builtin/merge-base.c\n      --- a/builtin/merge-base.c\n 16:  78ffb7aaff ! 16:  25f6771947 builtin rebase: support `fork-point` option\n     @@ -6,6 +6,7 @@\n          This is converted as-is from `git-legacy-rebase.sh`.\n      \n          Signed-off-by: Pratik Karki <predatoramigo@gmail.com>\n     +    Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n      \n      diff --git a/builtin/rebase.c b/builtin/rebase.c\n      --- a/builtin/rebase.c\n 17:  693b662542 ! 17:  10dc87d4ff builtin rebase: add support for custom merge strategies\n     @@ -9,6 +9,7 @@\n          This commit adds that support to the builtin rebase.\n      \n          Signed-off-by: Pratik Karki <predatoramigo@gmail.com>\n     +    Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n      \n      diff --git a/builtin/rebase.c b/builtin/rebase.c\n      --- a/builtin/rebase.c\n 18:  95679ccf0b ! 18:  f155141023 builtin rebase: support --root\n     @@ -9,6 +9,7 @@\n          the fact that we do not have to write an empty tree in C.\n      \n          Signed-off-by: Pratik Karki <predatoramigo@gmail.com>\n     +    Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n      \n      diff --git a/builtin/rebase.c b/builtin/rebase.c\n      --- a/builtin/rebase.c\n\n-- \ngitgitgadget\n"},{"id":"357365","messageId":"7f751c6ce106e1ca7c4fb63ae8db5ffe339e7404.1536098386.git.gitgitgadget@gmail.com","threadId":"49073","inReplyTo":"pull.33.v2.git.gitgitgadget@gmail.com","subject":"[PATCH v2 01/18] builtin rebase: allow selecting the rebase \"backend\"","fromName":"Pratik Karki via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2018-09-04T21:59:49Z","receivedAt":"2018-09-04T21:59:53Z","isPatch":true,"sender":{"key":"predatoramigo@gmail.com","avatar":"https://avatars.githubusercontent.com/u/12194950?v=4"},"body":"From: Pratik Karki <predatoramigo@gmail.com>\n\nWith this commit the builtin rebase supports selecting the \"rebase\nbackends\" (or \"type\") `interactive`, `preserve-merges`, and `merge`.\n\nThe `state_dir` was already handled according to the rebase type in a\nprevious commit.\n\nNote that there is one quirk in the shell script: `--interactive`\nfollowed by `--merge` won't reset the type to \"merge\" but keeps the type\nas \"interactive\". And as t3418 tests this explicitly, we have to support\nit in the builtin rebase, too.\n\nLikewise, `--interactive` followed by `--preserve-merges` makes it an\n\"explicitly interactive\" rebase, i.e. a rebase that should show the todo\nlist, while `--preserve-merges` alone is not interactive (and t5520\ntests for this via `git pull --rebase=preserve`).\n\nSigned-off-by: Pratik Karki <predatoramigo@gmail.com>\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n builtin/rebase.c | 37 +++++++++++++++++++++++++++++++++++++\n 1 file changed, 37 insertions(+)\n\ndiff --git a/builtin/rebase.c b/builtin/rebase.c\nindex 75c4ac66e0..fc9b5a8a60 100644\n--- a/builtin/rebase.c\n+++ b/builtin/rebase.c\n@@ -452,6 +452,29 @@ static int can_fast_forward(struct commit *onto, struct object_id *head_oid,\n \treturn res && is_linear_history(onto, head);\n }\n \n+/* -i followed by -m is still -i */\n+static int parse_opt_merge(const struct option *opt, const char *arg, int unset)\n+{\n+\tstruct rebase_options *opts = opt->value;\n+\n+\tif (!is_interactive(opts))\n+\t\topts->type = REBASE_MERGE;\n+\n+\treturn 0;\n+}\n+\n+/* -i followed by -p is still explicitly interactive, but -p alone is not */\n+static int parse_opt_interactive(const struct option *opt, const char *arg,\n+\t\t\t\t int unset)\n+{\n+\tstruct rebase_options *opts = opt->value;\n+\n+\topts->type = REBASE_INTERACTIVE;\n+\topts->flags |= REBASE_INTERACTIVE_EXPLICIT;\n+\n+\treturn 0;\n+}\n+\n int cmd_rebase(int argc, const char **argv, const char *prefix)\n {\n \tstruct rebase_options options = {\n@@ -510,6 +533,17 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \t\tOPT_CMDMODE(0, \"show-current-patch\", &action,\n \t\t\t    N_(\"show the patch file being applied or merged\"),\n \t\t\t    ACTION_SHOW_CURRENT_PATCH),\n+\t\t{ OPTION_CALLBACK, 'm', \"merge\", &options, NULL,\n+\t\t\tN_(\"use merging strategies to rebase\"),\n+\t\t\tPARSE_OPT_NOARG | PARSE_OPT_NONEG,\n+\t\t\tparse_opt_merge },\n+\t\t{ OPTION_CALLBACK, 'i', \"interactive\", &options, NULL,\n+\t\t\tN_(\"let the user edit the list of commits to rebase\"),\n+\t\t\tPARSE_OPT_NOARG | PARSE_OPT_NONEG,\n+\t\t\tparse_opt_interactive },\n+\t\tOPT_SET_INT('p', \"preserve-merges\", &options.type,\n+\t\t\t    N_(\"try to recreate merges instead of ignoring \"\n+\t\t\t       \"them\"), REBASE_PRESERVE_MERGES),\n \t\tOPT_END(),\n \t};\n \n@@ -884,6 +918,9 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \t\tdiff_flush(&opts);\n \t}\n \n+\tif (is_interactive(&options))\n+\t\tgoto run_rebase;\n+\n \t/* Detach HEAD and reset the tree */\n \tif (options.flags & REBASE_NO_QUIET)\n \t\tprintf(_(\"First, rewinding head to replay your work on top of \"\n-- \ngitgitgadget\n\n"},{"id":"357366","messageId":"1e2ce4b34efa234ebca0c008a3766bb9c998d466.1536098386.git.gitgitgadget@gmail.com","threadId":"49073","inReplyTo":"pull.33.v2.git.gitgitgadget@gmail.com","subject":"[PATCH v2 02/18] builtin rebase: support --signoff","fromName":"Pratik Karki via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2018-09-04T21:59:50Z","receivedAt":"2018-09-04T21:59:54Z","isPatch":true,"sender":{"key":"predatoramigo@gmail.com","avatar":"https://avatars.githubusercontent.com/u/12194950?v=4"},"body":"From: Pratik Karki <predatoramigo@gmail.com>\n\nThis commit adds support for `--signoff` which is used to add a\n`Signed-off-by` trailer to all the rebased commits. The actual\nhandling is left to the rebase backends.\n\nSigned-off-by: Pratik Karki <predatoramigo@gmail.com>\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n builtin/rebase.c | 17 +++++++++++++++++\n 1 file changed, 17 insertions(+)\n\ndiff --git a/builtin/rebase.c b/builtin/rebase.c\nindex fc9b5a8a60..a491481120 100644\n--- a/builtin/rebase.c\n+++ b/builtin/rebase.c\n@@ -93,6 +93,7 @@ struct rebase_options {\n \t} flags;\n \tstruct strbuf git_am_opt;\n \tconst char *action;\n+\tint signoff;\n };\n \n static int is_interactive(struct rebase_options *opts)\n@@ -168,6 +169,11 @@ static int read_basic_state(struct rebase_options *opts)\n \tif (file_exists(state_dir_path(\"verbose\", opts)))\n \t\topts->flags |= REBASE_VERBOSE;\n \n+\tif (file_exists(state_dir_path(\"signoff\", opts))) {\n+\t\topts->signoff = 1;\n+\t\topts->flags |= REBASE_FORCE;\n+\t}\n+\n \tstrbuf_release(&buf);\n \n \treturn 0;\n@@ -249,6 +255,7 @@ static int run_specific_rebase(struct rebase_options *opts)\n \tif (opts->switch_to)\n \t\tadd_var(&script_snippet, \"switch_to\", opts->switch_to);\n \tadd_var(&script_snippet, \"action\", opts->action ? opts->action : \"\");\n+\tadd_var(&script_snippet, \"signoff\", opts->signoff ? \"--signoff\" : \"\");\n \n \tswitch (opts->type) {\n \tcase REBASE_AM:\n@@ -513,6 +520,8 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \t\t{OPTION_NEGBIT, 'n', \"no-stat\", &options.flags, NULL,\n \t\t\tN_(\"do not show diffstat of what changed upstream\"),\n \t\t\tPARSE_OPT_NOARG, NULL, REBASE_DIFFSTAT },\n+\t\tOPT_BOOL(0, \"signoff\", &options.signoff,\n+\t\t\t N_(\"add a Signed-off-by: line to each commit\")),\n \t\tOPT_BIT('f', \"force-rebase\", &options.flags,\n \t\t\tN_(\"cherry-pick all commits, even if unchanged\"),\n \t\t\tREBASE_FORCE),\n@@ -745,6 +754,14 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \t\tbreak;\n \t}\n \n+\tif (options.signoff) {\n+\t\tif (options.type == REBASE_PRESERVE_MERGES)\n+\t\t\tdie(\"cannot combine '--signoff' with \"\n+\t\t\t    \"'--preserve-merges'\");\n+\t\tstrbuf_addstr(&options.git_am_opt, \" --signoff\");\n+\t\toptions.flags |= REBASE_FORCE;\n+\t}\n+\n \tif (!options.root) {\n \t\tif (argc < 1)\n \t\t\tdie(\"TODO: handle @{upstream}\");\n-- \ngitgitgadget\n\n"},{"id":"357367","messageId":"a301ef6bbdcdc1696991123cee078246deb65727.1536098386.git.gitgitgadget@gmail.com","threadId":"49073","inReplyTo":"pull.33.v2.git.gitgitgadget@gmail.com","subject":"[PATCH v2 03/18] builtin rebase: support --rerere-autoupdate","fromName":"Pratik Karki via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2018-09-04T21:59:52Z","receivedAt":"2018-09-04T21:59:55Z","isPatch":true,"sender":{"key":"predatoramigo@gmail.com","avatar":"https://avatars.githubusercontent.com/u/12194950?v=4"},"body":"From: Pratik Karki <predatoramigo@gmail.com>\n\nThe `--rerere-autoupdate` option allows rerere to update the index with\nresolved conflicts. This commit follows closely the equivalent part of\n`git-legacy-rebase.sh`.\n\nSigned-off-by: Pratik Karki <predatoramigo@gmail.com>\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n builtin/rebase.c | 25 +++++++++++++++++++++++++\n 1 file changed, 25 insertions(+)\n\ndiff --git a/builtin/rebase.c b/builtin/rebase.c\nindex a491481120..1729d2d9e2 100644\n--- a/builtin/rebase.c\n+++ b/builtin/rebase.c\n@@ -94,6 +94,7 @@ struct rebase_options {\n \tstruct strbuf git_am_opt;\n \tconst char *action;\n \tint signoff;\n+\tint allow_rerere_autoupdate;\n };\n \n static int is_interactive(struct rebase_options *opts)\n@@ -174,6 +175,21 @@ static int read_basic_state(struct rebase_options *opts)\n \t\topts->flags |= REBASE_FORCE;\n \t}\n \n+\tif (file_exists(state_dir_path(\"allow_rerere_autoupdate\", opts))) {\n+\t\tstrbuf_reset(&buf);\n+\t\tif (read_one(state_dir_path(\"allow_rerere_autoupdate\", opts),\n+\t\t\t    &buf))\n+\t\t\treturn -1;\n+\t\tif (!strcmp(buf.buf, \"--rerere-autoupdate\"))\n+\t\t\topts->allow_rerere_autoupdate = 1;\n+\t\telse if (!strcmp(buf.buf, \"--no-rerere-autoupdate\"))\n+\t\t\topts->allow_rerere_autoupdate = 0;\n+\t\telse\n+\t\t\twarning(_(\"ignoring invalid allow_rerere_autoupdate: \"\n+\t\t\t\t  \"'%s'\"), buf.buf);\n+\t} else\n+\t\topts->allow_rerere_autoupdate = -1;\n+\n \tstrbuf_release(&buf);\n \n \treturn 0;\n@@ -256,6 +272,10 @@ static int run_specific_rebase(struct rebase_options *opts)\n \t\tadd_var(&script_snippet, \"switch_to\", opts->switch_to);\n \tadd_var(&script_snippet, \"action\", opts->action ? opts->action : \"\");\n \tadd_var(&script_snippet, \"signoff\", opts->signoff ? \"--signoff\" : \"\");\n+\tadd_var(&script_snippet, \"allow_rerere_autoupdate\",\n+\t\topts->allow_rerere_autoupdate < 0 ? \"\" :\n+\t\topts->allow_rerere_autoupdate ?\n+\t\t\"--rerere-autoupdate\" : \"--no-rerere-autoupdate\");\n \n \tswitch (opts->type) {\n \tcase REBASE_AM:\n@@ -488,6 +508,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \t\t.type = REBASE_UNSPECIFIED,\n \t\t.flags = REBASE_NO_QUIET,\n \t\t.git_am_opt = STRBUF_INIT,\n+\t\t.allow_rerere_autoupdate  = -1,\n \t};\n \tconst char *branch_name;\n \tint ret, flags, total_argc, in_progress = 0;\n@@ -553,6 +574,10 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \t\tOPT_SET_INT('p', \"preserve-merges\", &options.type,\n \t\t\t    N_(\"try to recreate merges instead of ignoring \"\n \t\t\t       \"them\"), REBASE_PRESERVE_MERGES),\n+\t\tOPT_BOOL(0, \"rerere-autoupdate\",\n+\t\t\t &options.allow_rerere_autoupdate,\n+\t\t\t N_(\"allow rerere to update index  with resolved \"\n+\t\t\t    \"conflict\")),\n \t\tOPT_END(),\n \t};\n \n-- \ngitgitgadget\n\n"},{"id":"357368","messageId":"8f67a3969dc01669b5edd045e2ff92e45a08fb9d.1536098386.git.gitgitgadget@gmail.com","threadId":"49073","inReplyTo":"pull.33.v2.git.gitgitgadget@gmail.com","subject":"[PATCH v2 04/18] builtin rebase: support --committer-date-is-author-date","fromName":"Pratik Karki via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2018-09-04T21:59:53Z","receivedAt":"2018-09-04T21:59:56Z","isPatch":true,"sender":{"key":"predatoramigo@gmail.com","avatar":"https://avatars.githubusercontent.com/u/12194950?v=4"},"body":"From: Pratik Karki <predatoramigo@gmail.com>\n\nThis option is simply handed down to `git am` by way of setting the\n`git_am_opt` variable that is handled by the `git-rebase--am` backend.\n\nSigned-off-by: Pratik Karki <predatoramigo@gmail.com>\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n builtin/rebase.c | 10 ++++++++++\n 1 file changed, 10 insertions(+)\n\ndiff --git a/builtin/rebase.c b/builtin/rebase.c\nindex 1729d2d9e2..eef16206c2 100644\n--- a/builtin/rebase.c\n+++ b/builtin/rebase.c\n@@ -526,6 +526,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \t\tACTION_EDIT_TODO,\n \t\tACTION_SHOW_CURRENT_PATCH,\n \t} action = NO_ACTION;\n+\tint committer_date_is_author_date = 0;\n \tstruct option builtin_rebase_options[] = {\n \t\tOPT_STRING(0, \"onto\", &options.onto_name,\n \t\t\t   N_(\"revision\"),\n@@ -543,6 +544,9 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \t\t\tPARSE_OPT_NOARG, NULL, REBASE_DIFFSTAT },\n \t\tOPT_BOOL(0, \"signoff\", &options.signoff,\n \t\t\t N_(\"add a Signed-off-by: line to each commit\")),\n+\t\tOPT_BOOL(0, \"committer-date-is-author-date\",\n+\t\t\t &committer_date_is_author_date,\n+\t\t\t N_(\"passed to 'git am'\")),\n \t\tOPT_BIT('f', \"force-rebase\", &options.flags,\n \t\t\tN_(\"cherry-pick all commits, even if unchanged\"),\n \t\t\tREBASE_FORCE),\n@@ -763,6 +767,12 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \tif (!(options.flags & REBASE_NO_QUIET))\n \t\tstrbuf_addstr(&options.git_am_opt, \" -q\");\n \n+\tif (committer_date_is_author_date) {\n+\t\tstrbuf_addstr(&options.git_am_opt,\n+\t\t\t      \" --committer-date-is-author-date\");\n+\t\toptions.flags |= REBASE_FORCE;\n+\t}\n+\n \tswitch (options.type) {\n \tcase REBASE_MERGE:\n \tcase REBASE_INTERACTIVE:\n-- \ngitgitgadget\n\n"},{"id":"357369","messageId":"f04394a5002859d7e95f3bfc518028dcfb6d202d.1536098386.git.gitgitgadget@gmail.com","threadId":"49073","inReplyTo":"pull.33.v2.git.gitgitgadget@gmail.com","subject":"[PATCH v2 05/18] builtin rebase: support `ignore-whitespace` option","fromName":"Pratik Karki via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2018-09-04T21:59:54Z","receivedAt":"2018-09-04T21:59:57Z","isPatch":true,"sender":{"key":"predatoramigo@gmail.com","avatar":"https://avatars.githubusercontent.com/u/12194950?v=4"},"body":"From: Pratik Karki <predatoramigo@gmail.com>\n\nThis commit adds support for the `--ignore-whitespace` option\nof the rebase command. This option is simply passed to the\n`--am` backend.\n\nSigned-off-by: Pratik Karki <predatoramigo@gmail.com>\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n builtin/rebase.c | 6 ++++++\n 1 file changed, 6 insertions(+)\n\ndiff --git a/builtin/rebase.c b/builtin/rebase.c\nindex eef16206c2..7490d215ef 100644\n--- a/builtin/rebase.c\n+++ b/builtin/rebase.c\n@@ -527,6 +527,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \t\tACTION_SHOW_CURRENT_PATCH,\n \t} action = NO_ACTION;\n \tint committer_date_is_author_date = 0;\n+\tint ignore_whitespace = 0;\n \tstruct option builtin_rebase_options[] = {\n \t\tOPT_STRING(0, \"onto\", &options.onto_name,\n \t\t\t   N_(\"revision\"),\n@@ -542,6 +543,8 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \t\t{OPTION_NEGBIT, 'n', \"no-stat\", &options.flags, NULL,\n \t\t\tN_(\"do not show diffstat of what changed upstream\"),\n \t\t\tPARSE_OPT_NOARG, NULL, REBASE_DIFFSTAT },\n+\t\tOPT_BOOL(0, \"ignore-whitespace\", &ignore_whitespace,\n+\t\t\t N_(\"passed to 'git apply'\")),\n \t\tOPT_BOOL(0, \"signoff\", &options.signoff,\n \t\t\t N_(\"add a Signed-off-by: line to each commit\")),\n \t\tOPT_BOOL(0, \"committer-date-is-author-date\",\n@@ -773,6 +776,9 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \t\toptions.flags |= REBASE_FORCE;\n \t}\n \n+\tif (ignore_whitespace)\n+\t\tstrbuf_addstr(&options.git_am_opt, \" --ignore-whitespace\");\n+\n \tswitch (options.type) {\n \tcase REBASE_MERGE:\n \tcase REBASE_INTERACTIVE:\n-- \ngitgitgadget\n\n"},{"id":"357372","messageId":"83bb27750972a39c90d78ecebd07ac32745ab6c4.1536098386.git.gitgitgadget@gmail.com","threadId":"49073","inReplyTo":"pull.33.v2.git.gitgitgadget@gmail.com","subject":"[PATCH v2 06/18] builtin rebase: support `ignore-date` option","fromName":"Pratik Karki via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2018-09-04T21:59:56Z","receivedAt":"2018-09-04T21:59:59Z","isPatch":true,"sender":{"key":"predatoramigo@gmail.com","avatar":"https://avatars.githubusercontent.com/u/12194950?v=4"},"body":"From: Pratik Karki <predatoramigo@gmail.com>\n\nThis commit adds support for `--ignore-date` which is passed to `git am`\nto easily change the dates of the rebased commits.\n\nSigned-off-by: Pratik Karki <predatoramigo@gmail.com>\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n builtin/rebase.c | 8 ++++++++\n 1 file changed, 8 insertions(+)\n\ndiff --git a/builtin/rebase.c b/builtin/rebase.c\nindex 7490d215ef..42ee040da3 100644\n--- a/builtin/rebase.c\n+++ b/builtin/rebase.c\n@@ -527,6 +527,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \t\tACTION_SHOW_CURRENT_PATCH,\n \t} action = NO_ACTION;\n \tint committer_date_is_author_date = 0;\n+\tint ignore_date = 0;\n \tint ignore_whitespace = 0;\n \tstruct option builtin_rebase_options[] = {\n \t\tOPT_STRING(0, \"onto\", &options.onto_name,\n@@ -550,6 +551,8 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \t\tOPT_BOOL(0, \"committer-date-is-author-date\",\n \t\t\t &committer_date_is_author_date,\n \t\t\t N_(\"passed to 'git am'\")),\n+\t\tOPT_BOOL(0, \"ignore-date\", &ignore_date,\n+\t\t\t N_(\"passed to 'git am'\")),\n \t\tOPT_BIT('f', \"force-rebase\", &options.flags,\n \t\t\tN_(\"cherry-pick all commits, even if unchanged\"),\n \t\t\tREBASE_FORCE),\n@@ -779,6 +782,11 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \tif (ignore_whitespace)\n \t\tstrbuf_addstr(&options.git_am_opt, \" --ignore-whitespace\");\n \n+\tif (ignore_date) {\n+\t\tstrbuf_addstr(&options.git_am_opt, \" --ignore-date\");\n+\t\toptions.flags |= REBASE_FORCE;\n+\t}\n+\n \tswitch (options.type) {\n \tcase REBASE_MERGE:\n \tcase REBASE_INTERACTIVE:\n-- \ngitgitgadget\n\n"},{"id":"357373","messageId":"a8f12bf01ffb5411374843083cb18a7fa84a4935.1536098386.git.gitgitgadget@gmail.com","threadId":"49073","inReplyTo":"pull.33.v2.git.gitgitgadget@gmail.com","subject":"[PATCH v2 07/18] builtin rebase: support `keep-empty` option","fromName":"Pratik Karki via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2018-09-04T21:59:57Z","receivedAt":"2018-09-04T22:00:00Z","isPatch":true,"sender":{"key":"predatoramigo@gmail.com","avatar":"https://avatars.githubusercontent.com/u/12194950?v=4"},"body":"From: Pratik Karki <predatoramigo@gmail.com>\n\nThe `--keep-empty` option can be used to keep the commits that do not\nchange anything from its parents in the result.\n\nWhile the scripted version uses `interactive_rebase=implied` to indicate\nthat the rebase needs to use the `git-rebase--interactive` backend in\nnon-interactive mode as fallback when figuring out which backend to use,\nthe C version needs to use a different route because the backend will\nalready be chosen during the `parse_options()` call.\n\nSigned-off-by: Pratik Karki <predatoramigo@gmail.com>\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n builtin/rebase.c | 24 ++++++++++++++++++++++++\n 1 file changed, 24 insertions(+)\n\ndiff --git a/builtin/rebase.c b/builtin/rebase.c\nindex 42ee040da3..9c00f3568f 100644\n--- a/builtin/rebase.c\n+++ b/builtin/rebase.c\n@@ -95,6 +95,7 @@ struct rebase_options {\n \tconst char *action;\n \tint signoff;\n \tint allow_rerere_autoupdate;\n+\tint keep_empty;\n };\n \n static int is_interactive(struct rebase_options *opts)\n@@ -103,6 +104,23 @@ static int is_interactive(struct rebase_options *opts)\n \t\topts->type == REBASE_PRESERVE_MERGES;\n }\n \n+static void imply_interactive(struct rebase_options *opts, const char *option)\n+{\n+\tswitch (opts->type) {\n+\tcase REBASE_AM:\n+\t\tdie(_(\"%s requires an interactive rebase\"), option);\n+\t\tbreak;\n+\tcase REBASE_INTERACTIVE:\n+\tcase REBASE_PRESERVE_MERGES:\n+\t\tbreak;\n+\tcase REBASE_MERGE:\n+\t\t/* we silently *upgrade* --merge to --interactive if needed */\n+\tdefault:\n+\t\topts->type = REBASE_INTERACTIVE; /* implied */\n+\t\tbreak;\n+\t}\n+}\n+\n /* Returns the filename prefixed by the state_dir */\n static const char *state_dir_path(const char *filename, struct rebase_options *opts)\n {\n@@ -276,6 +294,7 @@ static int run_specific_rebase(struct rebase_options *opts)\n \t\topts->allow_rerere_autoupdate < 0 ? \"\" :\n \t\topts->allow_rerere_autoupdate ?\n \t\t\"--rerere-autoupdate\" : \"--no-rerere-autoupdate\");\n+\tadd_var(&script_snippet, \"keep_empty\", opts->keep_empty ? \"yes\" : \"\");\n \n \tswitch (opts->type) {\n \tcase REBASE_AM:\n@@ -588,6 +607,8 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \t\t\t &options.allow_rerere_autoupdate,\n \t\t\t N_(\"allow rerere to update index  with resolved \"\n \t\t\t    \"conflict\")),\n+\t\tOPT_BOOL('k', \"keep-empty\", &options.keep_empty,\n+\t\t\t N_(\"preserve empty commits during rebase\")),\n \t\tOPT_END(),\n \t};\n \n@@ -787,6 +808,9 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \t\toptions.flags |= REBASE_FORCE;\n \t}\n \n+\tif (options.keep_empty)\n+\t\timply_interactive(&options, \"--keep-empty\");\n+\n \tswitch (options.type) {\n \tcase REBASE_MERGE:\n \tcase REBASE_INTERACTIVE:\n-- \ngitgitgadget\n\n"},{"id":"357371","messageId":"1b6851e5e1e08eaaaa9e25c4a3cdae7ea1e6f8e9.1536098386.git.gitgitgadget@gmail.com","threadId":"49073","inReplyTo":"pull.33.v2.git.gitgitgadget@gmail.com","subject":"[PATCH v2 08/18] builtin rebase: support `--autosquash`","fromName":"Pratik Karki via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2018-09-04T21:59:58Z","receivedAt":"2018-09-04T22:00:01Z","isPatch":true,"sender":{"key":"predatoramigo@gmail.com","avatar":"https://avatars.githubusercontent.com/u/12194950?v=4"},"body":"From: Pratik Karki <predatoramigo@gmail.com>\n\nThis commit adds support for the `--autosquash` option which is used to\nautomatically squash the commits marked as `squash` or `fixup` in their\nmessages. This is converted following `git-legacy-rebase.sh` closely.\n\nThis option can also be configured via the Git config setting\nrebase.autosquash. To support this, we also add a custom\nrebase_config() function in this commit that will be used instead (and\nfalls back to) git_default_config().\n\nSigned-off-by: Pratik Karki <predatoramigo@gmail.com>\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n builtin/rebase.c | 10 ++++++++++\n 1 file changed, 10 insertions(+)\n\ndiff --git a/builtin/rebase.c b/builtin/rebase.c\nindex 9c00f3568f..c80eebfbd2 100644\n--- a/builtin/rebase.c\n+++ b/builtin/rebase.c\n@@ -96,6 +96,7 @@ struct rebase_options {\n \tint signoff;\n \tint allow_rerere_autoupdate;\n \tint keep_empty;\n+\tint autosquash;\n };\n \n static int is_interactive(struct rebase_options *opts)\n@@ -295,6 +296,7 @@ static int run_specific_rebase(struct rebase_options *opts)\n \t\topts->allow_rerere_autoupdate ?\n \t\t\"--rerere-autoupdate\" : \"--no-rerere-autoupdate\");\n \tadd_var(&script_snippet, \"keep_empty\", opts->keep_empty ? \"yes\" : \"\");\n+\tadd_var(&script_snippet, \"autosquash\", opts->autosquash ? \"t\" : \"\");\n \n \tswitch (opts->type) {\n \tcase REBASE_AM:\n@@ -455,6 +457,11 @@ static int rebase_config(const char *var, const char *value, void *data)\n \t\treturn 0;\n \t}\n \n+\tif (!strcmp(var, \"rebase.autosquash\")) {\n+\t\topts->autosquash = git_config_bool(var, value);\n+\t\treturn 0;\n+\t}\n+\n \treturn git_default_config(var, value, data);\n }\n \n@@ -609,6 +616,9 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \t\t\t    \"conflict\")),\n \t\tOPT_BOOL('k', \"keep-empty\", &options.keep_empty,\n \t\t\t N_(\"preserve empty commits during rebase\")),\n+\t\tOPT_BOOL(0, \"autosquash\", &options.autosquash,\n+\t\t\t N_(\"move commits that begin with \"\n+\t\t\t    \"squash!/fixup! under -i\")),\n \t\tOPT_END(),\n \t};\n \n-- \ngitgitgadget\n\n"},{"id":"357370","messageId":"b8055fb258ef07ba55e2e8c1ab3c3a5e91ddd16f.1536098386.git.gitgitgadget@gmail.com","threadId":"49073","inReplyTo":"pull.33.v2.git.gitgitgadget@gmail.com","subject":"[PATCH v2 09/18] builtin rebase: support `--gpg-sign` option","fromName":"Pratik Karki via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2018-09-04T22:00:00Z","receivedAt":"2018-09-04T22:00:03Z","isPatch":true,"sender":{"key":"predatoramigo@gmail.com","avatar":"https://avatars.githubusercontent.com/u/12194950?v=4"},"body":"From: Pratik Karki <predatoramigo@gmail.com>\n\nThis commit introduces support for `--gpg-sign` option which is used\nto GPG-sign commits.\n\nSigned-off-by: Pratik Karki <predatoramigo@gmail.com>\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n builtin/rebase.c | 27 +++++++++++++++++++++++++++\n 1 file changed, 27 insertions(+)\n\ndiff --git a/builtin/rebase.c b/builtin/rebase.c\nindex c80eebfbd2..0ab86b7c4c 100644\n--- a/builtin/rebase.c\n+++ b/builtin/rebase.c\n@@ -97,6 +97,7 @@ struct rebase_options {\n \tint allow_rerere_autoupdate;\n \tint keep_empty;\n \tint autosquash;\n+\tchar *gpg_sign_opt;\n };\n \n static int is_interactive(struct rebase_options *opts)\n@@ -209,6 +210,15 @@ static int read_basic_state(struct rebase_options *opts)\n \t} else\n \t\topts->allow_rerere_autoupdate = -1;\n \n+\tif (file_exists(state_dir_path(\"gpg_sign_opt\", opts))) {\n+\t\tstrbuf_reset(&buf);\n+\t\tif (read_one(state_dir_path(\"gpg_sign_opt\", opts),\n+\t\t\t    &buf))\n+\t\t\treturn -1;\n+\t\tfree(opts->gpg_sign_opt);\n+\t\topts->gpg_sign_opt = xstrdup(buf.buf);\n+\t}\n+\n \tstrbuf_release(&buf);\n \n \treturn 0;\n@@ -297,6 +307,7 @@ static int run_specific_rebase(struct rebase_options *opts)\n \t\t\"--rerere-autoupdate\" : \"--no-rerere-autoupdate\");\n \tadd_var(&script_snippet, \"keep_empty\", opts->keep_empty ? \"yes\" : \"\");\n \tadd_var(&script_snippet, \"autosquash\", opts->autosquash ? \"t\" : \"\");\n+\tadd_var(&script_snippet, \"gpg_sign_opt\", opts->gpg_sign_opt);\n \n \tswitch (opts->type) {\n \tcase REBASE_AM:\n@@ -462,6 +473,13 @@ static int rebase_config(const char *var, const char *value, void *data)\n \t\treturn 0;\n \t}\n \n+\tif (!strcmp(var, \"commit.gpgsign\")) {\n+\t\tfree(opts->gpg_sign_opt);\n+\t\topts->gpg_sign_opt = git_config_bool(var, value) ?\n+\t\t\txstrdup(\"-S\") : NULL;\n+\t\treturn 0;\n+\t}\n+\n \treturn git_default_config(var, value, data);\n }\n \n@@ -555,6 +573,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \tint committer_date_is_author_date = 0;\n \tint ignore_date = 0;\n \tint ignore_whitespace = 0;\n+\tconst char *gpg_sign = NULL;\n \tstruct option builtin_rebase_options[] = {\n \t\tOPT_STRING(0, \"onto\", &options.onto_name,\n \t\t\t   N_(\"revision\"),\n@@ -619,6 +638,8 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \t\tOPT_BOOL(0, \"autosquash\", &options.autosquash,\n \t\t\t N_(\"move commits that begin with \"\n \t\t\t    \"squash!/fixup! under -i\")),\n+\t\tOPT_STRING('S', \"gpg-sign\", &gpg_sign,\n+\t\t\t   N_(\"gpg-sign?\"), N_(\"GPG-sign commits\")),\n \t\tOPT_END(),\n \t};\n \n@@ -821,6 +842,11 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \tif (options.keep_empty)\n \t\timply_interactive(&options, \"--keep-empty\");\n \n+\tif (gpg_sign) {\n+\t\tfree(options.gpg_sign_opt);\n+\t\toptions.gpg_sign_opt = xstrfmt(\"-S%s\", gpg_sign);\n+\t}\n+\n \tswitch (options.type) {\n \tcase REBASE_MERGE:\n \tcase REBASE_INTERACTIVE:\n@@ -1046,5 +1072,6 @@ run_rebase:\n cleanup:\n \tstrbuf_release(&revisions);\n \tfree(options.head_name);\n+\tfree(options.gpg_sign_opt);\n \treturn ret;\n }\n-- \ngitgitgadget\n\n"},{"id":"357374","messageId":"5e5e5cb758356d8a9745949b10ba99991483b3d9.1536098386.git.gitgitgadget@gmail.com","threadId":"49073","inReplyTo":"pull.33.v2.git.gitgitgadget@gmail.com","subject":"[PATCH v2 11/18] builtin rebase: support `--autostash` option","fromName":"Pratik Karki via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2018-09-04T22:00:02Z","receivedAt":"2018-09-04T22:00:06Z","isPatch":true,"sender":{"key":"predatoramigo@gmail.com","avatar":"https://avatars.githubusercontent.com/u/12194950?v=4"},"body":"From: Pratik Karki <predatoramigo@gmail.com>\n\nTo support `--autostash` we introduce a function `apply_autostash()`\njust like in `git-legacy-rebase.sh`.\n\nRather than refactoring and using the same function that exists in\n`sequencer.c`, we go a different route here, to avoid clashes with\nthe sister GSoC project that turns the interactive rebase into a\nbuiltin.\n\nSigned-off-by: Pratik Karki <predatoramigo@gmail.com>\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n builtin/rebase.c | 117 +++++++++++++++++++++++++++++++++++++++++++----\n 1 file changed, 109 insertions(+), 8 deletions(-)\n\ndiff --git a/builtin/rebase.c b/builtin/rebase.c\nindex 63ffe5e1ff..1e35b82d9a 100644\n--- a/builtin/rebase.c\n+++ b/builtin/rebase.c\n@@ -63,12 +63,6 @@ static int use_builtin_rebase(void)\n \treturn ret;\n }\n \n-static int apply_autostash(void)\n-{\n-\twarning(\"TODO\");\n-\treturn 0;\n-}\n-\n struct rebase_options {\n \tenum rebase_type type;\n \tconst char *state_dir;\n@@ -98,6 +92,7 @@ struct rebase_options {\n \tint keep_empty;\n \tint autosquash;\n \tchar *gpg_sign_opt;\n+\tint autostash;\n };\n \n static int is_interactive(struct rebase_options *opts)\n@@ -224,13 +219,56 @@ static int read_basic_state(struct rebase_options *opts)\n \treturn 0;\n }\n \n+static int apply_autostash(struct rebase_options *opts)\n+{\n+\tconst char *path = state_dir_path(\"autostash\", opts);\n+\tstruct strbuf autostash = STRBUF_INIT;\n+\tstruct child_process stash_apply = CHILD_PROCESS_INIT;\n+\n+\tif (!file_exists(path))\n+\t\treturn 0;\n+\n+\tif (read_one(state_dir_path(\"autostash\", opts), &autostash))\n+\t\treturn error(_(\"Could not read '%s'\"), path);\n+\targv_array_pushl(&stash_apply.args,\n+\t\t\t \"stash\", \"apply\", autostash.buf, NULL);\n+\tstash_apply.git_cmd = 1;\n+\tstash_apply.no_stderr = stash_apply.no_stdout =\n+\t\tstash_apply.no_stdin = 1;\n+\tif (!run_command(&stash_apply))\n+\t\tprintf(_(\"Applied autostash.\\n\"));\n+\telse {\n+\t\tstruct argv_array args = ARGV_ARRAY_INIT;\n+\t\tint res = 0;\n+\n+\t\targv_array_pushl(&args,\n+\t\t\t\t \"stash\", \"store\", \"-m\", \"autostash\", \"-q\",\n+\t\t\t\t autostash.buf, NULL);\n+\t\tif (run_command_v_opt(args.argv, RUN_GIT_CMD))\n+\t\t\tres = error(_(\"Cannot store %s\"), autostash.buf);\n+\t\targv_array_clear(&args);\n+\t\tstrbuf_release(&autostash);\n+\t\tif (res)\n+\t\t\treturn res;\n+\n+\t\tfprintf(stderr,\n+\t\t\t_(\"Applying autostash resulted in conflicts.\\n\"\n+\t\t\t  \"Your changes are safe in the stash.\\n\"\n+\t\t\t  \"You can run \\\"git stash pop\\\" or \\\"git stash drop\\\" \"\n+\t\t\t  \"at any time.\\n\"));\n+\t}\n+\n+\tstrbuf_release(&autostash);\n+\treturn 0;\n+}\n+\n static int finish_rebase(struct rebase_options *opts)\n {\n \tstruct strbuf dir = STRBUF_INIT;\n \tconst char *argv_gc_auto[] = { \"gc\", \"--auto\", NULL };\n \n \tdelete_ref(NULL, \"REBASE_HEAD\", NULL, REF_NO_DEREF);\n-\tapply_autostash();\n+\tapply_autostash(opts);\n \tclose_all_packs(the_repository->objects);\n \t/*\n \t * We ignore errors in 'gc --auto', since the\n@@ -345,7 +383,7 @@ static int run_specific_rebase(struct rebase_options *opts)\n \t} else if (status == 2) {\n \t\tstruct strbuf dir = STRBUF_INIT;\n \n-\t\tapply_autostash();\n+\t\tapply_autostash(opts);\n \t\tstrbuf_addstr(&dir, opts->state_dir);\n \t\tremove_dir_recursively(&dir, 0);\n \t\tstrbuf_release(&dir);\n@@ -480,6 +518,11 @@ static int rebase_config(const char *var, const char *value, void *data)\n \t\treturn 0;\n \t}\n \n+\tif (!strcmp(var, \"rebase.autostash\")) {\n+\t\topts->autostash = git_config_bool(var, value);\n+\t\treturn 0;\n+\t}\n+\n \treturn git_default_config(var, value, data);\n }\n \n@@ -646,6 +689,8 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \t\t\t\tN_(\"whitespace\"), N_(\"passed to 'git apply'\")),\n \t\tOPT_SET_INT('C', 0, &opt_c, N_(\"passed to 'git apply'\"),\n \t\t\t    REBASE_AM),\n+\t\tOPT_BOOL(0, \"autostash\", &options.autostash,\n+\t\t\t N_(\"automatically stash/stash pop before and after\")),\n \t\tOPT_END(),\n \t};\n \n@@ -975,6 +1020,62 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \tif (read_index(the_repository->index) < 0)\n \t\tdie(_(\"could not read index\"));\n \n+\tif (options.autostash) {\n+\t\tstruct lock_file lock_file = LOCK_INIT;\n+\t\tint fd;\n+\n+\t\tfd = hold_locked_index(&lock_file, 0);\n+\t\trefresh_cache(REFRESH_QUIET);\n+\t\tif (0 <= fd)\n+\t\t\tupdate_index_if_able(&the_index, &lock_file);\n+\t\trollback_lock_file(&lock_file);\n+\n+\t\tif (has_unstaged_changes(0) || has_uncommitted_changes(0)) {\n+\t\t\tconst char *autostash =\n+\t\t\t\tstate_dir_path(\"autostash\", &options);\n+\t\t\tstruct child_process stash = CHILD_PROCESS_INIT;\n+\t\t\tstruct object_id oid;\n+\t\t\tstruct commit *head =\n+\t\t\t\tlookup_commit_reference(the_repository,\n+\t\t\t\t\t\t\t&options.orig_head);\n+\n+\t\t\targv_array_pushl(&stash.args,\n+\t\t\t\t\t \"stash\", \"create\", \"autostash\", NULL);\n+\t\t\tstash.git_cmd = 1;\n+\t\t\tstash.no_stdin = 1;\n+\t\t\tstrbuf_reset(&buf);\n+\t\t\tif (capture_command(&stash, &buf, GIT_MAX_HEXSZ))\n+\t\t\t\tdie(_(\"Cannot autostash\"));\n+\t\t\tstrbuf_trim_trailing_newline(&buf);\n+\t\t\tif (get_oid(buf.buf, &oid))\n+\t\t\t\tdie(_(\"Unexpected stash response: '%s'\"),\n+\t\t\t\t    buf.buf);\n+\t\t\tstrbuf_reset(&buf);\n+\t\t\tstrbuf_add_unique_abbrev(&buf, &oid, DEFAULT_ABBREV);\n+\n+\t\t\tif (safe_create_leading_directories_const(autostash))\n+\t\t\t\tdie(_(\"Could not create directory for '%s'\"),\n+\t\t\t\t    options.state_dir);\n+\t\t\twrite_file(autostash, \"%s\", buf.buf);\n+\t\t\tprintf(_(\"Created autostash: %s\\n\"), buf.buf);\n+\t\t\tif (reset_head(&head->object.oid, \"reset --hard\",\n+\t\t\t\t       NULL, 0) < 0)\n+\t\t\t\tdie(_(\"could not reset --hard\"));\n+\t\t\tprintf(_(\"HEAD is now at %s\"),\n+\t\t\t       find_unique_abbrev(&head->object.oid,\n+\t\t\t\t\t\t  DEFAULT_ABBREV));\n+\t\t\tstrbuf_reset(&buf);\n+\t\t\tpp_commit_easy(CMIT_FMT_ONELINE, head, &buf);\n+\t\t\tif (buf.len > 0)\n+\t\t\t\tprintf(\" %s\", buf.buf);\n+\t\t\tputchar('\\n');\n+\n+\t\t\tif (discard_index(the_repository->index) < 0 ||\n+\t\t\t\tread_index(the_repository->index) < 0)\n+\t\t\t\tdie(_(\"could not read index\"));\n+\t\t}\n+\t}\n+\n \tif (require_clean_work_tree(\"rebase\",\n \t\t\t\t    _(\"Please commit or stash them.\"), 1, 1)) {\n \t\tret = 1;\n-- \ngitgitgadget\n\n"},{"id":"357375","messageId":"98908573ce37abb3026061a8700dc74c23056955.1536098386.git.gitgitgadget@gmail.com","threadId":"49073","inReplyTo":"pull.33.v2.git.gitgitgadget@gmail.com","subject":"[PATCH v2 10/18] builtin rebase: support `-C` and `--whitespace=<type>`","fromName":"Pratik Karki via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2018-09-04T22:00:01Z","receivedAt":"2018-09-04T22:00:06Z","isPatch":true,"sender":{"key":"predatoramigo@gmail.com","avatar":"https://avatars.githubusercontent.com/u/12194950?v=4"},"body":"From: Pratik Karki <predatoramigo@gmail.com>\n\nThis commit converts more code from the shell script version to the\nbuiltin rebase. In this instance, we just have to be careful to\nkeep support for passing multiple `--whitespace` options, as the\nshell script version does so, too.\n\nSigned-off-by: Pratik Karki <predatoramigo@gmail.com>\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n builtin/rebase.c | 23 +++++++++++++++++++++++\n 1 file changed, 23 insertions(+)\n\ndiff --git a/builtin/rebase.c b/builtin/rebase.c\nindex 0ab86b7c4c..63ffe5e1ff 100644\n--- a/builtin/rebase.c\n+++ b/builtin/rebase.c\n@@ -574,6 +574,8 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \tint ignore_date = 0;\n \tint ignore_whitespace = 0;\n \tconst char *gpg_sign = NULL;\n+\tint opt_c = -1;\n+\tstruct string_list whitespace = STRING_LIST_INIT_NODUP;\n \tstruct option builtin_rebase_options[] = {\n \t\tOPT_STRING(0, \"onto\", &options.onto_name,\n \t\t\t   N_(\"revision\"),\n@@ -640,6 +642,10 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \t\t\t    \"squash!/fixup! under -i\")),\n \t\tOPT_STRING('S', \"gpg-sign\", &gpg_sign,\n \t\t\t   N_(\"gpg-sign?\"), N_(\"GPG-sign commits\")),\n+\t\tOPT_STRING_LIST(0, \"whitespace\", &whitespace,\n+\t\t\t\tN_(\"whitespace\"), N_(\"passed to 'git apply'\")),\n+\t\tOPT_SET_INT('C', 0, &opt_c, N_(\"passed to 'git apply'\"),\n+\t\t\t    REBASE_AM),\n \t\tOPT_END(),\n \t};\n \n@@ -847,6 +853,23 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \t\toptions.gpg_sign_opt = xstrfmt(\"-S%s\", gpg_sign);\n \t}\n \n+\tif (opt_c >= 0)\n+\t\tstrbuf_addf(&options.git_am_opt, \" -C%d\", opt_c);\n+\n+\tif (whitespace.nr) {\n+\t\tint i;\n+\n+\t\tfor (i = 0; i < whitespace.nr; i++) {\n+\t\t\tconst char *item = whitespace.items[i].string;\n+\n+\t\t\tstrbuf_addf(&options.git_am_opt, \" --whitespace=%s\",\n+\t\t\t\t    item);\n+\n+\t\t\tif ((!strcmp(item, \"fix\")) || (!strcmp(item, \"strip\")))\n+\t\t\t\toptions.flags |= REBASE_FORCE;\n+\t\t}\n+\t}\n+\n \tswitch (options.type) {\n \tcase REBASE_MERGE:\n \tcase REBASE_INTERACTIVE:\n-- \ngitgitgadget\n\n"},{"id":"357376","messageId":"01e5cb3e9185633fd6a07fcbdde99727b414d94d.1536098386.git.gitgitgadget@gmail.com","threadId":"49073","inReplyTo":"pull.33.v2.git.gitgitgadget@gmail.com","subject":"[PATCH v2 12/18] builtin rebase: support `--exec`","fromName":"Pratik Karki via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2018-09-04T22:00:04Z","receivedAt":"2018-09-04T22:00:09Z","isPatch":true,"sender":{"key":"predatoramigo@gmail.com","avatar":"https://avatars.githubusercontent.com/u/12194950?v=4"},"body":"From: Pratik Karki <predatoramigo@gmail.com>\n\nThis commit adds support for the `--exec` option which takes a shell\ncommand-line as argument. This argument will be appended as an `exec\n<cmd>` command after each line in the todo list that creates a commit in\nthe final history.  commands.\n\nNote: while the shell script version of `git rebase` assigned the empty\nstring to `cmd` by default, we *unset* it here because the code looks\nnicer and it does not change the behavior.\n\nThe `--exec` option requires `--interactive` machinery.\n\nSigned-off-by: Pratik Karki <predatoramigo@gmail.com>\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n builtin/rebase.c | 18 ++++++++++++++++++\n 1 file changed, 18 insertions(+)\n\ndiff --git a/builtin/rebase.c b/builtin/rebase.c\nindex 1e35b82d9a..2547be9efe 100644\n--- a/builtin/rebase.c\n+++ b/builtin/rebase.c\n@@ -93,6 +93,7 @@ struct rebase_options {\n \tint autosquash;\n \tchar *gpg_sign_opt;\n \tint autostash;\n+\tchar *cmd;\n };\n \n static int is_interactive(struct rebase_options *opts)\n@@ -346,6 +347,7 @@ static int run_specific_rebase(struct rebase_options *opts)\n \tadd_var(&script_snippet, \"keep_empty\", opts->keep_empty ? \"yes\" : \"\");\n \tadd_var(&script_snippet, \"autosquash\", opts->autosquash ? \"t\" : \"\");\n \tadd_var(&script_snippet, \"gpg_sign_opt\", opts->gpg_sign_opt);\n+\tadd_var(&script_snippet, \"cmd\", opts->cmd);\n \n \tswitch (opts->type) {\n \tcase REBASE_AM:\n@@ -619,6 +621,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \tconst char *gpg_sign = NULL;\n \tint opt_c = -1;\n \tstruct string_list whitespace = STRING_LIST_INIT_NODUP;\n+\tstruct string_list exec = STRING_LIST_INIT_NODUP;\n \tstruct option builtin_rebase_options[] = {\n \t\tOPT_STRING(0, \"onto\", &options.onto_name,\n \t\t\t   N_(\"revision\"),\n@@ -691,6 +694,9 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \t\t\t    REBASE_AM),\n \t\tOPT_BOOL(0, \"autostash\", &options.autostash,\n \t\t\t N_(\"automatically stash/stash pop before and after\")),\n+\t\tOPT_STRING_LIST('x', \"exec\", &exec, N_(\"exec\"),\n+\t\t\t\tN_(\"add exec lines after each commit of the \"\n+\t\t\t\t   \"editable list\")),\n \t\tOPT_END(),\n \t};\n \n@@ -915,6 +921,17 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \t\t}\n \t}\n \n+\tif (exec.nr) {\n+\t\tint i;\n+\n+\t\timply_interactive(&options, \"--exec\");\n+\n+\t\tstrbuf_reset(&buf);\n+\t\tfor (i = 0; i < exec.nr; i++)\n+\t\t\tstrbuf_addf(&buf, \"exec %s\\n\", exec.items[i].string);\n+\t\toptions.cmd = xstrdup(buf.buf);\n+\t}\n+\n \tswitch (options.type) {\n \tcase REBASE_MERGE:\n \tcase REBASE_INTERACTIVE:\n@@ -1197,5 +1214,6 @@ cleanup:\n \tstrbuf_release(&revisions);\n \tfree(options.head_name);\n \tfree(options.gpg_sign_opt);\n+\tfree(options.cmd);\n \treturn ret;\n }\n-- \ngitgitgadget\n\n"},{"id":"357377","messageId":"1c723ad5920a6282139c8fc0bb2f9f3b2e2cede9.1536098386.git.gitgitgadget@gmail.com","threadId":"49073","inReplyTo":"pull.33.v2.git.gitgitgadget@gmail.com","subject":"[PATCH v2 13/18] builtin rebase: support `--allow-empty-message` option","fromName":"Pratik Karki via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2018-09-04T22:00:05Z","receivedAt":"2018-09-04T22:00:10Z","isPatch":true,"sender":{"key":"predatoramigo@gmail.com","avatar":"https://avatars.githubusercontent.com/u/12194950?v=4"},"body":"From: Pratik Karki <predatoramigo@gmail.com>\n\nThis commit introduces the `--allow-empty-message` option to\n`builtin/rebase.c`. The motivation behind this option is: if there are\nempty messages (which is not allowed in Git by default, but can be\nimported from different version control systems), the rebase will fail.\n\nUsing `--allow-empty-message` overrides that behaviour which will allow\nthe commits having empty messages to continue in rebase operation.\n\nNote: a very recent change made this the default in the shell scripted\n`git rebase`, therefore the builtin rebase does the same.\n\nSigned-off-by: Pratik Karki <predatoramigo@gmail.com>\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n builtin/rebase.c | 7 +++++++\n 1 file changed, 7 insertions(+)\n\ndiff --git a/builtin/rebase.c b/builtin/rebase.c\nindex 2547be9efe..3e37603da4 100644\n--- a/builtin/rebase.c\n+++ b/builtin/rebase.c\n@@ -94,6 +94,7 @@ struct rebase_options {\n \tchar *gpg_sign_opt;\n \tint autostash;\n \tchar *cmd;\n+\tint allow_empty_message;\n };\n \n static int is_interactive(struct rebase_options *opts)\n@@ -348,6 +349,8 @@ static int run_specific_rebase(struct rebase_options *opts)\n \tadd_var(&script_snippet, \"autosquash\", opts->autosquash ? \"t\" : \"\");\n \tadd_var(&script_snippet, \"gpg_sign_opt\", opts->gpg_sign_opt);\n \tadd_var(&script_snippet, \"cmd\", opts->cmd);\n+\tadd_var(&script_snippet, \"allow_empty_message\",\n+\t\topts->allow_empty_message ?  \"--allow-empty-message\" : \"\");\n \n \tswitch (opts->type) {\n \tcase REBASE_AM:\n@@ -598,6 +601,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \t\t.flags = REBASE_NO_QUIET,\n \t\t.git_am_opt = STRBUF_INIT,\n \t\t.allow_rerere_autoupdate  = -1,\n+\t\t.allow_empty_message = 1,\n \t};\n \tconst char *branch_name;\n \tint ret, flags, total_argc, in_progress = 0;\n@@ -697,6 +701,9 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \t\tOPT_STRING_LIST('x', \"exec\", &exec, N_(\"exec\"),\n \t\t\t\tN_(\"add exec lines after each commit of the \"\n \t\t\t\t   \"editable list\")),\n+\t\tOPT_BOOL(0, \"allow-empty-message\",\n+\t\t\t &options.allow_empty_message,\n+\t\t\t N_(\"allow rebasing commits with empty messages\")),\n \t\tOPT_END(),\n \t};\n \n-- \ngitgitgadget\n\n"},{"id":"357378","messageId":"1bebcde41cf42d74278ad520d60255ebd0bbe8c5.1536098386.git.gitgitgadget@gmail.com","threadId":"49073","inReplyTo":"pull.33.v2.git.gitgitgadget@gmail.com","subject":"[PATCH v2 14/18] builtin rebase: support --rebase-merges[=[no-]rebase-cousins]","fromName":"Pratik Karki via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2018-09-04T22:00:07Z","receivedAt":"2018-09-04T22:00:11Z","isPatch":true,"sender":{"key":"predatoramigo@gmail.com","avatar":"https://avatars.githubusercontent.com/u/12194950?v=4"},"body":"From: Pratik Karki <predatoramigo@gmail.com>\n\nThe mode to rebase non-linear branches is now supported by the builtin\nrebase, too.\n\nSigned-off-by: Pratik Karki <predatoramigo@gmail.com>\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n builtin/rebase.c | 21 +++++++++++++++++++++\n 1 file changed, 21 insertions(+)\n\ndiff --git a/builtin/rebase.c b/builtin/rebase.c\nindex 3e37603da4..bcacffda33 100644\n--- a/builtin/rebase.c\n+++ b/builtin/rebase.c\n@@ -95,6 +95,7 @@ struct rebase_options {\n \tint autostash;\n \tchar *cmd;\n \tint allow_empty_message;\n+\tint rebase_merges, rebase_cousins;\n };\n \n static int is_interactive(struct rebase_options *opts)\n@@ -351,6 +352,10 @@ static int run_specific_rebase(struct rebase_options *opts)\n \tadd_var(&script_snippet, \"cmd\", opts->cmd);\n \tadd_var(&script_snippet, \"allow_empty_message\",\n \t\topts->allow_empty_message ?  \"--allow-empty-message\" : \"\");\n+\tadd_var(&script_snippet, \"rebase_merges\",\n+\t\topts->rebase_merges ? \"t\" : \"\");\n+\tadd_var(&script_snippet, \"rebase_cousins\",\n+\t\topts->rebase_cousins ? \"t\" : \"\");\n \n \tswitch (opts->type) {\n \tcase REBASE_AM:\n@@ -626,6 +631,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \tint opt_c = -1;\n \tstruct string_list whitespace = STRING_LIST_INIT_NODUP;\n \tstruct string_list exec = STRING_LIST_INIT_NODUP;\n+\tconst char *rebase_merges = NULL;\n \tstruct option builtin_rebase_options[] = {\n \t\tOPT_STRING(0, \"onto\", &options.onto_name,\n \t\t\t   N_(\"revision\"),\n@@ -704,6 +710,10 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \t\tOPT_BOOL(0, \"allow-empty-message\",\n \t\t\t &options.allow_empty_message,\n \t\t\t N_(\"allow rebasing commits with empty messages\")),\n+\t\t{OPTION_STRING, 'r', \"rebase-merges\", &rebase_merges,\n+\t\t\tN_(\"mode\"),\n+\t\t\tN_(\"try to rebase merges instead of skipping them\"),\n+\t\t\tPARSE_OPT_OPTARG, NULL, (intptr_t)\"\"},\n \t\tOPT_END(),\n \t};\n \n@@ -939,6 +949,17 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \t\toptions.cmd = xstrdup(buf.buf);\n \t}\n \n+\tif (rebase_merges) {\n+\t\tif (!*rebase_merges)\n+\t\t\t; /* default mode; do nothing */\n+\t\telse if (!strcmp(\"rebase-cousins\", rebase_merges))\n+\t\t\toptions.rebase_cousins = 1;\n+\t\telse if (strcmp(\"no-rebase-cousins\", rebase_merges))\n+\t\t\tdie(_(\"Unknown mode: %s\"), rebase_merges);\n+\t\toptions.rebase_merges = 1;\n+\t\timply_interactive(&options, \"--rebase-merges\");\n+\t}\n+\n \tswitch (options.type) {\n \tcase REBASE_MERGE:\n \tcase REBASE_INTERACTIVE:\n-- \ngitgitgadget\n\n"},{"id":"357379","messageId":"05652bccfeed8b9a70a3b1e16e5490e6c91acbc8.1536098386.git.gitgitgadget@gmail.com","threadId":"49073","inReplyTo":"pull.33.v2.git.gitgitgadget@gmail.com","subject":"[PATCH v2 15/18] merge-base --fork-point: extract libified function","fromName":"Pratik Karki via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2018-09-04T22:00:08Z","receivedAt":"2018-09-04T22:00:12Z","isPatch":true,"sender":{"key":"predatoramigo@gmail.com","avatar":"https://avatars.githubusercontent.com/u/12194950?v=4"},"body":"From: Pratik Karki <predatoramigo@gmail.com>\n\nWe need this functionality in the builtin rebase.\n\nNote: to make this function truly reusable, we have to switch the call\nget_merges_many_dirty() to get_merges_many() because we want the commit\nflags to be reset (otherwise, subsequent get_merge_bases() calls would\nobtain incorrect results). This did not matter when the function was\ncalled in `git rev-parse --fork-point` because in that command, the\nprocess definitely did not traverse any commits before exiting.\n\nSigned-off-by: Pratik Karki <predatoramigo@gmail.com>\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n builtin/merge-base.c | 81 ++++----------------------------------------\n commit.c             | 81 ++++++++++++++++++++++++++++++++++++++++++++\n commit.h             |  2 ++\n 3 files changed, 89 insertions(+), 75 deletions(-)\n\ndiff --git a/builtin/merge-base.c b/builtin/merge-base.c\nindex 08d91b1f0c..790ceaeed6 100644\n--- a/builtin/merge-base.c\n+++ b/builtin/merge-base.c\n@@ -110,54 +110,12 @@ static int handle_is_ancestor(int argc, const char **argv)\n \t\treturn 1;\n }\n \n-struct rev_collect {\n-\tstruct commit **commit;\n-\tint nr;\n-\tint alloc;\n-\tunsigned int initial : 1;\n-};\n-\n-static void add_one_commit(struct object_id *oid, struct rev_collect *revs)\n-{\n-\tstruct commit *commit;\n-\n-\tif (is_null_oid(oid))\n-\t\treturn;\n-\n-\tcommit = lookup_commit(the_repository, oid);\n-\tif (!commit ||\n-\t    (commit->object.flags & TMP_MARK) ||\n-\t    parse_commit(commit))\n-\t\treturn;\n-\n-\tALLOC_GROW(revs->commit, revs->nr + 1, revs->alloc);\n-\trevs->commit[revs->nr++] = commit;\n-\tcommit->object.flags |= TMP_MARK;\n-}\n-\n-static int collect_one_reflog_ent(struct object_id *ooid, struct object_id *noid,\n-\t\t\t\t  const char *ident, timestamp_t timestamp,\n-\t\t\t\t  int tz, const char *message, void *cbdata)\n-{\n-\tstruct rev_collect *revs = cbdata;\n-\n-\tif (revs->initial) {\n-\t\trevs->initial = 0;\n-\t\tadd_one_commit(ooid, revs);\n-\t}\n-\tadd_one_commit(noid, revs);\n-\treturn 0;\n-}\n-\n static int handle_fork_point(int argc, const char **argv)\n {\n \tstruct object_id oid;\n \tchar *refname;\n+\tstruct commit *derived, *fork_point;\n \tconst char *commitname;\n-\tstruct rev_collect revs;\n-\tstruct commit *derived;\n-\tstruct commit_list *bases;\n-\tint i, ret = 0;\n \n \tswitch (dwim_ref(argv[0], strlen(argv[0]), &oid, &refname)) {\n \tcase 0:\n@@ -173,41 +131,14 @@ static int handle_fork_point(int argc, const char **argv)\n \t\tdie(\"Not a valid object name: '%s'\", commitname);\n \n \tderived = lookup_commit_reference(the_repository, &oid);\n-\tmemset(&revs, 0, sizeof(revs));\n-\trevs.initial = 1;\n-\tfor_each_reflog_ent(refname, collect_one_reflog_ent, &revs);\n \n-\tif (!revs.nr && !get_oid(refname, &oid))\n-\t\tadd_one_commit(&oid, &revs);\n+\tfork_point = get_fork_point(refname, derived);\n \n-\tfor (i = 0; i < revs.nr; i++)\n-\t\trevs.commit[i]->object.flags &= ~TMP_MARK;\n-\n-\tbases = get_merge_bases_many_dirty(derived, revs.nr, revs.commit);\n-\n-\t/*\n-\t * There should be one and only one merge base, when we found\n-\t * a common ancestor among reflog entries.\n-\t */\n-\tif (!bases || bases->next) {\n-\t\tret = 1;\n-\t\tgoto cleanup_return;\n-\t}\n-\n-\t/* And the found one must be one of the reflog entries */\n-\tfor (i = 0; i < revs.nr; i++)\n-\t\tif (&bases->item->object == &revs.commit[i]->object)\n-\t\t\tbreak; /* found */\n-\tif (revs.nr <= i) {\n-\t\tret = 1; /* not found */\n-\t\tgoto cleanup_return;\n-\t}\n-\n-\tprintf(\"%s\\n\", oid_to_hex(&bases->item->object.oid));\n+\tif (!fork_point)\n+\t\treturn 1;\n \n-cleanup_return:\n-\tfree_commit_list(bases);\n-\treturn ret;\n+\tprintf(\"%s\\n\", oid_to_hex(&fork_point->object.oid));\n+\treturn 0;\n }\n \n int cmd_merge_base(int argc, const char **argv, const char *prefix)\ndiff --git a/commit.c b/commit.c\nindex 30d1af2b20..a3fc77a4eb 100644\n--- a/commit.c\n+++ b/commit.c\n@@ -17,6 +17,7 @@\n #include \"sha1-lookup.h\"\n #include \"wt-status.h\"\n #include \"advice.h\"\n+#include \"refs.h\"\n \n static struct commit_extra_header *read_commit_extra_header_lines(const char *buf, size_t len, const char **);\n \n@@ -958,6 +959,86 @@ static struct commit_list *merge_bases_many(struct commit *one, int n, struct co\n \treturn result;\n }\n \n+struct rev_collect {\n+\tstruct commit **commit;\n+\tint nr;\n+\tint alloc;\n+\tunsigned int initial : 1;\n+};\n+\n+static void add_one_commit(struct object_id *oid, struct rev_collect *revs)\n+{\n+\tstruct commit *commit;\n+\n+\tif (is_null_oid(oid))\n+\t\treturn;\n+\n+\tcommit = lookup_commit(the_repository, oid);\n+\tif (!commit ||\n+\t    (commit->object.flags & TMP_MARK) ||\n+\t    parse_commit(commit))\n+\t\treturn;\n+\n+\tALLOC_GROW(revs->commit, revs->nr + 1, revs->alloc);\n+\trevs->commit[revs->nr++] = commit;\n+\tcommit->object.flags |= TMP_MARK;\n+}\n+\n+static int collect_one_reflog_ent(struct object_id *ooid, struct object_id *noid,\n+\t\t\t\t  const char *ident, timestamp_t timestamp,\n+\t\t\t\t  int tz, const char *message, void *cbdata)\n+{\n+\tstruct rev_collect *revs = cbdata;\n+\n+\tif (revs->initial) {\n+\t\trevs->initial = 0;\n+\t\tadd_one_commit(ooid, revs);\n+\t}\n+\tadd_one_commit(noid, revs);\n+\treturn 0;\n+}\n+\n+struct commit *get_fork_point(const char *refname, struct commit *commit)\n+{\n+\tstruct object_id oid;\n+\tstruct rev_collect revs;\n+\tstruct commit_list *bases;\n+\tint i;\n+\tstruct commit *ret = NULL;\n+\n+\tmemset(&revs, 0, sizeof(revs));\n+\trevs.initial = 1;\n+\tfor_each_reflog_ent(refname, collect_one_reflog_ent, &revs);\n+\n+\tif (!revs.nr && !get_oid(refname, &oid))\n+\t\tadd_one_commit(&oid, &revs);\n+\n+\tfor (i = 0; i < revs.nr; i++)\n+\t\trevs.commit[i]->object.flags &= ~TMP_MARK;\n+\n+\tbases = get_merge_bases_many(commit, revs.nr, revs.commit);\n+\n+\t/*\n+\t * There should be one and only one merge base, when we found\n+\t * a common ancestor among reflog entries.\n+\t */\n+\tif (!bases || bases->next)\n+\t\tgoto cleanup_return;\n+\n+\t/* And the found one must be one of the reflog entries */\n+\tfor (i = 0; i < revs.nr; i++)\n+\t\tif (&bases->item->object == &revs.commit[i]->object)\n+\t\t\tbreak; /* found */\n+\tif (revs.nr <= i)\n+\t\tgoto cleanup_return;\n+\n+\tret = bases->item;\n+\n+cleanup_return:\n+\tfree_commit_list(bases);\n+\treturn ret;\n+}\n+\n struct commit_list *get_octopus_merge_bases(struct commit_list *in)\n {\n \tstruct commit_list *i, *j, *k, *ret = NULL;\ndiff --git a/commit.h b/commit.h\nindex da0db36eba..b34240017f 100644\n--- a/commit.h\n+++ b/commit.h\n@@ -211,6 +211,8 @@ extern struct commit_list *get_octopus_merge_bases(struct commit_list *in);\n /* To be used only when object flags after this call no longer matter */\n extern struct commit_list *get_merge_bases_many_dirty(struct commit *one, int n, struct commit **twos);\n \n+struct commit *get_fork_point(const char *refname, struct commit *commit);\n+\n /* largest positive number a signed 32-bit integer can contain */\n #define INFINITE_DEPTH 0x7fffffff\n \n-- \ngitgitgadget\n\n"},{"id":"357380","messageId":"25f6771947fd42de2c1373fef2f5043317161c04.1536098386.git.gitgitgadget@gmail.com","threadId":"49073","inReplyTo":"pull.33.v2.git.gitgitgadget@gmail.com","subject":"[PATCH v2 16/18] builtin rebase: support `fork-point` option","fromName":"Pratik Karki via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2018-09-04T22:00:09Z","receivedAt":"2018-09-04T22:00:13Z","isPatch":true,"sender":{"key":"predatoramigo@gmail.com","avatar":"https://avatars.githubusercontent.com/u/12194950?v=4"},"body":"From: Pratik Karki <predatoramigo@gmail.com>\n\nThis commit adds support for `--fork-point` and `--no-fork-point`.\nThis is converted as-is from `git-legacy-rebase.sh`.\n\nSigned-off-by: Pratik Karki <predatoramigo@gmail.com>\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n builtin/rebase.c | 11 +++++++++++\n 1 file changed, 11 insertions(+)\n\ndiff --git a/builtin/rebase.c b/builtin/rebase.c\nindex bcacffda33..6c101e1260 100644\n--- a/builtin/rebase.c\n+++ b/builtin/rebase.c\n@@ -632,6 +632,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \tstruct string_list whitespace = STRING_LIST_INIT_NODUP;\n \tstruct string_list exec = STRING_LIST_INIT_NODUP;\n \tconst char *rebase_merges = NULL;\n+\tint fork_point = -1;\n \tstruct option builtin_rebase_options[] = {\n \t\tOPT_STRING(0, \"onto\", &options.onto_name,\n \t\t\t   N_(\"revision\"),\n@@ -714,6 +715,8 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \t\t\tN_(\"mode\"),\n \t\t\tN_(\"try to rebase merges instead of skipping them\"),\n \t\t\tPARSE_OPT_OPTARG, NULL, (intptr_t)\"\"},\n+\t\tOPT_BOOL(0, \"fork-point\", &fork_point,\n+\t\t\t N_(\"use 'merge-base --fork-point' to refine upstream\")),\n \t\tOPT_END(),\n \t};\n \n@@ -1062,6 +1065,14 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \t} else\n \t\tBUG(\"unexpected number of arguments left to parse\");\n \n+\tif (fork_point > 0) {\n+\t\tstruct commit *head =\n+\t\t\tlookup_commit_reference(the_repository,\n+\t\t\t\t\t\t&options.orig_head);\n+\t\toptions.restrict_revision =\n+\t\t\tget_fork_point(options.upstream_name, head);\n+\t}\n+\n \tif (read_index(the_repository->index) < 0)\n \t\tdie(_(\"could not read index\"));\n \n-- \ngitgitgadget\n\n"},{"id":"357381","messageId":"10dc87d4ff20a68ccbab904dfbffbd7bf8c7dc35.1536098386.git.gitgitgadget@gmail.com","threadId":"49073","inReplyTo":"pull.33.v2.git.gitgitgadget@gmail.com","subject":"[PATCH v2 17/18] builtin rebase: add support for custom merge strategies","fromName":"Pratik Karki via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2018-09-04T22:00:11Z","receivedAt":"2018-09-04T22:00:14Z","isPatch":true,"sender":{"key":"predatoramigo@gmail.com","avatar":"https://avatars.githubusercontent.com/u/12194950?v=4"},"body":"From: Pratik Karki <predatoramigo@gmail.com>\n\nWhen running a rebase in non-am mode, it uses the recursive merge to\ncherry-pick the commits, and the rebase command allows to configure\nthe merge strategy to be used in this operation.\n\nThis commit adds that support to the builtin rebase.\n\nSigned-off-by: Pratik Karki <predatoramigo@gmail.com>\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n builtin/rebase.c | 57 ++++++++++++++++++++++++++++++++++++++++++++++++\n 1 file changed, 57 insertions(+)\n\ndiff --git a/builtin/rebase.c b/builtin/rebase.c\nindex 6c101e1260..847c7daf1c 100644\n--- a/builtin/rebase.c\n+++ b/builtin/rebase.c\n@@ -96,6 +96,7 @@ struct rebase_options {\n \tchar *cmd;\n \tint allow_empty_message;\n \tint rebase_merges, rebase_cousins;\n+\tchar *strategy, *strategy_opts;\n };\n \n static int is_interactive(struct rebase_options *opts)\n@@ -217,6 +218,22 @@ static int read_basic_state(struct rebase_options *opts)\n \t\topts->gpg_sign_opt = xstrdup(buf.buf);\n \t}\n \n+\tif (file_exists(state_dir_path(\"strategy\", opts))) {\n+\t\tstrbuf_reset(&buf);\n+\t\tif (read_one(state_dir_path(\"strategy\", opts), &buf))\n+\t\t\treturn -1;\n+\t\tfree(opts->strategy);\n+\t\topts->strategy = xstrdup(buf.buf);\n+\t}\n+\n+\tif (file_exists(state_dir_path(\"strategy_opts\", opts))) {\n+\t\tstrbuf_reset(&buf);\n+\t\tif (read_one(state_dir_path(\"strategy_opts\", opts), &buf))\n+\t\t\treturn -1;\n+\t\tfree(opts->strategy_opts);\n+\t\topts->strategy_opts = xstrdup(buf.buf);\n+\t}\n+\n \tstrbuf_release(&buf);\n \n \treturn 0;\n@@ -356,6 +373,8 @@ static int run_specific_rebase(struct rebase_options *opts)\n \t\topts->rebase_merges ? \"t\" : \"\");\n \tadd_var(&script_snippet, \"rebase_cousins\",\n \t\topts->rebase_cousins ? \"t\" : \"\");\n+\tadd_var(&script_snippet, \"strategy\", opts->strategy);\n+\tadd_var(&script_snippet, \"strategy_opts\", opts->strategy_opts);\n \n \tswitch (opts->type) {\n \tcase REBASE_AM:\n@@ -633,6 +652,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \tstruct string_list exec = STRING_LIST_INIT_NODUP;\n \tconst char *rebase_merges = NULL;\n \tint fork_point = -1;\n+\tstruct string_list strategy_options = STRING_LIST_INIT_NODUP;\n \tstruct option builtin_rebase_options[] = {\n \t\tOPT_STRING(0, \"onto\", &options.onto_name,\n \t\t\t   N_(\"revision\"),\n@@ -717,6 +737,12 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \t\t\tPARSE_OPT_OPTARG, NULL, (intptr_t)\"\"},\n \t\tOPT_BOOL(0, \"fork-point\", &fork_point,\n \t\t\t N_(\"use 'merge-base --fork-point' to refine upstream\")),\n+\t\tOPT_STRING('s', \"strategy\", &options.strategy,\n+\t\t\t   N_(\"strategy\"), N_(\"use the given merge strategy\")),\n+\t\tOPT_STRING_LIST('X', \"strategy-option\", &strategy_options,\n+\t\t\t\tN_(\"option\"),\n+\t\t\t\tN_(\"pass the argument through to the merge \"\n+\t\t\t\t   \"strategy\")),\n \t\tOPT_END(),\n \t};\n \n@@ -963,6 +989,37 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \t\timply_interactive(&options, \"--rebase-merges\");\n \t}\n \n+\tif (strategy_options.nr) {\n+\t\tint i;\n+\n+\t\tif (!options.strategy)\n+\t\t\toptions.strategy = \"recursive\";\n+\n+\t\tstrbuf_reset(&buf);\n+\t\tfor (i = 0; i < strategy_options.nr; i++)\n+\t\t\tstrbuf_addf(&buf, \" --%s\",\n+\t\t\t\t    strategy_options.items[i].string);\n+\t\toptions.strategy_opts = xstrdup(buf.buf);\n+\t}\n+\n+\tif (options.strategy) {\n+\t\toptions.strategy = xstrdup(options.strategy);\n+\t\tswitch (options.type) {\n+\t\tcase REBASE_AM:\n+\t\t\tdie(_(\"--strategy requires --merge or --interactive\"));\n+\t\tcase REBASE_MERGE:\n+\t\tcase REBASE_INTERACTIVE:\n+\t\tcase REBASE_PRESERVE_MERGES:\n+\t\t\t/* compatible */\n+\t\t\tbreak;\n+\t\tcase REBASE_UNSPECIFIED:\n+\t\t\toptions.type = REBASE_MERGE;\n+\t\t\tbreak;\n+\t\tdefault:\n+\t\t\tBUG(\"unhandled rebase type (%d)\", options.type);\n+\t\t}\n+\t}\n+\n \tswitch (options.type) {\n \tcase REBASE_MERGE:\n \tcase REBASE_INTERACTIVE:\n-- \ngitgitgadget\n\n"},{"id":"357382","messageId":"f1551410230e8f25c8d69e0b57984f59cb6d6df7.1536098386.git.gitgitgadget@gmail.com","threadId":"49073","inReplyTo":"pull.33.v2.git.gitgitgadget@gmail.com","subject":"[PATCH v2 18/18] builtin rebase: support --root","fromName":"Pratik Karki via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2018-09-04T22:00:12Z","receivedAt":"2018-09-04T22:00:16Z","isPatch":true,"sender":{"key":"predatoramigo@gmail.com","avatar":"https://avatars.githubusercontent.com/u/12194950?v=4"},"body":"From: Pratik Karki <predatoramigo@gmail.com>\n\nThis option allows to rebase entire histories up to, and including, the\nroot commit.\n\nThe conversion from the shell script is straight-forward, apart from\nthe fact that we do not have to write an empty tree in C.\n\nSigned-off-by: Pratik Karki <predatoramigo@gmail.com>\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n builtin/rebase.c | 31 +++++++++++++++++++++++++++++--\n 1 file changed, 29 insertions(+), 2 deletions(-)\n\ndiff --git a/builtin/rebase.c b/builtin/rebase.c\nindex 847c7daf1c..71b92658ec 100644\n--- a/builtin/rebase.c\n+++ b/builtin/rebase.c\n@@ -76,6 +76,7 @@ struct rebase_options {\n \tconst char *revisions;\n \tconst char *switch_to;\n \tint root;\n+\tstruct object_id *squash_onto;\n \tstruct commit *restrict_revision;\n \tint dont_finish_rebase;\n \tenum {\n@@ -375,6 +376,9 @@ static int run_specific_rebase(struct rebase_options *opts)\n \t\topts->rebase_cousins ? \"t\" : \"\");\n \tadd_var(&script_snippet, \"strategy\", opts->strategy);\n \tadd_var(&script_snippet, \"strategy_opts\", opts->strategy_opts);\n+\tadd_var(&script_snippet, \"rebase_root\", opts->root ? \"t\" : \"\");\n+\tadd_var(&script_snippet, \"squash_onto\",\n+\t\topts->squash_onto ? oid_to_hex(opts->squash_onto) : \"\");\n \n \tswitch (opts->type) {\n \tcase REBASE_AM:\n@@ -653,6 +657,8 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \tconst char *rebase_merges = NULL;\n \tint fork_point = -1;\n \tstruct string_list strategy_options = STRING_LIST_INIT_NODUP;\n+\tstruct object_id squash_onto;\n+\tchar *squash_onto_name = NULL;\n \tstruct option builtin_rebase_options[] = {\n \t\tOPT_STRING(0, \"onto\", &options.onto_name,\n \t\t\t   N_(\"revision\"),\n@@ -743,6 +749,8 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \t\t\t\tN_(\"option\"),\n \t\t\t\tN_(\"pass the argument through to the merge \"\n \t\t\t\t   \"strategy\")),\n+\t\tOPT_BOOL(0, \"root\", &options.root,\n+\t\t\t N_(\"rebase all reachable commits up to the root(s)\")),\n \t\tOPT_END(),\n \t};\n \n@@ -1020,6 +1028,9 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \t\t}\n \t}\n \n+\tif (options.root && !options.onto_name)\n+\t\timply_interactive(&options, \"--root without --onto\");\n+\n \tswitch (options.type) {\n \tcase REBASE_MERGE:\n \tcase REBASE_INTERACTIVE:\n@@ -1058,8 +1069,22 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \t\tif (!options.upstream)\n \t\t\tdie(_(\"invalid upstream '%s'\"), options.upstream_name);\n \t\toptions.upstream_arg = options.upstream_name;\n-\t} else\n-\t\tdie(\"TODO: upstream for --root\");\n+\t} else {\n+\t\tif (!options.onto_name) {\n+\t\t\tif (commit_tree(\"\", 0, the_hash_algo->empty_tree, NULL,\n+\t\t\t\t\t&squash_onto, NULL, NULL) < 0)\n+\t\t\t\tdie(_(\"Could not create new root commit\"));\n+\t\t\toptions.squash_onto = &squash_onto;\n+\t\t\toptions.onto_name = squash_onto_name =\n+\t\t\t\txstrdup(oid_to_hex(&squash_onto));\n+\t\t}\n+\t\toptions.upstream_name = NULL;\n+\t\toptions.upstream = NULL;\n+\t\tif (argc > 1)\n+\t\t\tusage_with_options(builtin_rebase_usage,\n+\t\t\t\t\t   builtin_rebase_options);\n+\t\toptions.upstream_arg = \"--root\";\n+\t}\n \n \t/* Make sure the branch to rebase onto is valid. */\n \tif (!options.onto_name)\n@@ -1207,6 +1232,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \t */\n \tif (can_fast_forward(options.onto, &options.orig_head, &merge_base) &&\n \t    !is_interactive(&options) && !options.restrict_revision &&\n+\t    options.upstream &&\n \t    !oidcmp(&options.upstream->object.oid, &options.onto->object.oid)) {\n \t\tint flag;\n \n@@ -1311,5 +1337,6 @@ cleanup:\n \tfree(options.head_name);\n \tfree(options.gpg_sign_opt);\n \tfree(options.cmd);\n+\tfree(squash_onto_name);\n \treturn ret;\n }\n-- \ngitgitgadget\n"},{"id":"357571","messageId":"xmqqmusuz9ql.fsf@gitster-ct.c.googlers.com","threadId":"49073","inReplyTo":"pull.33.v2.git.gitgitgadget@gmail.com","subject":"Re: [PATCH v2 00/18] builtin rebase options","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2018-09-06T19:50:10Z","receivedAt":"2018-09-06T19:50:16Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"\"Johannes Schindelin via GitGitGadget\" <gitgitgadget@gmail.com>\nwrites:\n\n> This patch series completes the support for all rebase options in the\n> builtin rebase, e.g. --signoff, rerere-autoupdate, etc.\n>\n> It is based on pk/rebase -in-c-3-acts.\n\n... which in turn was based on pk/rebase-in-c-2-basic that just got\nrerolled, so I would assume that you want pk/rebase-in-c-3-acts I\nhave rebased on top of the result of applying the updated 2-basic\nseries.\n\nI've rebuilt the collection of topics up to pk/rebase-in-c-6-final\nwith these two updated series twice, once doing it manually, like I\ndid the last time, and another using \"rebase -i -r\" on top of the\nupdated pk/rebase-in-c-4-opts.  The resulting trees match, of\ncourse.\n\nI did it twice to try out how it feels to use \"rebase -i -r\" because\nI wanted to make sure what we are shipping in 'master' behaves\nsensibly ;-)\n\nTwo things I noticed about the recreation of the merge ...\n\n\tReminder to bystanders.  We need to merge ag/rebase-i-in-c\n\ttopic on top of pk/reabse-in-c-5-test topic before applying\n\ta patch to adjust rebase to call rebase-i using the latter's\n\tnew calling convention.  The topics look like\n\n\t- pk/rebase-in-c has three patches on master\n\t- pk/rebase-in-c-2-basic builds on it, and being replaced\n\t- pk/rebase-in-c-3-acts builds on 2-basic (no update this time)\n\t- pk/rebase-in-c-4-opts builds on 3-acts, and being replaced\n\t- pk/rebase-in-c-5-test builds on 4-opts (no update this time)\n\t- js/rebase-in-c-5.5 builds on 5-test and merges ag/rebase-in-c\n\t  topic before applying one patch on it (no update this time)\n\t- pk/rebase-in-c-6-final builds on 5.5 (no update this time)\n\n\tand we are replacing 2-basic with 11 patches and 4-opts with\n\t18 patches.\n\n... using \"rebase -i -r\" are that \n\n (1) it rebuilt, or at least offered to rebuild, the entire side\n     branch, even though there is absolutely no need to.  Leaving\n     \"pick\"s untouched, based on the correct fork point, resulted in\n     all picks fast forwarded, but it was somewhat alarming.\n\n (2) \"merge -C <original merge commit> ag/rebase-i-in-c\" appeared as\n     the insn to merge in the (possibly rebuilt) side branch.  And\n     just like \"commit -C\", it took the merge message from the\n     original merge commit, which means that the summary of the\n     merged side branch is kept stale.  In this particular case, I\n     did not even want to see ag/rebase-i-in-c topic touched, so I\n     knew I want to keep the original merge summary, but if the user\n     took the offer to rewrite the side branch (e.g. with a \"reword\"\n     to retitle), using the original merge message would probably\n     disappoint the user.\n\nI think (1) actually is a feature.  Not everybody is an integrator\nwho does not want to touch any commit on the topic branch(es) while\nrebuilding a single-strand-of-pearls that has many commits and an\noccasional merge of the tip of another topic branch.  It's just that\nthe feature does not suit the workflow I use when I am playing the\ntop-level integrator role.\n\nI am not sure what should be the ideal behaviour for (2).  I would\nimagine that\n\n - I do want to keep the original title the merge (e.g. \"into\n   <target branch>\", if left to \"git merge\" to come up with the\n   title during \"rebase -i\" session, would be lost and become \"into\n   HEAD\", which is not what we want);\n\n - I do want to keep the original commentary in the merge (e.g. what\n   you would see in \"git log --first-parent master..next\" that gives\n   summary of each topic getting merged) so that I can update it as\n   needed; but \n\n - I do want the topic summary fmt-merge-msg produces to be based on\n   the updated side branch.\n\nI am not sure if the last item can reliably be filtered out of the\noriginal and replaced with newly generated summary.  If we can do\nso, that would be ideal, I guess.\n\nAnother observation was that after rebuiding pk/rebase-in-c-6^0 on\ntop of the updated pk'/rebase-in-c-4 using \"rebase -i -r\", I of\ncourse still needed to \"branch -f\" to update pk/rebase-in-c-5,\njs/reabse-in-c-5.5, and pk/rebase-in-c-6 branches to point at\nappropriate commits.  I do not think it is a good idea to let\n\"rebase -i\" munge these dependent branches by default, but it might\nbe worth considering it as an option.  Since I want to be more in\ncontrol of what happens to the tips of topic branches, I did not\nmind at all having to run \"branch -f\" and having the chance to run\n\"diff\" before doing so, but at the same time, that means doing these\nmanually in steps building 5 on 4, 5.5 on 5 and then 6 on 5.5,\ninstead of building 6 on top of 4 using \"rebase -i\" and then tagging\nthe intermediate states, gives me more control without forcing me\nmore work.\n\nI guess that is the answer to a question you asked earlier, which I\nhaven't answered so far because I didn't have a good grasp of where\nmy preference was coming from when it was asked.  Now I know, so...\n\n"},{"id":"357575","messageId":"xmqqin3iz7ik.fsf@gitster-ct.c.googlers.com","threadId":"49073","inReplyTo":"xmqqmusuz9ql.fsf@gitster-ct.c.googlers.com","subject":"Re: [PATCH v2 00/18] builtin rebase options","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2018-09-06T20:38:11Z","receivedAt":"2018-09-06T20:38:16Z","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've rebuilt the collection of topics up to pk/rebase-in-c-6-final\n> with these two updated series twice, once doing it manually, like I\n> did the last time, and another using \"rebase -i -r\" on top of the\n> updated pk/rebase-in-c-4-opts.  The resulting trees match, of\n> course.\n\nJust to clarify, \"trees match\" means \"'rebase -i -r' gave us the\ncorrect result\" ;-).\n\n> I guess that is the answer to a question you asked earlier, which I\n> haven't answered so far because I didn't have a good grasp of where\n> my preference was coming from when it was asked.  Now I know, so...\n\nIn case the question was unclear it was \"is there a reason why you\ndo not want to use rebase -ir?\"\n\nIf \"cherry-pick\" did not lose notes, I would have preferred to do\nthis kind of rebuilding dependent chains of topics without using\nrebase at all, but that is a different story.\n"},{"id":"360297","messageId":"nycvar.QRO.7.76.6.1810121345160.561@tvgsbejvaqbjf.bet","threadId":"49073","inReplyTo":"xmqqmusuz9ql.fsf@gitster-ct.c.googlers.com","subject":"Re: [PATCH v2 00/18] builtin rebase options","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2018-10-12T12:01:03Z","receivedAt":"2018-10-12T12:01:34Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Junio,\n\nOn Thu, 6 Sep 2018, Junio C Hamano wrote:\n\n> \"Johannes Schindelin via GitGitGadget\" <gitgitgadget@gmail.com>\n> writes:\n> \n> > This patch series completes the support for all rebase options in the\n> > builtin rebase, e.g. --signoff, rerere-autoupdate, etc.\n> >\n> > It is based on pk/rebase -in-c-3-acts.\n> \n> ... which in turn was based on pk/rebase-in-c-2-basic that just got\n> rerolled, so I would assume that you want pk/rebase-in-c-3-acts I\n> have rebased on top of the result of applying the updated 2-basic\n> series.\n> \n> I've rebuilt the collection of topics up to pk/rebase-in-c-6-final\n> with these two updated series twice, once doing it manually, like I\n> did the last time, and another using \"rebase -i -r\" on top of the\n> updated pk/rebase-in-c-4-opts.  The resulting trees match, of\n> course.\n> \n> I did it twice to try out how it feels to use \"rebase -i -r\" because\n> I wanted to make sure what we are shipping in 'master' behaves\n> sensibly ;-)\n> \n> Two things I noticed about the recreation of the merge ...\n> \n> \tReminder to bystanders.  We need to merge ag/rebase-i-in-c\n> \ttopic on top of pk/reabse-in-c-5-test topic before applying\n> \ta patch to adjust rebase to call rebase-i using the latter's\n> \tnew calling convention.  The topics look like\n> \n> \t- pk/rebase-in-c has three patches on master\n> \t- pk/rebase-in-c-2-basic builds on it, and being replaced\n> \t- pk/rebase-in-c-3-acts builds on 2-basic (no update this time)\n> \t- pk/rebase-in-c-4-opts builds on 3-acts, and being replaced\n> \t- pk/rebase-in-c-5-test builds on 4-opts (no update this time)\n> \t- js/rebase-in-c-5.5 builds on 5-test and merges ag/rebase-in-c\n> \t  topic before applying one patch on it (no update this time)\n> \t- pk/rebase-in-c-6-final builds on 5.5 (no update this time)\n> \n> \tand we are replacing 2-basic with 11 patches and 4-opts with\n> \t18 patches.\n> \n> ... using \"rebase -i -r\" are that \n> \n>  (1) it rebuilt, or at least offered to rebuild, the entire side\n>      branch, even though there is absolutely no need to.  Leaving\n>      \"pick\"s untouched, based on the correct fork point, resulted in\n>      all picks fast forwarded, but it was somewhat alarming.\n\nRight. But this is a legacy of our paradigm to script things in Unix shell\nscript. It not only is slow, error-prone and hard to keep portable, it\nalso encourages poor design, as you do not have the same expressive power\nas C has.\n\nIn this case, it harmed us by making it impossible to essentially play out\nthe rebase in memory and only fall back to writing things into the\nworktree upon failure.\n\nHowever, this is where we want to go. It is still a long way to go,\nthough, as many code parts are safely in the \"we use the worktree to play\nout the rebase in its entirety\" place.\n\nThe \"skip_unnecessary_picks\" trick is the best we could do so far.\n\n>  (2) \"merge -C <original merge commit> ag/rebase-i-in-c\" appeared as\n>      the insn to merge in the (possibly rebuilt) side branch.  And\n>      just like \"commit -C\", it took the merge message from the\n>      original merge commit, which means that the summary of the\n>      merged side branch is kept stale.  In this particular case, I\n>      did not even want to see ag/rebase-i-in-c topic touched, so I\n>      knew I want to keep the original merge summary, but if the user\n>      took the offer to rewrite the side branch (e.g. with a \"reword\"\n>      to retitle), using the original merge message would probably\n>      disappoint the user.\n\nRight. But the user would then also freely admit that they asked for the\nmerge commit to be rebased, which is what `--rebase-merges` says.\n\n> I think (1) actually is a feature.  Not everybody is an integrator\n> who does not want to touch any commit on the topic branch(es) while\n> rebuilding a single-strand-of-pearls that has many commits and an\n> occasional merge of the tip of another topic branch.  It's just that\n> the feature does not suit the workflow I use when I am playing the\n> top-level integrator role.\n\nAs I said. The ideal thing would be to invest quite a bit in refactoring\nespecially the do_pick_commit() function, and then play out the rebase in\nmemory, where one state variable knows what the \"HEAD\" is (but the\nworktree is left untouched, up until the point when an error occurs, in\nwhich case we want to write out the files). This would also need a major\nrefactoring of the recursive merge, of course, which conflates the merge\npart with the writing of the merge conflicts to disk part.\n\nWhile I would love to see this happening, I don't think that I can spare\nenough time to drive this, at least for a couple of years.\n\n> I am not sure what should be the ideal behaviour for (2).  I would\n> imagine that\n> \n>  - I do want to keep the original title the merge (e.g. \"into\n>    <target branch>\", if left to \"git merge\" to come up with the\n>    title during \"rebase -i\" session, would be lost and become \"into\n>    HEAD\", which is not what we want);\n> \n>  - I do want to keep the original commentary in the merge (e.g. what\n>    you would see in \"git log --first-parent master..next\" that gives\n>    summary of each topic getting merged) so that I can update it as\n>    needed; but \n> \n>  - I do want the topic summary fmt-merge-msg produces to be based on\n>    the updated side branch.\n> \n> I am not sure if the last item can reliably be filtered out of the\n> original and replaced with newly generated summary.  If we can do\n> so, that would be ideal, I guess.\n\nI think what you want is not the `merge` command, but a custom script that\nyou can then `exec`.\n\nThis could even be automated to some extent, by introducing an option to\n`git rebase -i` that lets a script post-process the generated todo list,\nsomething I wanted for a long time.\n\n> Another observation was that after rebuiding pk/rebase-in-c-6^0 on\n> top of the updated pk'/rebase-in-c-4 using \"rebase -i -r\", I of\n> course still needed to \"branch -f\" to update pk/rebase-in-c-5,\n> js/reabse-in-c-5.5, and pk/rebase-in-c-6 branches to point at\n> appropriate commits.  I do not think it is a good idea to let\n> \"rebase -i\" munge these dependent branches by default, but it might\n> be worth considering it as an option.\n\nYes! Already years ago, I wanted to teach the shears to figure out that a\nbranch (i.e. a second parent of a merge commit that mentions the branch\nname in its oneline) was updated by the rebase, and if the pre-rebase\ncommit agrees with a local ref of that name, update said ref after the\nrebase finished successfully.\n\nThere is one big caveat, though: what if one of those branches is checked\nout in a worktree?\n\nI think it can be done, and it should be hidden behind an opt-in config\nsetting.\n\n#leftoverbits?\n\n> Since I want to be more in control of what happens to the tips of topic\n> branches, I did not mind at all having to run \"branch -f\" and having the\n> chance to run \"diff\" before doing so, but at the same time, that means\n> doing these manually in steps building 5 on 4, 5.5 on 5 and then 6 on\n> 5.5, instead of building 6 on top of 4 using \"rebase -i\" and then\n> tagging the intermediate states, gives me more control without forcing\n> me more work.\n\nSure. This definitely gives you more control.\n\nI am not sure whether you want that control, or whether you *actually*\nwant more safety guards. If it was me, I would prefer something that can\nstop/pause the process when something is obviously going wrong (it could\nbe a script verifying that, e.g. looking at the length/contents of the\nrange-diff and ringing an alarm when a commit other than a fixup! was\ndropped).\n\nCiao,\nDscho\n"}]}