{"thread":{"id":"49071","subject":"[GSoC] [PATCH 00/11] A minimal builtin rebase","startedAt":"2018-08-08T13:51:12Z","lastAt":"2018-09-10T20:25:33Z","messageCount":42,"participants":["Pratik Karki","Duy Nguyen","Stefan Beller","Johannes Schindelin","Junio C Hamano","Johannes Schindelin via GitGitGadget","Pratik Karki via GitGitGadget","SZEDER Gábor"],"isPatch":true,"patchVersion":1,"patchTotal":11},"messages":[{"id":"354801","messageId":"20180808134830.19949-1-predatoramigo@gmail.com","threadId":"49071","inReplyTo":null,"subject":"[GSoC] [PATCH 00/11] A minimal builtin rebase","fromName":"Pratik Karki","fromEmail":"predatoramigo@gmail.com","sentAt":"2018-08-08T13:48:19Z","receivedAt":"2018-08-08T13:51:12Z","isPatch":true,"sender":{"key":"predatoramigo@gmail.com","avatar":"https://avatars.githubusercontent.com/u/12194950?v=4"},"body":"This patch series provides the bare minimum to run more than the trivial\nrebase (i.e. `git rebase <upstream>`).\n\nHere, I have implemented essential options needed to make this a\nbuiltin rebase. Ofcourse, to accomplish the task of builtin rebase, I had to\ndo essential optimizations and add certain shield which weren't present in\noriginal rebase.\n\nIt is based the latest iteration of pk/rebase-in-c, i.e. ac7f467fef8b\n(builtin/rebase: support running \"git rebase <upstream>\", 2018-08-07).\n\nThis is the second patch series that brings us more closer to a\nbuiltin \"git rebase\".\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\nI plan on submitting the next patch series today, in this order:\n\nbultin rebase actions: The builtin rebase will add all the rebase actions.\nbuiltin rebase options: The builtin rebase will add all the options supported\nby original rebase.\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 order.\n\nThe motivation to organize these patch series is to make review easier and\nfor pleasant read with the help of my GSoC mentors since, this is the final\nweek of GSoC and other GSoC students most likely have submitted their\nrespective works which will need lots of review.\n\nPratik Karki (11):\n  builtin rebase: support --onto\n  builtin rebase: support `git rebase --onto A...B`\n  builtin rebase: handle the pre-rebase hook (and add --no-verify)\n  builtin rebase: support --quiet\n  builtin rebase: support the `verbose` and `diffstat` options\n  builtin rebase: require a clean worktree\n  builtin rebase: try to fast forward when possible\n  builtin rebase: support --force-rebase\n  builtin rebase: start a new rebase only if none is in progress\n  builtin rebase: only store fully-qualified refs in `options.head_name`\n  builtin rebase: support `git rebase <upstream> <switch-to>`\n\n builtin/rebase.c | 333 +++++++++++++++++++++++++++++++++++++++++++++--\n 1 file changed, 320 insertions(+), 13 deletions(-)\n\n-- \n2.18.0\n\n"},{"id":"354802","messageId":"20180808134830.19949-2-predatoramigo@gmail.com","threadId":"49071","inReplyTo":"20180808134830.19949-1-predatoramigo@gmail.com","subject":"[PATCH 01/11] builtin rebase: support --onto","fromName":"Pratik Karki","fromEmail":"predatoramigo@gmail.com","sentAt":"2018-08-08T13:48:20Z","receivedAt":"2018-08-08T13:51:16Z","isPatch":true,"sender":{"key":"predatoramigo@gmail.com","avatar":"https://avatars.githubusercontent.com/u/12194950?v=4"},"body":"The `--onto` option is important, as it allows to rebase a range of\ncommits onto a different base commit (which gave the command its odd\nname: \"rebase\").\n\nThis commit introduces options parsing so that different options can\nbe added in future commits.\n\nNote: As this commit introduces to the parse_options() call (which\n\"eats\" argv[0]), the argc is now expected to be lower by one after this\npatch, compared to before this patch: argv[0] no longer refers to the\ncommand name, but to the first (non-option) command-line parameter.\n\nSigned-off-by: Pratik Karki <predatoramigo@gmail.com>\n---\n builtin/rebase.c | 35 ++++++++++++++++++++++++++++++-----\n 1 file changed, 30 insertions(+), 5 deletions(-)\n\ndiff --git a/builtin/rebase.c b/builtin/rebase.c\nindex e695d8a430..742ed31498 100644\n--- a/builtin/rebase.c\n+++ b/builtin/rebase.c\n@@ -16,6 +16,16 @@\n #include \"cache-tree.h\"\n #include \"unpack-trees.h\"\n #include \"lockfile.h\"\n+#include \"parse-options.h\"\n+\n+static char const * const builtin_rebase_usage[] = {\n+\tN_(\"git rebase [-i] [options] [--exec <cmd>] [--onto <newbase>] \"\n+\t\t\"[<upstream>] [<branch>]\"),\n+\tN_(\"git rebase [-i] [options] [--exec <cmd>] [--onto <newbase>] \"\n+\t\t\"--root [<branch>]\"),\n+\tN_(\"git rebase --continue | --abort | --skip | --edit-todo\"),\n+\tNULL\n+};\n \n static GIT_PATH_FUNC(apply_dir, \"rebase-apply\")\n static GIT_PATH_FUNC(merge_dir, \"rebase-merge\")\n@@ -301,6 +311,12 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \tint ret, flags;\n \tstruct strbuf msg = STRBUF_INIT;\n \tstruct strbuf revisions = STRBUF_INIT;\n+\tstruct option builtin_rebase_options[] = {\n+\t\tOPT_STRING(0, \"onto\", &options.onto_name,\n+\t\t\t   N_(\"revision\"),\n+\t\t\t   N_(\"rebase onto given branch instead of upstream\")),\n+\t\tOPT_END(),\n+\t};\n \n \t/*\n \t * NEEDSWORK: Once the builtin rebase has been tested enough\n@@ -318,13 +334,22 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \t\t\tBUG(\"sane_execvp() returned???\");\n \t}\n \n-\tif (argc != 2)\n-\t\tdie(_(\"Usage: %s <base>\"), argv[0]);\n+\tif (argc == 2 && !strcmp(argv[1], \"-h\"))\n+\t\tusage_with_options(builtin_rebase_usage,\n+\t\t\t\t   builtin_rebase_options);\n+\n \tprefix = setup_git_directory();\n \ttrace_repo_setup(prefix);\n \tsetup_work_tree();\n \n \tgit_config(git_default_config, NULL);\n+\targc = parse_options(argc, argv, prefix,\n+\t\t\t     builtin_rebase_options,\n+\t\t\t     builtin_rebase_usage, 0);\n+\n+\tif (argc > 2)\n+\t\tusage_with_options(builtin_rebase_usage,\n+\t\t\t\t   builtin_rebase_options);\n \n \tswitch (options.type) {\n \tcase REBASE_MERGE:\n@@ -343,10 +368,10 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \t}\n \n \tif (!options.root) {\n-\t\tif (argc < 2)\n+\t\tif (argc < 1)\n \t\t\tdie(\"TODO: handle @{upstream}\");\n \t\telse {\n-\t\t\toptions.upstream_name = argv[1];\n+\t\t\toptions.upstream_name = argv[0];\n \t\t\targc--;\n \t\t\targv++;\n \t\t\tif (!strcmp(options.upstream_name, \"-\"))\n@@ -377,7 +402,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \t * orig_head -- commit object name of tip of the branch before rebasing\n \t * head_name -- refs/heads/<that-branch> or \"detached HEAD\"\n \t */\n-\tif (argc > 1)\n+\tif (argc > 0)\n \t\t die(\"TODO: handle switch_to\");\n \telse {\n \t\t/* Do not need to switch branches, we are already on it. */\n-- \n2.18.0\n\n"},{"id":"354803","messageId":"20180808134830.19949-3-predatoramigo@gmail.com","threadId":"49071","inReplyTo":"20180808134830.19949-1-predatoramigo@gmail.com","subject":"[PATCH 02/11] builtin rebase: support `git rebase --onto A...B`","fromName":"Pratik Karki","fromEmail":"predatoramigo@gmail.com","sentAt":"2018-08-08T13:48:21Z","receivedAt":"2018-08-08T13:51:19Z","isPatch":true,"sender":{"key":"predatoramigo@gmail.com","avatar":"https://avatars.githubusercontent.com/u/12194950?v=4"},"body":"This commit implements support for an --onto argument that is actually a\n\"symmetric range\" i.e. `<rev1>...<rev2>`.\n\nThe equivalent shell script version of the code offers two different\nerror messages for the cases where there is no merge base vs more than\none merge base. Though following the similar approach would be nice,\nthis would create more complexity than it is of current. Currently, for\nsimple convenience, the `get_oid_mb()` function is used whose return\nvalue does not discern between those two error conditions.\n\nSigned-off-by: Pratik Karki <predatoramigo@gmail.com>\n---\n builtin/rebase.c | 8 +++++++-\n 1 file changed, 7 insertions(+), 1 deletion(-)\n\ndiff --git a/builtin/rebase.c b/builtin/rebase.c\nindex 742ed31498..38c496dd10 100644\n--- a/builtin/rebase.c\n+++ b/builtin/rebase.c\n@@ -17,6 +17,7 @@\n #include \"unpack-trees.h\"\n #include \"lockfile.h\"\n #include \"parse-options.h\"\n+#include \"commit.h\"\n \n static char const * const builtin_rebase_usage[] = {\n \tN_(\"git rebase [-i] [options] [--exec <cmd>] [--onto <newbase>] \"\n@@ -311,6 +312,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \tint ret, flags;\n \tstruct strbuf msg = STRBUF_INIT;\n \tstruct strbuf revisions = STRBUF_INIT;\n+\tstruct object_id merge_base;\n \tstruct option builtin_rebase_options[] = {\n \t\tOPT_STRING(0, \"onto\", &options.onto_name,\n \t\t\t   N_(\"revision\"),\n@@ -387,7 +389,11 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \tif (!options.onto_name)\n \t\toptions.onto_name = options.upstream_name;\n \tif (strstr(options.onto_name, \"...\")) {\n-\t\tdie(\"TODO\");\n+\t\tif (get_oid_mb(options.onto_name, &merge_base) < 0)\n+\t\t\tdie(_(\"'%s': need exactly one merge base\"),\n+\t\t\t    options.onto_name);\n+\t\toptions.onto = lookup_commit_or_die(&merge_base,\n+\t\t\t\t\t\t    options.onto_name);\n \t} else {\n \t\toptions.onto = peel_committish(options.onto_name);\n \t\tif (!options.onto)\n-- \n2.18.0\n\n"},{"id":"354804","messageId":"20180808134830.19949-4-predatoramigo@gmail.com","threadId":"49071","inReplyTo":"20180808134830.19949-1-predatoramigo@gmail.com","subject":"[PATCH 03/11] builtin rebase: handle the pre-rebase hook (and add --no-verify)","fromName":"Pratik Karki","fromEmail":"predatoramigo@gmail.com","sentAt":"2018-08-08T13:48:22Z","receivedAt":"2018-08-08T13:51:23Z","isPatch":true,"sender":{"key":"predatoramigo@gmail.com","avatar":"https://avatars.githubusercontent.com/u/12194950?v=4"},"body":"This commit converts the equivalent part of the shell script\n`git-legacy-rebase.sh` to run the pre-rebase hook (unless disabled), and\nto interrupt the rebase with error if the hook fails.\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 38c496dd10..b79f9b0a9f 100644\n--- a/builtin/rebase.c\n+++ b/builtin/rebase.c\n@@ -70,6 +70,7 @@ struct rebase_options {\n \tconst char *state_dir;\n \tstruct commit *upstream;\n \tconst char *upstream_name;\n+\tconst char *upstream_arg;\n \tchar *head_name;\n \tstruct object_id orig_head;\n \tstruct commit *onto;\n@@ -310,6 +311,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \t};\n \tconst char *branch_name;\n \tint ret, flags;\n+\tint ok_to_skip_pre_rebase = 0;\n \tstruct strbuf msg = STRBUF_INIT;\n \tstruct strbuf revisions = STRBUF_INIT;\n \tstruct object_id merge_base;\n@@ -317,6 +319,8 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \t\tOPT_STRING(0, \"onto\", &options.onto_name,\n \t\t\t   N_(\"revision\"),\n \t\t\t   N_(\"rebase onto given branch instead of upstream\")),\n+\t\tOPT_BOOL(0, \"no-verify\", &ok_to_skip_pre_rebase,\n+\t\t\t N_(\"allow pre-rebase hook to run\")),\n \t\tOPT_END(),\n \t};\n \n@@ -382,6 +386,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \t\toptions.upstream = peel_committish(options.upstream_name);\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 \n@@ -430,6 +435,12 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \t\t\tdie(_(\"Could not resolve HEAD to a revision\"));\n \t}\n \n+\t/* If a hook exists, give it a chance to interrupt*/\n+\tif (!ok_to_skip_pre_rebase &&\n+\t    run_hook_le(NULL, \"pre-rebase\", options.upstream_arg,\n+\t\t\targc ? argv[0] : NULL, NULL))\n+\t\tdie(_(\"The pre-rebase hook refused to rebase.\"));\n+\n \tstrbuf_addf(&msg, \"rebase: checkout %s\", options.onto_name);\n \tif (reset_head(&options.onto->object.oid, \"checkout\", NULL, 1))\n \t\tdie(_(\"Could not detach HEAD\"));\n-- \n2.18.0\n\n"},{"id":"354805","messageId":"20180808134830.19949-5-predatoramigo@gmail.com","threadId":"49071","inReplyTo":"20180808134830.19949-1-predatoramigo@gmail.com","subject":"[PATCH 04/11] builtin rebase: support --quiet","fromName":"Pratik Karki","fromEmail":"predatoramigo@gmail.com","sentAt":"2018-08-08T13:48:23Z","receivedAt":"2018-08-08T13:51:27Z","isPatch":true,"sender":{"key":"predatoramigo@gmail.com","avatar":"https://avatars.githubusercontent.com/u/12194950?v=4"},"body":"This commit introduces a rebase option `--quiet`. While `--quiet` is\ncommonly perceived as opposite to `--verbose`, this is not the case for\nthe rebase command: both `--quiet` and `--verbose` default to `false` if\nneither `--quiet` nor `--verbose` is present.\n\nThis commit goes further and introduces `--no-quiet` which is the\ncontrary of `--quiet` and it's introduction doesn't modify any\nbehaviour.\n\nNote: The `flags` field in `rebase_options` will accumulate more bits in\nsubsequent commits, in particular a verbose and a diffstat flag. And as\n--quoet inthe shell scripted version of the rebase command switches off\n--verbose and --stat, and as --verbose switches off --quiet, we use the\n(negated) REBASE_NO_QUIET instead of REBASE_QUIET: this allows us to\nturn off the quiet mode and turn on the verbose and diffstat mode in a\nsingle OPT_BIT(), and the opposite in a single OPT_NEGBIT().\n\nSigned-off-by: Pratik Karki <predatoramigo@gmail.com>\n---\n builtin/rebase.c | 15 +++++++++++++++\n 1 file changed, 15 insertions(+)\n\ndiff --git a/builtin/rebase.c b/builtin/rebase.c\nindex b79f9b0a9f..19fa4d3fc4 100644\n--- a/builtin/rebase.c\n+++ b/builtin/rebase.c\n@@ -79,6 +79,10 @@ struct rebase_options {\n \tint root;\n \tstruct commit *restrict_revision;\n \tint dont_finish_rebase;\n+\tenum {\n+\t\tREBASE_NO_QUIET = 1<<0,\n+\t} flags;\n+\tstruct strbuf git_am_opt;\n };\n \n /* Returns the filename prefixed by the state_dir */\n@@ -159,6 +163,9 @@ static int run_specific_rebase(struct rebase_options *opts)\n \tadd_var(&script_snippet, \"revisions\", opts->revisions);\n \tadd_var(&script_snippet, \"restrict_revision\", opts->restrict_revision ?\n \t\toid_to_hex(&opts->restrict_revision->object.oid) : NULL);\n+\tadd_var(&script_snippet, \"GIT_QUIET\",\n+\t\topts->flags & REBASE_NO_QUIET ? \"\" : \"t\");\n+\tadd_var(&script_snippet, \"git_am_opt\", opts->git_am_opt.buf);\n \n \tswitch (opts->type) {\n \tcase REBASE_AM:\n@@ -308,6 +315,8 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n {\n \tstruct rebase_options options = {\n \t\t.type = REBASE_UNSPECIFIED,\n+\t\t.flags = REBASE_NO_QUIET,\n+\t\t.git_am_opt = STRBUF_INIT,\n \t};\n \tconst char *branch_name;\n \tint ret, flags;\n@@ -321,6 +330,9 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \t\t\t   N_(\"rebase onto given branch instead of upstream\")),\n \t\tOPT_BOOL(0, \"no-verify\", &ok_to_skip_pre_rebase,\n \t\t\t N_(\"allow pre-rebase hook to run\")),\n+\t\tOPT_NEGBIT('q', \"quiet\", &options.flags,\n+\t\t\t   N_(\"be quiet. implies --no-stat\"),\n+\t\t\t   REBASE_NO_QUIET),\n \t\tOPT_END(),\n \t};\n \n@@ -357,6 +369,9 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \t\tusage_with_options(builtin_rebase_usage,\n \t\t\t\t   builtin_rebase_options);\n \n+\tif (!(options.flags & REBASE_NO_QUIET))\n+\t\tstrbuf_addstr(&options.git_am_opt, \" -q\");\n+\n \tswitch (options.type) {\n \tcase REBASE_MERGE:\n \tcase REBASE_INTERACTIVE:\n-- \n2.18.0\n\n"},{"id":"354806","messageId":"20180808134830.19949-6-predatoramigo@gmail.com","threadId":"49071","inReplyTo":"20180808134830.19949-1-predatoramigo@gmail.com","subject":"[PATCH 05/11] builtin rebase: support the `verbose` and `diffstat` options","fromName":"Pratik Karki","fromEmail":"predatoramigo@gmail.com","sentAt":"2018-08-08T13:48:24Z","receivedAt":"2018-08-08T13:51:31Z","isPatch":true,"sender":{"key":"predatoramigo@gmail.com","avatar":"https://avatars.githubusercontent.com/u/12194950?v=4"},"body":"This commit introduces support for the `-v` and `--stat` options of\nrebase.\n\nThe --stat option can also be configured via the Git config setting\nrebase.stat. To support this, we also add a custom rebase_config()\nfunction in this commit that will be used instead of (and falls back to\ncalling) git_default_config().\n\nSigned-off-by: Pratik Karki <predatoramigo@gmail.com>\n---\n builtin/rebase.c | 60 ++++++++++++++++++++++++++++++++++++++++++++++--\n 1 file changed, 58 insertions(+), 2 deletions(-)\n\ndiff --git a/builtin/rebase.c b/builtin/rebase.c\nindex 19fa4d3fc4..2d3f1d65fb 100644\n--- a/builtin/rebase.c\n+++ b/builtin/rebase.c\n@@ -18,6 +18,7 @@\n #include \"lockfile.h\"\n #include \"parse-options.h\"\n #include \"commit.h\"\n+#include \"diff.h\"\n \n static char const * const builtin_rebase_usage[] = {\n \tN_(\"git rebase [-i] [options] [--exec <cmd>] [--onto <newbase>] \"\n@@ -81,6 +82,8 @@ struct rebase_options {\n \tint dont_finish_rebase;\n \tenum {\n \t\tREBASE_NO_QUIET = 1<<0,\n+\t\tREBASE_VERBOSE = 1<<1,\n+\t\tREBASE_DIFFSTAT = 1<<2,\n \t} flags;\n \tstruct strbuf git_am_opt;\n };\n@@ -166,6 +169,10 @@ static int run_specific_rebase(struct rebase_options *opts)\n \tadd_var(&script_snippet, \"GIT_QUIET\",\n \t\topts->flags & REBASE_NO_QUIET ? \"\" : \"t\");\n \tadd_var(&script_snippet, \"git_am_opt\", opts->git_am_opt.buf);\n+\tadd_var(&script_snippet, \"verbose\",\n+\t\topts->flags & REBASE_VERBOSE ? \"t\" : \"\");\n+\tadd_var(&script_snippet, \"diffstat\",\n+\t\topts->flags & REBASE_DIFFSTAT ? \"t\" : \"\");\n \n \tswitch (opts->type) {\n \tcase REBASE_AM:\n@@ -311,6 +318,21 @@ static int reset_head(struct object_id *oid, const char *action,\n \treturn ret;\n }\n \n+static int rebase_config(const char *var, const char *value, void *data)\n+{\n+\tstruct rebase_options *opts = data;\n+\n+\tif (!strcmp(var, \"rebase.stat\")) {\n+\t\tif (git_config_bool(var, value))\n+\t\t\topts->flags |= REBASE_DIFFSTAT;\n+\t\telse\n+\t\t\topts->flags &= !REBASE_DIFFSTAT;\n+\t\treturn 0;\n+\t}\n+\n+\treturn git_default_config(var, value, data);\n+}\n+\n int cmd_rebase(int argc, const char **argv, const char *prefix)\n {\n \tstruct rebase_options options = {\n@@ -332,7 +354,13 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \t\t\t N_(\"allow pre-rebase hook to run\")),\n \t\tOPT_NEGBIT('q', \"quiet\", &options.flags,\n \t\t\t   N_(\"be quiet. implies --no-stat\"),\n-\t\t\t   REBASE_NO_QUIET),\n+\t\t\t   REBASE_NO_QUIET| REBASE_VERBOSE | REBASE_DIFFSTAT),\n+\t\tOPT_BIT('v', \"verbose\", &options.flags,\n+\t\t\tN_(\"display a diffstat of what changed upstream\"),\n+\t\t\tREBASE_NO_QUIET | REBASE_VERBOSE | REBASE_DIFFSTAT),\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_END(),\n \t};\n \n@@ -360,7 +388,8 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \ttrace_repo_setup(prefix);\n \tsetup_work_tree();\n \n-\tgit_config(git_default_config, NULL);\n+\tgit_config(rebase_config, &options);\n+\n \targc = parse_options(argc, argv, prefix,\n \t\t\t     builtin_rebase_options,\n \t\t\t     builtin_rebase_usage, 0);\n@@ -456,6 +485,33 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \t\t\targc ? argv[0] : NULL, NULL))\n \t\tdie(_(\"The pre-rebase hook refused to rebase.\"));\n \n+\tif (options.flags & REBASE_DIFFSTAT) {\n+\t\tstruct diff_options opts;\n+\n+\t\tif (options.flags & REBASE_VERBOSE)\n+\t\t\tprintf(_(\"Changes from %s to %s:\\n\"),\n+\t\t\t\toid_to_hex(&merge_base),\n+\t\t\t\toid_to_hex(&options.onto->object.oid));\n+\n+\t\t/* We want color (if set), but no pager */\n+\t\tdiff_setup(&opts);\n+\t\topts.stat_width = -1; /* use full terminal width */\n+\t\topts.stat_graph_width = -1; /* respect statGraphWidth config */\n+\t\topts.output_format |=\n+\t\t\tDIFF_FORMAT_SUMMARY | DIFF_FORMAT_DIFFSTAT;\n+\t\topts.detect_rename = DIFF_DETECT_RENAME;\n+\t\tdiff_setup_done(&opts);\n+\t\tdiff_tree_oid(&merge_base, &options.onto->object.oid,\n+\t\t\t      \"\", &opts);\n+\t\tdiffcore_std(&opts);\n+\t\tdiff_flush(&opts);\n+\t}\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+\t\t\t \"it...\\n\"));\n+\n \tstrbuf_addf(&msg, \"rebase: checkout %s\", options.onto_name);\n \tif (reset_head(&options.onto->object.oid, \"checkout\", NULL, 1))\n \t\tdie(_(\"Could not detach HEAD\"));\n-- \n2.18.0\n\n"},{"id":"354807","messageId":"20180808134830.19949-7-predatoramigo@gmail.com","threadId":"49071","inReplyTo":"20180808134830.19949-1-predatoramigo@gmail.com","subject":"[PATCH 06/11] builtin rebase: require a clean worktree","fromName":"Pratik Karki","fromEmail":"predatoramigo@gmail.com","sentAt":"2018-08-08T13:48:25Z","receivedAt":"2018-08-08T13:51:34Z","isPatch":true,"sender":{"key":"predatoramigo@gmail.com","avatar":"https://avatars.githubusercontent.com/u/12194950?v=4"},"body":"This commit reads the index of the repository for rebase and checks\nwhether the repository is ready for rebase.\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 2d3f1d65fb..afef0b0046 100644\n--- a/builtin/rebase.c\n+++ b/builtin/rebase.c\n@@ -19,6 +19,7 @@\n #include \"parse-options.h\"\n #include \"commit.h\"\n #include \"diff.h\"\n+#include \"wt-status.h\"\n \n static char const * const builtin_rebase_usage[] = {\n \tN_(\"git rebase [-i] [options] [--exec <cmd>] [--onto <newbase>] \"\n@@ -479,6 +480,15 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \t\t\tdie(_(\"Could not resolve HEAD to a revision\"));\n \t}\n \n+\tif (read_index(the_repository->index) < 0)\n+\t\tdie(_(\"could not read index\"));\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+\t\tgoto cleanup;\n+\t}\n+\n \t/* If a hook exists, give it a chance to interrupt*/\n \tif (!ok_to_skip_pre_rebase &&\n \t    run_hook_le(NULL, \"pre-rebase\", options.upstream_arg,\n@@ -528,6 +538,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \n \tret = !!run_specific_rebase(&options);\n \n+cleanup:\n \tstrbuf_release(&revisions);\n \tfree(options.head_name);\n \treturn ret;\n-- \n2.18.0\n\n"},{"id":"354808","messageId":"20180808134830.19949-8-predatoramigo@gmail.com","threadId":"49071","inReplyTo":"20180808134830.19949-1-predatoramigo@gmail.com","subject":"[PATCH 07/11] builtin rebase: try to fast forward when possible","fromName":"Pratik Karki","fromEmail":"predatoramigo@gmail.com","sentAt":"2018-08-08T13:48:26Z","receivedAt":"2018-08-08T13:51:38Z","isPatch":true,"sender":{"key":"predatoramigo@gmail.com","avatar":"https://avatars.githubusercontent.com/u/12194950?v=4"},"body":"In this commit, we add support to fast forward.\n\nNote: we will need the merge base later, therefore the call to\ncan_fast_forward() really needs to be the first one when testing whether\nwe can skip the rebase entirely (otherwise, it would make more sense to\nskip the possibly expensive operation if, say, running an interactive\nrebase).\n\nSigned-off-by: Pratik Karki <predatoramigo@gmail.com>\n---\n builtin/rebase.c | 72 ++++++++++++++++++++++++++++++++++++++++++++++++\n 1 file changed, 72 insertions(+)\n\ndiff --git a/builtin/rebase.c b/builtin/rebase.c\nindex afef0b0046..52a218cd18 100644\n--- a/builtin/rebase.c\n+++ b/builtin/rebase.c\n@@ -20,6 +20,7 @@\n #include \"commit.h\"\n #include \"diff.h\"\n #include \"wt-status.h\"\n+#include \"revision.h\"\n \n static char const * const builtin_rebase_usage[] = {\n \tN_(\"git rebase [-i] [options] [--exec <cmd>] [--onto <newbase>] \"\n@@ -89,6 +90,12 @@ struct rebase_options {\n \tstruct strbuf git_am_opt;\n };\n \n+static int is_interactive(struct rebase_options *opts)\n+{\n+\treturn opts->type == REBASE_INTERACTIVE ||\n+\t\topts->type == REBASE_PRESERVE_MERGES;\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@@ -334,6 +341,46 @@ static int rebase_config(const char *var, const char *value, void *data)\n \treturn git_default_config(var, value, data);\n }\n \n+/*\n+ * Determines whether the commits in from..to are linear, i.e. contain\n+ * no merge commits. This function *expects* `from` to be an ancestor of\n+ * `to`.\n+ */\n+static int is_linear_history(struct commit *from, struct commit *to)\n+{\n+\twhile (to && to != from) {\n+\t\tparse_commit(to);\n+\t\tif (!to->parents)\n+\t\t\treturn 1;\n+\t\tif (to->parents->next)\n+\t\t\treturn 0;\n+\t\tto = to->parents->item;\n+\t}\n+\treturn 1;\n+}\n+\n+static int can_fast_forward(struct commit *onto, struct object_id *head_oid,\n+\t\t\t    struct object_id *merge_base)\n+{\n+\tstruct commit *head = lookup_commit(the_repository, head_oid);\n+\tstruct commit_list *merge_bases;\n+\tint res;\n+\n+\tif (!head)\n+\t\treturn 0;\n+\n+\tmerge_bases = get_merge_bases(onto, head);\n+\tif (merge_bases && !merge_bases->next) {\n+\t\toidcpy(merge_base, &merge_bases->item->object.oid);\n+\t\tres = !oidcmp(merge_base, &onto->object.oid);\n+\t} else {\n+\t\toidcpy(merge_base, &null_oid);\n+\t\tres = 0;\n+\t}\n+\tfree_commit_list(merge_bases);\n+\treturn res && is_linear_history(onto, head);\n+}\n+\n int cmd_rebase(int argc, const char **argv, const char *prefix)\n {\n \tstruct rebase_options options = {\n@@ -489,6 +536,31 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \t\tgoto cleanup;\n \t}\n \n+\t/*\n+\t * Now we are rebasing commits upstream..orig_head (or with --root,\n+\t * everything leading up to orig_head) on top of onto.\n+\t */\n+\n+\t/*\n+\t * Check if we are already based on onto with linear history,\n+\t * but this should be done only when upstream and onto are the same\n+\t * and if this is not an interactive rebase.\n+\t */\n+\tif (can_fast_forward(options.onto, &options.orig_head, &merge_base) &&\n+\t    !is_interactive(&options) && !options.restrict_revision &&\n+\t    !oidcmp(&options.upstream->object.oid, &options.onto->object.oid)) {\n+\t\tint flag;\n+\n+\t\tif (!(options.flags & REBASE_NO_QUIET))\n+\t\t\t; /* be quiet */\n+\t\telse if (!strcmp(branch_name, \"HEAD\") &&\n+\t\t\tresolve_ref_unsafe(\"HEAD\", 0, NULL, &flag))\n+\t\t\tputs(_(\"HEAD is up to date, rebase forced.\"));\n+\t\telse\n+\t\t\tprintf(_(\"Current branch %s is up to date, rebase \"\n+\t\t\t\t \"forced.\\n\"), branch_name);\n+\t}\n+\n \t/* If a hook exists, give it a chance to interrupt*/\n \tif (!ok_to_skip_pre_rebase &&\n \t    run_hook_le(NULL, \"pre-rebase\", options.upstream_arg,\n-- \n2.18.0\n\n"},{"id":"354809","messageId":"20180808134830.19949-9-predatoramigo@gmail.com","threadId":"49071","inReplyTo":"20180808134830.19949-1-predatoramigo@gmail.com","subject":"[PATCH 08/11] builtin rebase: support --force-rebase","fromName":"Pratik Karki","fromEmail":"predatoramigo@gmail.com","sentAt":"2018-08-08T13:48:27Z","receivedAt":"2018-08-08T13:51:41Z","isPatch":true,"sender":{"key":"predatoramigo@gmail.com","avatar":"https://avatars.githubusercontent.com/u/12194950?v=4"},"body":"In this commit, we add support to `--force-rebase` option. The\nequivalent part of the shell script found in `git-legacy-rebase.sh` is\nconverted as faithfully as possible to C.\n\nThe --force-rebase option ensures that the rebase does not simply\nfast-forward even if it could.\n\nSigned-off-by: Pratik Karki <predatoramigo@gmail.com>\n---\n builtin/rebase.c | 24 ++++++++++++++++++++++--\n 1 file changed, 22 insertions(+), 2 deletions(-)\n\ndiff --git a/builtin/rebase.c b/builtin/rebase.c\nindex 52a218cd18..8a7bf3d468 100644\n--- a/builtin/rebase.c\n+++ b/builtin/rebase.c\n@@ -86,6 +86,7 @@ struct rebase_options {\n \t\tREBASE_NO_QUIET = 1<<0,\n \t\tREBASE_VERBOSE = 1<<1,\n \t\tREBASE_DIFFSTAT = 1<<2,\n+\t\tREBASE_FORCE = 1<<3,\n \t} flags;\n \tstruct strbuf git_am_opt;\n };\n@@ -181,6 +182,8 @@ static int run_specific_rebase(struct rebase_options *opts)\n \t\topts->flags & REBASE_VERBOSE ? \"t\" : \"\");\n \tadd_var(&script_snippet, \"diffstat\",\n \t\topts->flags & REBASE_DIFFSTAT ? \"t\" : \"\");\n+\tadd_var(&script_snippet, \"force_rebase\",\n+\t\topts->flags & REBASE_FORCE ? \"t\" : \"\");\n \n \tswitch (opts->type) {\n \tcase REBASE_AM:\n@@ -409,6 +412,12 @@ 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_BIT('f', \"force-rebase\", &options.flags,\n+\t\t\tN_(\"cherry-pick all commits, even if unchanged\"),\n+\t\t\tREBASE_FORCE),\n+\t\tOPT_BIT(0, \"no-ff\", &options.flags,\n+\t\t\tN_(\"cherry-pick all commits, even if unchanged\"),\n+\t\t\tREBASE_FORCE),\n \t\tOPT_END(),\n \t};\n \n@@ -551,10 +560,21 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \t    !oidcmp(&options.upstream->object.oid, &options.onto->object.oid)) {\n \t\tint flag;\n \n-\t\tif (!(options.flags & REBASE_NO_QUIET))\n+\t\tif (!(options.flags & REBASE_FORCE)) {\n+\t\t\tif (!(options.flags & REBASE_NO_QUIET))\n+\t\t\t\t; /* be quiet */\n+\t\t\telse if (!strcmp(branch_name, \"HEAD\") &&\n+\t\t\t\t resolve_ref_unsafe(\"HEAD\", 0, NULL, &flag))\n+\t\t\t\tputs(_(\"HEAD is up to date.\"));\n+\t\t\telse\n+\t\t\t\tprintf(_(\"Current branch %s is up to date.\\n\"),\n+\t\t\t\t       branch_name);\n+\t\t\tret = !!finish_rebase(&options);\n+\t\t\tgoto cleanup;\n+\t\t} else if (!(options.flags & REBASE_NO_QUIET))\n \t\t\t; /* be quiet */\n \t\telse if (!strcmp(branch_name, \"HEAD\") &&\n-\t\t\tresolve_ref_unsafe(\"HEAD\", 0, NULL, &flag))\n+\t\t\t resolve_ref_unsafe(\"HEAD\", 0, NULL, &flag))\n \t\t\tputs(_(\"HEAD is up to date, rebase forced.\"));\n \t\telse\n \t\t\tprintf(_(\"Current branch %s is up to date, rebase \"\n-- \n2.18.0\n\n"},{"id":"354810","messageId":"20180808134830.19949-10-predatoramigo@gmail.com","threadId":"49071","inReplyTo":"20180808134830.19949-1-predatoramigo@gmail.com","subject":"[PATCH 09/11] builtin rebase: start a new rebase only if none is in progress","fromName":"Pratik Karki","fromEmail":"predatoramigo@gmail.com","sentAt":"2018-08-08T13:48:28Z","receivedAt":"2018-08-08T13:51:45Z","isPatch":true,"sender":{"key":"predatoramigo@gmail.com","avatar":"https://avatars.githubusercontent.com/u/12194950?v=4"},"body":"To run a new rebase, there needs to be a check to assure that no other\nrebase is in progress. New rebase operation cannot start until an\nongoing rebase operation completes or is terminated.\n\nSigned-off-by: Pratik Karki <predatoramigo@gmail.com>\n---\n builtin/rebase.c | 48 +++++++++++++++++++++++++++++++++++++++++++++++-\n 1 file changed, 47 insertions(+), 1 deletion(-)\n\ndiff --git a/builtin/rebase.c b/builtin/rebase.c\nindex 8a7bf3d468..a261f552f1 100644\n--- a/builtin/rebase.c\n+++ b/builtin/rebase.c\n@@ -87,6 +87,7 @@ struct rebase_options {\n \t\tREBASE_VERBOSE = 1<<1,\n \t\tREBASE_DIFFSTAT = 1<<2,\n \t\tREBASE_FORCE = 1<<3,\n+\t\tREBASE_INTERACTIVE_EXPLICIT = 1<<4,\n \t} flags;\n \tstruct strbuf git_am_opt;\n };\n@@ -392,10 +393,11 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \t\t.git_am_opt = STRBUF_INIT,\n \t};\n \tconst char *branch_name;\n-\tint ret, flags;\n+\tint ret, flags, in_progress = 0;\n \tint ok_to_skip_pre_rebase = 0;\n \tstruct strbuf msg = STRBUF_INIT;\n \tstruct strbuf revisions = STRBUF_INIT;\n+\tstruct strbuf buf = STRBUF_INIT;\n \tstruct object_id merge_base;\n \tstruct option builtin_rebase_options[] = {\n \t\tOPT_STRING(0, \"onto\", &options.onto_name,\n@@ -447,6 +449,30 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \n \tgit_config(rebase_config, &options);\n \n+\tif (is_directory(apply_dir())) {\n+\t\toptions.type = REBASE_AM;\n+\t\toptions.state_dir = apply_dir();\n+\t} else if (is_directory(merge_dir())) {\n+\t\tstrbuf_reset(&buf);\n+\t\tstrbuf_addf(&buf, \"%s/rewritten\", merge_dir());\n+\t\tif (is_directory(buf.buf)) {\n+\t\t\toptions.type = REBASE_PRESERVE_MERGES;\n+\t\t\toptions.flags |= REBASE_INTERACTIVE_EXPLICIT;\n+\t\t} else {\n+\t\t\tstrbuf_reset(&buf);\n+\t\t\tstrbuf_addf(&buf, \"%s/interactive\", merge_dir());\n+\t\t\tif(file_exists(buf.buf)) {\n+\t\t\t\toptions.type = REBASE_INTERACTIVE;\n+\t\t\t\toptions.flags |= REBASE_INTERACTIVE_EXPLICIT;\n+\t\t\t} else\n+\t\t\t\toptions.type = REBASE_MERGE;\n+\t\t}\n+\t\toptions.state_dir = merge_dir();\n+\t}\n+\n+\tif (options.type != REBASE_UNSPECIFIED)\n+\t\tin_progress = 1;\n+\n \targc = parse_options(argc, argv, prefix,\n \t\t\t     builtin_rebase_options,\n \t\t\t     builtin_rebase_usage, 0);\n@@ -455,6 +481,26 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \t\tusage_with_options(builtin_rebase_usage,\n \t\t\t\t   builtin_rebase_options);\n \n+\t/* Make sure no rebase is in progress */\n+\tif (in_progress) {\n+\t\tconst char *last_slash = strrchr(options.state_dir, '/');\n+\t\tconst char *state_dir_base =\n+\t\t\tlast_slash ? last_slash + 1 : options.state_dir;\n+\t\tconst char *cmd_live_rebase =\n+\t\t\t\"git rebase (--continue | --abort | --skip)\";\n+\t\tstrbuf_reset(&buf);\n+\t\tstrbuf_addf(&buf, \"rm -fr \\\"%s\\\"\", options.state_dir);\n+\t\tdie(_(\"It seems that there is already a %s directory, and\\n\"\n+\t\t      \"I wonder if you are in the middle of another rebase.  \"\n+\t\t      \"If that is the\\n\"\n+\t\t      \"case, please try\\n\\t%s\\n\"\n+\t\t      \"If that is not the case, please\\n\\t%s\\n\"\n+\t\t      \"and run me again.  I am stopping in case you still \"\n+\t\t      \"have something\\n\"\n+\t\t      \"valuable there.\\n\"),\n+\t\t    state_dir_base, cmd_live_rebase,buf.buf);\n+\t}\n+\n \tif (!(options.flags & REBASE_NO_QUIET))\n \t\tstrbuf_addstr(&options.git_am_opt, \" -q\");\n \n-- \n2.18.0\n\n"},{"id":"354811","messageId":"20180808134830.19949-11-predatoramigo@gmail.com","threadId":"49071","inReplyTo":"20180808134830.19949-1-predatoramigo@gmail.com","subject":"[PATCH 10/11] builtin rebase: only store fully-qualified refs in `options.head_name`","fromName":"Pratik Karki","fromEmail":"predatoramigo@gmail.com","sentAt":"2018-08-08T13:48:29Z","receivedAt":"2018-08-08T13:51:49Z","isPatch":true,"sender":{"key":"predatoramigo@gmail.com","avatar":"https://avatars.githubusercontent.com/u/12194950?v=4"},"body":"When running a rebase on a detached HEAD, we currently store the string\n\"detached HEAD\" in options.head_name. That is a faithful translation of\nthe shell script version, and we still kind of need it for the purposes of\nthe scripted backends.\n\nIt is poor style for C, though, where we would really only want a valid,\nfully-qualified ref name as value, and NULL for detached HEADs, using\n\"detached HEAD\" for display only. Make it so.\n\nSigned-off-by: Pratik Karki <predatoramigo@gmail.com>\n---\n builtin/rebase.c | 11 ++++++++---\n 1 file changed, 8 insertions(+), 3 deletions(-)\n\ndiff --git a/builtin/rebase.c b/builtin/rebase.c\nindex a261f552f1..63634210c0 100644\n--- a/builtin/rebase.c\n+++ b/builtin/rebase.c\n@@ -169,7 +169,8 @@ static int run_specific_rebase(struct rebase_options *opts)\n \tadd_var(&script_snippet, \"upstream_name\", opts->upstream_name);\n \tadd_var(&script_snippet, \"upstream\",\n \t\t\t\t oid_to_hex(&opts->upstream->object.oid));\n-\tadd_var(&script_snippet, \"head_name\", opts->head_name);\n+\tadd_var(&script_snippet, \"head_name\",\n+\t\topts->head_name ? opts->head_name : \"detached HEAD\");\n \tadd_var(&script_snippet, \"orig_head\", oid_to_hex(&opts->orig_head));\n \tadd_var(&script_snippet, \"onto\", oid_to_hex(&opts->onto->object.oid));\n \tadd_var(&script_snippet, \"onto_name\", opts->onto_name);\n@@ -251,6 +252,9 @@ static int reset_head(struct object_id *oid, const char *action,\n \t\t*old_orig = NULL, oid_old_orig;\n \tint ret = 0;\n \n+\tif (switch_to_branch && !starts_with(switch_to_branch, \"refs/\"))\n+\t\tBUG(\"Not a fully qualified branch: '%s'\", switch_to_branch);\n+\n \tif (hold_locked_index(&lock, LOCK_REPORT_ON_ERROR) < 0)\n \t\treturn -1;\n \n@@ -558,7 +562,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \t * branch_name -- branch/commit being rebased, or\n \t * \t\t  HEAD (already detached)\n \t * orig_head -- commit object name of tip of the branch before rebasing\n-\t * head_name -- refs/heads/<that-branch> or \"detached HEAD\"\n+\t * head_name -- refs/heads/<that-branch> or NULL (detached HEAD)\n \t */\n \tif (argc > 0)\n \t\t die(\"TODO: handle switch_to\");\n@@ -575,7 +579,8 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \t\t\t\tbranch_name = options.head_name;\n \n \t\t} else {\n-\t\t\toptions.head_name = xstrdup(\"detached HEAD\");\n+\t\t\tfree(options.head_name);\n+\t\t\toptions.head_name = NULL;\n \t\t\tbranch_name = \"HEAD\";\n \t\t}\n \t\tif (get_oid(\"HEAD\", &options.orig_head))\n-- \n2.18.0\n\n"},{"id":"354812","messageId":"20180808134830.19949-12-predatoramigo@gmail.com","threadId":"49071","inReplyTo":"20180808134830.19949-1-predatoramigo@gmail.com","subject":"[PATCH 11/11] builtin rebase: support `git rebase <upstream> <switch-to>`","fromName":"Pratik Karki","fromEmail":"predatoramigo@gmail.com","sentAt":"2018-08-08T13:48:30Z","receivedAt":"2018-08-08T13:51:52Z","isPatch":true,"sender":{"key":"predatoramigo@gmail.com","avatar":"https://avatars.githubusercontent.com/u/12194950?v=4"},"body":"This commit adds support for `switch-to` which is used to switch to the\ntarget branch if needed. The equivalent codes found in shell script\n`git-legacy-rebase.sh` is converted to builtin `rebase.c`.\n\nSigned-off-by: Pratik Karki <predatoramigo@gmail.com>\n---\n builtin/rebase.c | 48 ++++++++++++++++++++++++++++++++++++++++++++----\n 1 file changed, 44 insertions(+), 4 deletions(-)\n\ndiff --git a/builtin/rebase.c b/builtin/rebase.c\nindex 63634210c0..b2ddfa8dbf 100644\n--- a/builtin/rebase.c\n+++ b/builtin/rebase.c\n@@ -79,6 +79,7 @@ struct rebase_options {\n \tstruct commit *onto;\n \tconst char *onto_name;\n \tconst char *revisions;\n+\tconst char *switch_to;\n \tint root;\n \tstruct commit *restrict_revision;\n \tint dont_finish_rebase;\n@@ -186,6 +187,8 @@ static int run_specific_rebase(struct rebase_options *opts)\n \t\topts->flags & REBASE_DIFFSTAT ? \"t\" : \"\");\n \tadd_var(&script_snippet, \"force_rebase\",\n \t\topts->flags & REBASE_FORCE ? \"t\" : \"\");\n+\tif (opts->switch_to)\n+\t\tadd_var(&script_snippet, \"switch_to\", opts->switch_to);\n \n \tswitch (opts->type) {\n \tcase REBASE_AM:\n@@ -564,9 +567,23 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \t * orig_head -- commit object name of tip of the branch before rebasing\n \t * head_name -- refs/heads/<that-branch> or NULL (detached HEAD)\n \t */\n-\tif (argc > 0)\n-\t\t die(\"TODO: handle switch_to\");\n-\telse {\n+\tif (argc == 1) {\n+\t\t/* Is it \"rebase other branchname\" or \"rebase other commit\"? */\n+\t\tbranch_name = argv[0];\n+\t\toptions.switch_to = argv[0];\n+\n+\t\t/* Is it a local branch? */\n+\t\tstrbuf_reset(&buf);\n+\t\tstrbuf_addf(&buf, \"refs/heads/%s\", branch_name);\n+\t\tif (!read_ref(buf.buf, &options.orig_head))\n+\t\t\toptions.head_name = xstrdup(buf.buf);\n+\t\t/* If not is it a valid ref (branch or commit)? */\n+\t\telse if (!get_oid(branch_name, &options.orig_head))\n+\t\t\toptions.head_name = NULL;\n+\t\telse\n+\t\t\tdie(_(\"fatal: no such branch/commit '%s'\"),\n+\t\t\t    branch_name);\n+\t} else if (argc == 0) {\n \t\t/* Do not need to switch branches, we are already on it. */\n \t\toptions.head_name =\n \t\t\txstrdup_or_null(resolve_ref_unsafe(\"HEAD\", 0, NULL,\n@@ -585,7 +602,8 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \t\t}\n \t\tif (get_oid(\"HEAD\", &options.orig_head))\n \t\t\tdie(_(\"Could not resolve HEAD to a revision\"));\n-\t}\n+\t} else\n+\t\tBUG(\"unexpected number of arguments left to parse\");\n \n \tif (read_index(the_repository->index) < 0)\n \t\tdie(_(\"could not read index\"));\n@@ -612,6 +630,28 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \t\tint flag;\n \n \t\tif (!(options.flags & REBASE_FORCE)) {\n+\t\t\t/* Lazily switch to the target branch if needed... */\n+\t\t\tif (options.switch_to) {\n+\t\t\t\tstruct object_id oid;\n+\n+\t\t\t\tif (get_oid(options.switch_to, &oid) < 0) {\n+\t\t\t\t\tret = !!error(_(\"could not parse '%s'\"),\n+\t\t\t\t\t\t      options.switch_to);\n+\t\t\t\t\tgoto cleanup;\n+\t\t\t\t}\n+\n+\t\t\t\tstrbuf_reset(&buf);\n+\t\t\t\tstrbuf_addf(&buf, \"rebase: checkout %s\",\n+\t\t\t\t\t    options.switch_to);\n+\t\t\t\tif (reset_head(&oid, \"checkout\",\n+\t\t\t\t\t       options.head_name, 0) < 0) {\n+\t\t\t\t\tret = !!error(_(\"could not switch to \"\n+\t\t\t\t\t\t\t\"%s\"),\n+\t\t\t\t\t\t      options.switch_to);\n+\t\t\t\t\tgoto cleanup;\n+\t\t\t\t}\n+\t\t\t}\n+\n \t\t\tif (!(options.flags & REBASE_NO_QUIET))\n \t\t\t\t; /* be quiet */\n \t\t\telse if (!strcmp(branch_name, \"HEAD\") &&\n-- \n2.18.0\n\n"},{"id":"354856","messageId":"CACsJy8BDLvGhRvNQgSgvkR-RMAvVxPpT=i9ayi=awQYOqd2Crg@mail.gmail.com","threadId":"49071","inReplyTo":"20180808134830.19949-12-predatoramigo@gmail.com","subject":"Re: [PATCH 11/11] builtin rebase: support `git rebase <upstream> <switch-to>`","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2018-08-08T16:03:12Z","receivedAt":"2018-08-08T16:03:41Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"(not really a review, this patch just happens to catch my eyes)\n\nOn Wed, Aug 8, 2018 at 3:55 PM Pratik Karki <predatoramigo@gmail.com> wrote:\n>\n> This commit adds support for `switch-to` which is used to switch to the\n> target branch if needed. The equivalent codes found in shell script\n> `git-legacy-rebase.sh` is converted to builtin `rebase.c`.\n>\n> Signed-off-by: Pratik Karki <predatoramigo@gmail.com>\n> ---\n>  builtin/rebase.c | 48 ++++++++++++++++++++++++++++++++++++++++++++----\n>  1 file changed, 44 insertions(+), 4 deletions(-)\n>\n> diff --git a/builtin/rebase.c b/builtin/rebase.c\n> index 63634210c0..b2ddfa8dbf 100644\n> --- a/builtin/rebase.c\n> +++ b/builtin/rebase.c\n> @@ -79,6 +79,7 @@ struct rebase_options {\n>         struct commit *onto;\n>         const char *onto_name;\n>         const char *revisions;\n> +       const char *switch_to;\n>         int root;\n>         struct commit *restrict_revision;\n>         int dont_finish_rebase;\n> @@ -186,6 +187,8 @@ static int run_specific_rebase(struct rebase_options *opts)\n>                 opts->flags & REBASE_DIFFSTAT ? \"t\" : \"\");\n>         add_var(&script_snippet, \"force_rebase\",\n>                 opts->flags & REBASE_FORCE ? \"t\" : \"\");\n> +       if (opts->switch_to)\n> +               add_var(&script_snippet, \"switch_to\", opts->switch_to);\n>\n>         switch (opts->type) {\n>         case REBASE_AM:\n> @@ -564,9 +567,23 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n>          * orig_head -- commit object name of tip of the branch before rebasing\n>          * head_name -- refs/heads/<that-branch> or NULL (detached HEAD)\n>          */\n> -       if (argc > 0)\n> -                die(\"TODO: handle switch_to\");\n> -       else {\n> +       if (argc == 1) {\n> +               /* Is it \"rebase other branchname\" or \"rebase other commit\"? */\n> +               branch_name = argv[0];\n> +               options.switch_to = argv[0];\n> +\n> +               /* Is it a local branch? */\n> +               strbuf_reset(&buf);\n> +               strbuf_addf(&buf, \"refs/heads/%s\", branch_name);\n> +               if (!read_ref(buf.buf, &options.orig_head))\n> +                       options.head_name = xstrdup(buf.buf);\n> +               /* If not is it a valid ref (branch or commit)? */\n> +               else if (!get_oid(branch_name, &options.orig_head))\n> +                       options.head_name = NULL;\n> +               else\n> +                       die(_(\"fatal: no such branch/commit '%s'\"),\n\ndie() automatically adds \"fatal:\" so you should not add it yourself here\n\n> +                           branch_name);\n> +       } else if (argc == 0) {\n>                 /* Do not need to switch branches, we are already on it. */\n>                 options.head_name =\n>                         xstrdup_or_null(resolve_ref_unsafe(\"HEAD\", 0, NULL,\n> @@ -585,7 +602,8 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n>                 }\n>                 if (get_oid(\"HEAD\", &options.orig_head))\n>                         die(_(\"Could not resolve HEAD to a revision\"));\n> -       }\n> +       } else\n> +               BUG(\"unexpected number of arguments left to parse\");\n\nDoes this mean \"git base one two three\" triggers this BUG? If so, this\nshould be a die() instead. I did not real the full source code, so\nmaybe this case is already caught higher up.\n-- \nDuy\n"},{"id":"354879","messageId":"CAGZ79kah=sGgzJS1rL6Bx1Vkd6RVFLUNEk_o4iqKsjDx5_arJw@mail.gmail.com","threadId":"49071","inReplyTo":"20180808134830.19949-5-predatoramigo@gmail.com","subject":"Re: [PATCH 04/11] builtin rebase: support --quiet","fromName":"Stefan Beller","fromEmail":"sbeller@google.com","sentAt":"2018-08-08T18:31:59Z","receivedAt":"2018-08-08T18:32:12Z","isPatch":true,"sender":{"key":"stefanbeller@gmail.com","avatar":"https://avatars.githubusercontent.com/u/455868?v=4"},"body":"On Wed, Aug 8, 2018 at 6:51 AM Pratik Karki <predatoramigo@gmail.com> wrote:\n>\n> This commit introduces a rebase option `--quiet`. While `--quiet` is\n> commonly perceived as opposite to `--verbose`, this is not the case for\n> the rebase command: both `--quiet` and `--verbose` default to `false` if\n> neither `--quiet` nor `--verbose` is present.\n>\n> This commit goes further and introduces `--no-quiet` which is the\n> contrary of `--quiet` and it's introduction doesn't modify any\n> behaviour.\n>\n> Note: The `flags` field in `rebase_options` will accumulate more bits in\n> subsequent commits, in particular a verbose and a diffstat flag. And as\n> --quoet inthe shell scripted version of the rebase command switches off\n\n  --quote in the\n\n(in case a resend is needed)\n"},{"id":"354884","messageId":"CAGZ79ka1uokeUzyZ37=o7J0Tu0k8P4fKj8hv8L-GpktU5i7+mQ@mail.gmail.com","threadId":"49071","inReplyTo":"20180808134830.19949-9-predatoramigo@gmail.com","subject":"Re: [PATCH 08/11] builtin rebase: support --force-rebase","fromName":"Stefan Beller","fromEmail":"sbeller@google.com","sentAt":"2018-08-08T18:51:01Z","receivedAt":"2018-08-08T18:51:16Z","isPatch":true,"sender":{"key":"stefanbeller@gmail.com","avatar":"https://avatars.githubusercontent.com/u/455868?v=4"},"body":"On Wed, Aug 8, 2018 at 6:51 AM Pratik Karki <predatoramigo@gmail.com> wrote:\n\n> @@ -551,10 +560,21 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n[...]\n>                         ; /* be quiet */\n>                 else if (!strcmp(branch_name, \"HEAD\") &&\n> -                       resolve_ref_unsafe(\"HEAD\", 0, NULL, &flag))\n> +                        resolve_ref_unsafe(\"HEAD\", 0, NULL, &flag))\n\nThis line is changing only the indentation whitespace?\nWould it make sense to have it in the previous patch?\n"},{"id":"354885","messageId":"nycvar.QRO.7.76.6.1808082049180.71@tvgsbejvaqbjf.bet","threadId":"49071","inReplyTo":"CACsJy8BDLvGhRvNQgSgvkR-RMAvVxPpT=i9ayi=awQYOqd2Crg@mail.gmail.com","subject":"Re: [PATCH 11/11] builtin rebase: support `git rebase <upstream> <switch-to>`","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2018-08-08T18:52:24Z","receivedAt":"2018-08-08T18:52:31Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Duy,\n\nOn Wed, 8 Aug 2018, Duy Nguyen wrote:\n\n> On Wed, Aug 8, 2018 at 3:55 PM Pratik Karki <predatoramigo@gmail.com> wrote:\n> >\n> > diff --git a/builtin/rebase.c b/builtin/rebase.c\n> > index 63634210c0..b2ddfa8dbf 100644\n> > --- a/builtin/rebase.c\n> > +++ b/builtin/rebase.c\n> > @@ -585,7 +602,8 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n> >                 }\n> >                 if (get_oid(\"HEAD\", &options.orig_head))\n> >                         die(_(\"Could not resolve HEAD to a revision\"));\n> > -       }\n> > +       } else\n> > +               BUG(\"unexpected number of arguments left to parse\");\n> \n> Does this mean \"git base one two three\" triggers this BUG? If so, this\n> should be a die() instead. I did not real the full source code, so\n> maybe this case is already caught higher up.\n\nAs you can see from\n\n\thttps://github.com/git/git/blob/v2.18.0/git-rebase.sh#L615\n\nthe original, Unix shell script version of `git rebase` also says \"BUG\"\nhere. And if you care to look at\n\n\thttps://github.com/git/git/blob/3358abdcb/builtin/rebase.c#L870-L872\n\nyou will see that there is a proper check for the correct amount of\ncommand-line parameters.\n\nSo at this point, it would indeed indicate a bug if the `argc` had an\nunexpected value.\n\nCiao,\nDscho\n"},{"id":"354913","messageId":"CAGZ79kafP=dVrwWopXW0WCWf199sU6uFSphjxtMTXDSix4Y81Q@mail.gmail.com","threadId":"49071","inReplyTo":"20180808134830.19949-10-predatoramigo@gmail.com","subject":"Re: [PATCH 09/11] builtin rebase: start a new rebase only if none is in progress","fromName":"Stefan Beller","fromEmail":"sbeller@google.com","sentAt":"2018-08-08T18:59:35Z","receivedAt":"2018-08-08T18:59:49Z","isPatch":true,"sender":{"key":"stefanbeller@gmail.com","avatar":"https://avatars.githubusercontent.com/u/455868?v=4"},"body":"On Wed, Aug 8, 2018 at 6:51 AM Pratik Karki <predatoramigo@gmail.com> wrote:\n>\n> To run a new rebase, there needs to be a check to assure that no other\n> rebase is in progress. New rebase operation cannot start until an\n> ongoing rebase operation completes or is terminated.\n>\n> Signed-off-by: Pratik Karki <predatoramigo@gmail.com>\n> ---\n>  builtin/rebase.c | 48 +++++++++++++++++++++++++++++++++++++++++++++++-\n>  1 file changed, 47 insertions(+), 1 deletion(-)\n>\n> diff --git a/builtin/rebase.c b/builtin/rebase.c\n> index 8a7bf3d468..a261f552f1 100644\n> --- a/builtin/rebase.c\n> +++ b/builtin/rebase.c\n> @@ -87,6 +87,7 @@ struct rebase_options {\n>                 REBASE_VERBOSE = 1<<1,\n>                 REBASE_DIFFSTAT = 1<<2,\n>                 REBASE_FORCE = 1<<3,\n> +               REBASE_INTERACTIVE_EXPLICIT = 1<<4,\n>         } flags;\n>         struct strbuf git_am_opt;\n>  };\n> @@ -392,10 +393,11 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n>                 .git_am_opt = STRBUF_INIT,\n>         };\n>         const char *branch_name;\n> -       int ret, flags;\n> +       int ret, flags, in_progress = 0;\n>         int ok_to_skip_pre_rebase = 0;\n>         struct strbuf msg = STRBUF_INIT;\n>         struct strbuf revisions = STRBUF_INIT;\n> +       struct strbuf buf = STRBUF_INIT;\n>         struct object_id merge_base;\n>         struct option builtin_rebase_options[] = {\n>                 OPT_STRING(0, \"onto\", &options.onto_name,\n> @@ -447,6 +449,30 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n>\n>         git_config(rebase_config, &options);\n>\n> +       if (is_directory(apply_dir())) {\n> +               options.type = REBASE_AM;\n> +               options.state_dir = apply_dir();\n> +       } else if (is_directory(merge_dir())) {\n> +               strbuf_reset(&buf);\n> +               strbuf_addf(&buf, \"%s/rewritten\", merge_dir());\n> +               if (is_directory(buf.buf)) {\n> +                       options.type = REBASE_PRESERVE_MERGES;\n> +                       options.flags |= REBASE_INTERACTIVE_EXPLICIT;\n> +               } else {\n> +                       strbuf_reset(&buf);\n> +                       strbuf_addf(&buf, \"%s/interactive\", merge_dir());\n> +                       if(file_exists(buf.buf)) {\n> +                               options.type = REBASE_INTERACTIVE;\n> +                               options.flags |= REBASE_INTERACTIVE_EXPLICIT;\n> +                       } else\n> +                               options.type = REBASE_MERGE;\n> +               }\n> +               options.state_dir = merge_dir();\n> +       }\n> +\n> +       if (options.type != REBASE_UNSPECIFIED)\n> +               in_progress = 1;\n> +\n>         argc = parse_options(argc, argv, prefix,\n>                              builtin_rebase_options,\n>                              builtin_rebase_usage, 0);\n> @@ -455,6 +481,26 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n>                 usage_with_options(builtin_rebase_usage,\n>                                    builtin_rebase_options);\n>\n> +       /* Make sure no rebase is in progress */\n\nThe faithful conversion doesn't even stop at the comments. ;-)\nI shortly wondered if this is the best place for this comment,\nbut let's just keep it here to have the 1:1 rewrite.\n\n\n> +       if (in_progress) {\n[...]\n> +                   state_dir_base, cmd_live_rebase,buf.buf);\n\nIn case a resend is needed, add a whitespace after the\ncomma and buf.buf, please.\n\nSo far I have not seen anything major that would warrant a resend.\n\nThanks,\nStefan\n"},{"id":"354915","messageId":"xmqq600kheb7.fsf@gitster-ct.c.googlers.com","threadId":"49071","inReplyTo":"20180808134830.19949-2-predatoramigo@gmail.com","subject":"Re: [PATCH 01/11] builtin rebase: support --onto","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2018-08-08T19:02:36Z","receivedAt":"2018-08-08T19:02:42Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Pratik Karki <predatoramigo@gmail.com> writes:\n\n> The `--onto` option is important, as it allows to rebase a range of\n> commits onto a different base commit (which gave the command its odd\n> name: \"rebase\").\n\nIs there anything unimportant?  A rhetorical question, of course.\n\nThe quite casual and natural use of \"to rebase\" as a verb in the\nfirst sentence contradicts with what the parenthetical \"its odd\nname\" comment says.  Perhaps drop everything after \"(which...\"?\n\ni.e.\n\n\tThe `--onto` option allows to rebase a range of commits onto\n\ta different base commit.  Port the support for the option to\n\tthe C re-implementation.\n\n> This commit introduces options parsing so that different options can\n> be added in future commits.\n\nWe usually do not say \"This commit does X\", or (worse) \"I do X in\nthis commit\".  Instead, order the codebase to be like so, e.g.\n\"Support command line options by adding a call to parse_options();\nlater commits will add more options by building on top.\" or\nsomething like that.\n\n> @@ -318,13 +334,22 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n>  \t\t\tBUG(\"sane_execvp() returned???\");\n>  \t}\n>  \n> -\tif (argc != 2)\n> -\t\tdie(_(\"Usage: %s <base>\"), argv[0]);\n> +\tif (argc == 2 && !strcmp(argv[1], \"-h\"))\n> +\t\tusage_with_options(builtin_rebase_usage,\n> +\t\t\t\t   builtin_rebase_options);\n> +\n>  \tprefix = setup_git_directory();\n>  \ttrace_repo_setup(prefix);\n>  \tsetup_work_tree();\n>\n>  \tgit_config(git_default_config, NULL);\n> +\targc = parse_options(argc, argv, prefix,\n> +\t\t\t     builtin_rebase_options,\n> +\t\t\t     builtin_rebase_usage, 0);\n> +\n> +\tif (argc > 2)\n> +\t\tusage_with_options(builtin_rebase_usage,\n> +\t\t\t\t   builtin_rebase_options);\n\nOK.  This correctly calls the parser after repository setup.\n\n>  \tswitch (options.type) {\n>  \tcase REBASE_MERGE:\n> @@ -343,10 +368,10 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n>  \t}\n>  \n>  \tif (!options.root) {\n> -\t\tif (argc < 2)\n> +\t\tif (argc < 1)\n>  \t\t\tdie(\"TODO: handle @{upstream}\");\n>  \t\telse {\n> -\t\t\toptions.upstream_name = argv[1];\n> +\t\t\toptions.upstream_name = argv[0];\n>  \t\t\targc--;\n>  \t\t\targv++;\n>  \t\t\tif (!strcmp(options.upstream_name, \"-\"))\n> @@ -377,7 +402,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n>  \t * orig_head -- commit object name of tip of the branch before rebasing\n>  \t * head_name -- refs/heads/<that-branch> or \"detached HEAD\"\n>  \t */\n> -\tif (argc > 1)\n> +\tif (argc > 0)\n>  \t\t die(\"TODO: handle switch_to\");\n>  \telse {\n>  \t\t/* Do not need to switch branches, we are already on it. */\n"},{"id":"354916","messageId":"xmqq1sb8hdvd.fsf@gitster-ct.c.googlers.com","threadId":"49071","inReplyTo":"20180808134830.19949-3-predatoramigo@gmail.com","subject":"Re: [PATCH 02/11] builtin rebase: support `git rebase --onto A...B`","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2018-08-08T19:12:06Z","receivedAt":"2018-08-08T19:12:10Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Pratik Karki <predatoramigo@gmail.com> writes:\n\n> This commit implements support for an --onto argument that is actually a\n> \"symmetric range\" i.e. `<rev1>...<rev2>`.\n>\n> The equivalent shell script version of the code offers two different\n> error messages for the cases where there is no merge base vs more than\n> one merge base. Though following the similar approach would be nice,\n> this would create more complexity than it is of current. Currently, for\n\nSorry, but it is unclear what you mean by \"than it is of current.\"\nDo you mean we leave it broken at this step in the series for now\nfor expediency, with the intention to later revisit and fix it, or\ndo you mean something else?\n\n> simple convenience, the `get_oid_mb()` function is used whose return\n> value does not discern between those two error conditions.\n>\n> Signed-off-by: Pratik Karki <predatoramigo@gmail.com>\n> ...\n> @@ -387,7 +389,11 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n>  \tif (!options.onto_name)\n>  \t\toptions.onto_name = options.upstream_name;\n>  \tif (strstr(options.onto_name, \"...\")) {\n> -\t\tdie(\"TODO\");\n> +\t\tif (get_oid_mb(options.onto_name, &merge_base) < 0)\n> +\t\t\tdie(_(\"'%s': need exactly one merge base\"),\n> +\t\t\t    options.onto_name);\n> +\t\toptions.onto = lookup_commit_or_die(&merge_base,\n> +\t\t\t\t\t\t    options.onto_name);\n\nThe original is slightly sloppy in that it will misparse\n\n\trebase --onto 'master^{/log ... message}'\n\nand this shares the same, which I think is probably OK.  When this\nactually becomes problematic, the original can easily be salvaged by\nmaking it to fall back to the same peel_committish in its else\nclause; I am not sure if this C rewrite is as easily be fixed the\nsame way, though.\n\n>  \t} else {\n>  \t\toptions.onto = peel_committish(options.onto_name);\n>  \t\tif (!options.onto)\n"},{"id":"354917","messageId":"xmqqwot0fydp.fsf@gitster-ct.c.googlers.com","threadId":"49071","inReplyTo":"20180808134830.19949-4-predatoramigo@gmail.com","subject":"Re: [PATCH 03/11] builtin rebase: handle the pre-rebase hook (and add --no-verify)","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2018-08-08T19:32:02Z","receivedAt":"2018-08-08T19:32:08Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Pratik Karki <predatoramigo@gmail.com> writes:\n\n> This commit converts the equivalent part of the shell script\n> `git-legacy-rebase.sh` to run the pre-rebase hook (unless disabled), and\n> to interrupt the rebase with error if the hook fails.\n>\n> Signed-off-by: Pratik Karki <predatoramigo@gmail.com>\n> ---\n\nIntroduction of upstream_arg in this step looked a bit\nsurprising, but the hook invocation is the only thing that uses it,\nso it is understandable.\n\n\"rebase: handle the re-rebase hook and --no-verify\" would have been\nsufficient, without \"add\" or parentheses.\n\n>  builtin/rebase.c | 11 +++++++++++\n>  1 file changed, 11 insertions(+)\n>\n> diff --git a/builtin/rebase.c b/builtin/rebase.c\n> index 38c496dd10..b79f9b0a9f 100644\n> --- a/builtin/rebase.c\n> +++ b/builtin/rebase.c\n> @@ -70,6 +70,7 @@ struct rebase_options {\n>  \tconst char *state_dir;\n>  \tstruct commit *upstream;\n>  \tconst char *upstream_name;\n> +\tconst char *upstream_arg;\n>  \tchar *head_name;\n>  \tstruct object_id orig_head;\n>  \tstruct commit *onto;\n> @@ -310,6 +311,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n>  \t};\n>  \tconst char *branch_name;\n>  \tint ret, flags;\n> +\tint ok_to_skip_pre_rebase = 0;\n>  \tstruct strbuf msg = STRBUF_INIT;\n>  \tstruct strbuf revisions = STRBUF_INIT;\n>  \tstruct object_id merge_base;\n> @@ -317,6 +319,8 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n>  \t\tOPT_STRING(0, \"onto\", &options.onto_name,\n>  \t\t\t   N_(\"revision\"),\n>  \t\t\t   N_(\"rebase onto given branch instead of upstream\")),\n> +\t\tOPT_BOOL(0, \"no-verify\", &ok_to_skip_pre_rebase,\n> +\t\t\t N_(\"allow pre-rebase hook to run\")),\n\nDo we need to catch \"--no-no-verify\" ourselves with NONEG bit, or is\nthis sufficient to tell parse_options() machinery to take care of\nit?\n\n>  \t\tOPT_END(),\n>  \t};\n>  \n> @@ -382,6 +386,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n>  \t\toptions.upstream = peel_committish(options.upstream_name);\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>  \n> @@ -430,6 +435,12 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n>  \t\t\tdie(_(\"Could not resolve HEAD to a revision\"));\n>  \t}\n>  \n> +\t/* If a hook exists, give it a chance to interrupt*/\n> +\tif (!ok_to_skip_pre_rebase &&\n> +\t    run_hook_le(NULL, \"pre-rebase\", options.upstream_arg,\n> +\t\t\targc ? argv[0] : NULL, NULL))\n> +\t\tdie(_(\"The pre-rebase hook refused to rebase.\"));\n> +\n>  \tstrbuf_addf(&msg, \"rebase: checkout %s\", options.onto_name);\n>  \tif (reset_head(&options.onto->object.oid, \"checkout\", NULL, 1))\n>  \t\tdie(_(\"Could not detach HEAD\"));\n"},{"id":"354918","messageId":"xmqqsh3ofy4f.fsf@gitster-ct.c.googlers.com","threadId":"49071","inReplyTo":"CAGZ79kah=sGgzJS1rL6Bx1Vkd6RVFLUNEk_o4iqKsjDx5_arJw@mail.gmail.com","subject":"Re: [PATCH 04/11] builtin rebase: support --quiet","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2018-08-08T19:37:36Z","receivedAt":"2018-08-08T19:37:41Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Stefan Beller <sbeller@google.com> writes:\n\n> On Wed, Aug 8, 2018 at 6:51 AM Pratik Karki <predatoramigo@gmail.com> wrote:\n>>\n>> This commit introduces a rebase option `--quiet`. While `--quiet` is\n>> commonly perceived as opposite to `--verbose`, this is not the case for\n>> the rebase command: both `--quiet` and `--verbose` default to `false` if\n>> neither `--quiet` nor `--verbose` is present.\n>>\n>> This commit goes further and introduces `--no-quiet` which is the\n>> contrary of `--quiet` and it's introduction doesn't modify any\n>> behaviour.\n\nWhy?  Is it for completeness (i.e. does the scripted version take\nsuch an option and addition of --no-quiet makes the C rewrite behave\nthe same)?\n\n>> Note: The `flags` field in `rebase_options` will accumulate more bits in\n>> subsequent commits, in particular a verbose and a diffstat flag. And as\n>> --quoet inthe shell scripted version of the rebase command switches off\n>\n>   --quote in the\n>\n> (in case a resend is needed)\n\nMeaning --quiet?\n\n"},{"id":"356474","messageId":"nycvar.QRO.7.76.6.1808241809110.73@tvgsbejvaqbjf.bet","threadId":"49071","inReplyTo":"CAGZ79ka1uokeUzyZ37=o7J0Tu0k8P4fKj8hv8L-GpktU5i7+mQ@mail.gmail.com","subject":"Re: [PATCH 08/11] builtin rebase: support --force-rebase","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2018-08-24T16:10:11Z","receivedAt":"2018-08-24T16:10:19Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Stefan,\n\nOn Wed, 8 Aug 2018, Stefan Beller wrote:\n\n> On Wed, Aug 8, 2018 at 6:51 AM Pratik Karki <predatoramigo@gmail.com> wrote:\n> \n> > @@ -551,10 +560,21 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n> [...]\n> >                         ; /* be quiet */\n> >                 else if (!strcmp(branch_name, \"HEAD\") &&\n> > -                       resolve_ref_unsafe(\"HEAD\", 0, NULL, &flag))\n> > +                        resolve_ref_unsafe(\"HEAD\", 0, NULL, &flag))\n> \n> This line is changing only the indentation whitespace?\n> Would it make sense to have it in the previous patch?\n\nCorrect. I will fix this before sending the next iteration,\nDscho\n"},{"id":"356475","messageId":"nycvar.QRO.7.76.6.1808241811240.73@tvgsbejvaqbjf.bet","threadId":"49071","inReplyTo":"CAGZ79kafP=dVrwWopXW0WCWf199sU6uFSphjxtMTXDSix4Y81Q@mail.gmail.com","subject":"Re: [PATCH 09/11] builtin rebase: start a new rebase only if none is in progress","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2018-08-24T16:13:24Z","receivedAt":"2018-08-24T16:13:30Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Stefan,\n\nOn Wed, 8 Aug 2018, Stefan Beller wrote:\n\n> On Wed, Aug 8, 2018 at 6:51 AM Pratik Karki <predatoramigo@gmail.com> wrote:\n> >\n> > diff --git a/builtin/rebase.c b/builtin/rebase.c\n> > index 8a7bf3d468..a261f552f1 100644\n> > --- a/builtin/rebase.c\n> > +++ b/builtin/rebase.c\n> > @@ -455,6 +481,26 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n> >                 usage_with_options(builtin_rebase_usage,\n> >                                    builtin_rebase_options);\n> >\n> > +       /* Make sure no rebase is in progress */\n> \n> The faithful conversion doesn't even stop at the comments. ;-)\n\nYes, I insisted on it.\n\nTBH it is a bit of a shame that we cannot fix all those error messages\ngoing to stdout, but... you know... One step after the other.\n\n> I shortly wondered if this is the best place for this comment,\n> but let's just keep it here to have the 1:1 rewrite.\n\nIt should probably be inside the conditional block, but as you say: the\noriginal had it in a funny spot, and so does the converted code.\n\n> > +       if (in_progress) {\n> [...]\n> > +                   state_dir_base, cmd_live_rebase,buf.buf);\n> \n> In case a resend is needed, add a whitespace after the\n> comma and buf.buf, please.\n\nI will fix this before sending the next iteration.\n\nThanks for the review!\nDscho\n"},{"id":"356476","messageId":"nycvar.QRO.7.76.6.1808241813420.73@tvgsbejvaqbjf.bet","threadId":"49071","inReplyTo":"xmqq600kheb7.fsf@gitster-ct.c.googlers.com","subject":"Re: [PATCH 01/11] builtin rebase: support --onto","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2018-08-24T16:21:12Z","receivedAt":"2018-08-24T16:21:22Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Junio,\n\nOn Wed, 8 Aug 2018, Junio C Hamano wrote:\n\n> Pratik Karki <predatoramigo@gmail.com> writes:\n> \n> > The `--onto` option is important, as it allows to rebase a range of\n> > commits onto a different base commit (which gave the command its odd\n> > name: \"rebase\").\n> \n> Is there anything unimportant?  A rhetorical question, of course.\n\nYou might think it is a rhetorical question, but obviously it is not, as\nyour reaction testifies.\n\nBut certainly there are more important options and less important options!\nThe most important options are those that are frequently used.\n\n> The quite casual and natural use of \"to rebase\" as a verb in the\n> first sentence contradicts with what the parenthetical \"its odd\n> name\" comment says.  Perhaps drop everything after \"(which...\"?\n> \n> i.e.\n> \n> \tThe `--onto` option allows to rebase a range of commits onto\n> \ta different base commit.  Port the support for the option to\n> \tthe C re-implementation.\n\nI'd rather keep it.\n\nRemember, a story is easier to read than a dull academic treatise. I want\nto have a little bit of a personal touch when I stumble over these commit\nmessages again. And I know I will.\n\n> > This commit introduces options parsing so that different options can\n> > be added in future commits.\n> \n> We usually do not say \"This commit does X\", or (worse) \"I do X in\n> this commit\".\n\nOh, don't we now? ;-)\n\n(This *was* a rhetorical question, as *I* use this tense all the time, and\nunless you have quietly rewritten my commit messages without my knowledge\nnor consent, the Git commit history is full of these instances.)\n\n> Instead, order the codebase to be like so, e.g.  \"Support command line\n> options by adding a call to parse_options(); later commits will add more\n> options by building on top.\" or something like that.\n\nTo be quite frank with you, I hoped for a review that would focus a teeny\ntiny bit on the correctness of the code.\n\nIf you want to continue to nit-pick the commit messages, that's fine, of\ncourse, but do understand that I am not really prepared to change a whole\nlot there, unless you point out outright errors or false statements. Those\nnaturally need fixing.\n\nAlso, please note that I will now *definitely* focus on bug fixes, as I am\nreally eager to get those speed improvements into Git for Windows v2.19.0.\n\nAnd I don't know whether I have said this publicly yet: I will send the\nnext iterations of Pratik's patch series. He is busy with exams (GSoC\nreally caters for US schedules, students who are in countries with very\ndifferent university schedules are a bit out of luck here), and I really\nwant these patches.\n\nCiao,\nDscho\n"},{"id":"356564","messageId":"nycvar.QRO.7.76.6.1808241821470.73@tvgsbejvaqbjf.bet","threadId":"49071","inReplyTo":"xmqq1sb8hdvd.fsf@gitster-ct.c.googlers.com","subject":"Re: [PATCH 02/11] builtin rebase: support `git rebase --onto A...B`","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2018-08-26T18:36:25Z","receivedAt":"2018-08-26T18:36:39Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Junio,\n\nOn Wed, 8 Aug 2018, Junio C Hamano wrote:\n\n> Pratik Karki <predatoramigo@gmail.com> writes:\n> \n> > This commit implements support for an --onto argument that is actually a\n> > \"symmetric range\" i.e. `<rev1>...<rev2>`.\n> >\n> > The equivalent shell script version of the code offers two different\n> > error messages for the cases where there is no merge base vs more than\n> > one merge base. Though following the similar approach would be nice,\n> > this would create more complexity than it is of current. Currently, for\n> \n> Sorry, but it is unclear what you mean by \"than it is of current.\"\n> Do you mean we leave it broken at this step in the series for now\n> for expediency, with the intention to later revisit and fix it, or\n> do you mean something else?\n\nI suggested to drop the distinction, in favor of simpler code. Not for the\ntime being, but for good.\n\nI reworded the commit message thusly:\n\n    builtin rebase: support `git rebase --onto A...B`\n\n    This commit implements support for an --onto argument that is actually a\n    \"symmetric range\" i.e. `<rev1>...<rev2>`.\n\n    The equivalent shell script version of the code offers two different\n    error messages for the cases where there is no merge base vs more than\n    one merge base.\n\n    Though it would be nice to retain this distinction, dropping it makes it\n    possible to simply use the `get_oid_mb()` function. Besides, it happens\n    rarely in real-world scenarios.\n\n    Therefore, in the interest of keeping the code less complex, let's just\n    use that function, and live with an error message that does not\n    distinguish between those two error conditions.\n\n> > @@ -387,7 +389,11 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n> >  \tif (!options.onto_name)\n> >  \t\toptions.onto_name = options.upstream_name;\n> >  \tif (strstr(options.onto_name, \"...\")) {\n> > -\t\tdie(\"TODO\");\n> > +\t\tif (get_oid_mb(options.onto_name, &merge_base) < 0)\n> > +\t\t\tdie(_(\"'%s': need exactly one merge base\"),\n> > +\t\t\t    options.onto_name);\n> > +\t\toptions.onto = lookup_commit_or_die(&merge_base,\n> > +\t\t\t\t\t\t    options.onto_name);\n> \n> The original is slightly sloppy in that it will misparse\n> \n> \trebase --onto 'master^{/log ... message}'\n> \n> and this shares the same, which I think is probably OK.\n\nI did run into this recently, but not with an `--onto` option. I forgot\nthe details (I meant to write it down, and forgot that, too).\n\nSorry for musing, back on the topic. Yes, it shares the same, and *that*\nmakes it okay. Remember: this patch series is not about improving `git\nrebase` at all. It is about converting from shell script to builtin.\n\n> When this actually becomes problematic, the original can easily be\n> salvaged by making it to fall back to the same peel_committish in its\n> else clause; I am not sure if this C rewrite is as easily be fixed the\n> same way, though.\n\nI will make a note so that I hopefully won't forget.\n\nThanks,\nDscho\n\n> \n> >  \t} else {\n> >  \t\toptions.onto = peel_committish(options.onto_name);\n> >  \t\tif (!options.onto)\n> \n"},{"id":"356572","messageId":"nycvar.QRO.7.76.6.1808271412140.73@tvgsbejvaqbjf.bet","threadId":"49071","inReplyTo":"xmqqwot0fydp.fsf@gitster-ct.c.googlers.com","subject":"Re: [PATCH 03/11] builtin rebase: handle the pre-rebase hook (and add --no-verify)","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2018-08-27T12:15:40Z","receivedAt":"2018-08-27T12:15:51Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Junio,\n\nOn Wed, 8 Aug 2018, Junio C Hamano wrote:\n\n> Pratik Karki <predatoramigo@gmail.com> writes:\n> \n> > This commit converts the equivalent part of the shell script\n> > `git-legacy-rebase.sh` to run the pre-rebase hook (unless disabled), and\n> > to interrupt the rebase with error if the hook fails.\n> >\n> > Signed-off-by: Pratik Karki <predatoramigo@gmail.com>\n> > ---\n> \n> Introduction of upstream_arg in this step looked a bit\n> surprising, but the hook invocation is the only thing that uses it,\n> so it is understandable.\n\nYep, that's literally all that `upstream_arg` is used for:\n\n$ git grep upstream_arg v2.19.0-rc0\nv2.19.0-rc0:git-rebase.sh:      upstream_arg=\"$upstream_name\"\nv2.19.0-rc0:git-rebase.sh:      upstream_arg=--root\nv2.19.0-rc0:git-rebase.sh:run_pre_rebase_hook \"$upstream_arg\" \"$@\"\n\n> \"rebase: handle the re-rebase hook and --no-verify\" would have been\n> sufficient, without \"add\" or parentheses.\n\nFixed.\n\n> > diff --git a/builtin/rebase.c b/builtin/rebase.c\n> > index 38c496dd10..b79f9b0a9f 100644\n> > --- a/builtin/rebase.c\n> > +++ b/builtin/rebase.c\n> > @@ -317,6 +319,8 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n> >  \t\tOPT_STRING(0, \"onto\", &options.onto_name,\n> >  \t\t\t   N_(\"revision\"),\n> >  \t\t\t   N_(\"rebase onto given branch instead of upstream\")),\n> > +\t\tOPT_BOOL(0, \"no-verify\", &ok_to_skip_pre_rebase,\n> > +\t\t\t N_(\"allow pre-rebase hook to run\")),\n> \n> Do we need to catch \"--no-no-verify\" ourselves with NONEG bit, or is\n> this sufficient to tell parse_options() machinery to take care of\n> it?\n\nI just issued\n\n\t$ ./git rebase --verify --no-no-verify --xyz\n\nand it showed\n\n\terror: unknown option `xyz'\n\t[... usage ...]\n\nI vaguely remembered that the parse_options() machinery special-cases\n\"no-\" prefixes, and my test seems to confirm it.\n\nHoller if you want a more in-depth analysis.\n\nCiao,\nDscho\n"},{"id":"356573","messageId":"nycvar.QRO.7.76.6.1808271416410.73@tvgsbejvaqbjf.bet","threadId":"49071","inReplyTo":"xmqqsh3ofy4f.fsf@gitster-ct.c.googlers.com","subject":"Re: [PATCH 04/11] builtin rebase: support --quiet","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2018-08-27T12:31:04Z","receivedAt":"2018-08-27T12:31:15Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Junio,\n\nOn Wed, 8 Aug 2018, Junio C Hamano wrote:\n\n> Stefan Beller <sbeller@google.com> writes:\n> \n> > On Wed, Aug 8, 2018 at 6:51 AM Pratik Karki <predatoramigo@gmail.com> wrote:\n> >>\n> >> This commit introduces a rebase option `--quiet`. While `--quiet` is\n> >> commonly perceived as opposite to `--verbose`, this is not the case for\n> >> the rebase command: both `--quiet` and `--verbose` default to `false` if\n> >> neither `--quiet` nor `--verbose` is present.\n> >>\n> >> This commit goes further and introduces `--no-quiet` which is the\n> >> contrary of `--quiet` and it's introduction doesn't modify any\n> >> behaviour.\n> \n> Why?  Is it for completeness (i.e. does the scripted version take\n> such an option and addition of --no-quiet makes the C rewrite behave\n> the same)?\n\nAh. I mentioned that an explanation for this is needed in the commit\nmessage, and I guess that it is a bit too subtle. The part you clipped\nfrom your quoted text says:\n\n\t[... `--quiet`] switches off --verbose and --stat, and as\n\t--verbose switches off --quiet, we use the (negated)\n\tREBASE_NO_QUIET instead of REBASE_QUIET: this allows us to turn\n\toff the quiet mode and turn on the verbose and diffstat mode in a\n\tsingle OPT_BIT(), and the opposite in a single OPT_NEGBIT().\n\nI agree that this is a pretty convoluted way to express the issue. See\nbelow for an attempt at a clearer commit message.\n\n> >> Note: The `flags` field in `rebase_options` will accumulate more bits in\n> >> subsequent commits, in particular a verbose and a diffstat flag. And as\n> >> --quoet inthe shell scripted version of the rebase command switches off\n> >\n> >   --quote in the\n> >\n> > (in case a resend is needed)\n> \n> Meaning --quiet?\n\nYep. I should have paid more attention in my pre-submission review, sorry.\n\nI changed the commit message to read like this:\n\n\tbuiltin rebase: support --quiet\n\n\tThis commit introduces a rebase option `--quiet`. While `--quiet` is\n\tcommonly perceived as opposite to `--verbose`, this is not the case for\n\tthe rebase command: both `--quiet` and `--verbose` default to `false` if\n\tneither `--quiet` nor `--verbose` is present.\n\n\tDespite the default being `false` for both verbose and quiet mode,\n\tpassing the `--quiet` option will turn off verbose mode, and `--verbose`\n\twill turn off quiet mode.\n\n\tThis patch introduces the `flags` bit field, with `REBASE_NO_QUIET`\n\tas first user (with many more to come).\n\n\tWe do *not* use `REBASE_QUIET` here for an important reason: To keep the\n\timplementation simple, this commit introduces `--no-quiet` instead of\n\t`--quiet`, so that a single `OPT_NEGBIT()` can turn on quiet mode and\n\tturn off verbose and diffstat mode at the same time. Likewise, the\n\tcompanion commit which will introduce support for `--verbose` will have\n\ta single `OPT_BIT()` that turns off quiet mode and turns on verbose and\n\tdiffstat mode at the same time.\n\nCiao,\nDscho\n"},{"id":"357352","messageId":"pull.32.v2.git.gitgitgadget@gmail.com","threadId":"49071","inReplyTo":"20180808134830.19949-1-predatoramigo@gmail.com","subject":"[PATCH v2 00/11] A minimal builtin rebase","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2018-09-04T21:27:06Z","receivedAt":"2018-09-04T21:27:10Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"This patch series provides the bare minimum to run more than just the\ntrivial rebase (i.e. git rebase <upstream>): it implements the most common\noptions such as --onto.\n\nIt is based the latest iteration of pk/rebase-in-c.\n\nThis is the second patch series that brings us more closer to a builtin \"git\nrebase\".\n\nChanges since v1:\n\n * Many commit messages were reworded.\n * An indentation fix was folded into the commit that introduces the\n   incorrect indentation.\n * A missing space after a comma was inserted.\n\nPratik Karki (11):\n  builtin rebase: support --onto\n  builtin rebase: support `git rebase --onto A...B`\n  builtin rebase: handle the pre-rebase hook and --no-verify\n  builtin rebase: support --quiet\n  builtin rebase: support the `verbose` and `diffstat` options\n  builtin rebase: require a clean worktree\n  builtin rebase: try to fast forward when possible\n  builtin rebase: support --force-rebase\n  builtin rebase: start a new rebase only if none is in progress\n  builtin rebase: only store fully-qualified refs in `options.head_name`\n  builtin rebase: support `git rebase <upstream> <switch-to>`\n\n builtin/rebase.c | 333 +++++++++++++++++++++++++++++++++++++++++++++--\n 1 file changed, 320 insertions(+), 13 deletions(-)\n\n\nbase-commit: ac7f467fef8b836084afdce5eded047c79a6858d\nPublished-As: https://github.com/gitgitgadget/git/releases/tags/pr-32%2Fdscho%2Frebase-in-c-2-basic-v2\nFetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-32/dscho/rebase-in-c-2-basic-v2\nPull-Request: https://github.com/gitgitgadget/git/pull/32\n\nRange-diff vs v1:\n\n  1:  c5f67c35ea !  1:  fba1b3e2a9 builtin rebase: support --onto\n     @@ -15,6 +15,7 @@\n          command name, but to the first (non-option) command-line parameter.\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:  35d141c32a !  2:  f9826ab58f builtin rebase: support `git rebase --onto A...B`\n     @@ -7,12 +7,18 @@\n      \n          The equivalent shell script version of the code offers two different\n          error messages for the cases where there is no merge base vs more than\n     -    one merge base. Though following the similar approach would be nice,\n     -    this would create more complexity than it is of current. Currently, for\n     -    simple convenience, the `get_oid_mb()` function is used whose return\n     -    value does not discern between those two error conditions.\n     +    one merge base.\n     +\n     +    Though it would be nice to retain this distinction, dropping it makes it\n     +    possible to simply use the `get_oid_mb()` function. Besides, it happens\n     +    rarely in real-world scenarios.\n     +\n     +    Therefore, in the interest of keeping the code less complex, let's just\n     +    use that function, and live with an error message that does not\n     +    distinguish between those two error conditions.\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:  e223f2209d !  3:  7100820def builtin rebase: handle the pre-rebase hook (and add --no-verify)\n     @@ -1,12 +1,13 @@\n      Author: Pratik Karki <predatoramigo@gmail.com>\n      \n     -    builtin rebase: handle the pre-rebase hook (and add --no-verify)\n     +    builtin rebase: handle the pre-rebase hook and --no-verify\n      \n          This commit converts the equivalent part of the shell script\n          `git-legacy-rebase.sh` to run the pre-rebase hook (unless disabled), and\n          to interrupt the rebase with error if the hook fails.\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:  19919e7e24 !  4:  5034f53024 builtin rebase: support --quiet\n     @@ -7,19 +7,23 @@\n          the rebase command: both `--quiet` and `--verbose` default to `false` if\n          neither `--quiet` nor `--verbose` is present.\n      \n     -    This commit goes further and introduces `--no-quiet` which is the\n     -    contrary of `--quiet` and it's introduction doesn't modify any\n     -    behaviour.\n     +    Despite the default being `false` for both verbose and quiet mode,\n     +    passing the `--quiet` option will turn off verbose mode, and `--verbose`\n     +    will turn off quiet mode.\n      \n     -    Note: The `flags` field in `rebase_options` will accumulate more bits in\n     -    subsequent commits, in particular a verbose and a diffstat flag. And as\n     -    --quoet inthe shell scripted version of the rebase command switches off\n     -    --verbose and --stat, and as --verbose switches off --quiet, we use the\n     -    (negated) REBASE_NO_QUIET instead of REBASE_QUIET: this allows us to\n     -    turn off the quiet mode and turn on the verbose and diffstat mode in a\n     -    single OPT_BIT(), and the opposite in a single OPT_NEGBIT().\n     +    This patch introduces the `flags` bit field, with `REBASE_NO_QUIET`\n     +    as first user (with many more to come).\n     +\n     +    We do *not* use `REBASE_QUIET` here for an important reason: To keep the\n     +    implementation simple, this commit introduces `--no-quiet` instead of\n     +    `--quiet`, so that a single `OPT_NEGBIT()` can turn on quiet mode and\n     +    turn off verbose and diffstat mode at the same time. Likewise, the\n     +    companion commit which will introduce support for `--verbose` will have\n     +    a single `OPT_BIT()` that turns off quiet mode and turns on verbose and\n     +    diffstat mode at the same time.\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:  cbf318d0de !  5:  ce1e1f266a builtin rebase: support the `verbose` and `diffstat` options\n     @@ -11,6 +11,7 @@\n          calling) 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  6:  b440bf9884 !  6:  f11f21d5c6 builtin rebase: require a clean worktree\n     @@ -6,6 +6,7 @@\n          whether the repository is ready for 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  7:  0efe9b41f0 !  7:  2ec0b744bf builtin rebase: try to fast forward when possible\n     @@ -11,6 +11,7 @@\n          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     @@ -105,7 +106,7 @@\n      +\t\tif (!(options.flags & REBASE_NO_QUIET))\n      +\t\t\t; /* be quiet */\n      +\t\telse if (!strcmp(branch_name, \"HEAD\") &&\n     -+\t\t\tresolve_ref_unsafe(\"HEAD\", 0, NULL, &flag))\n     ++\t\t\t resolve_ref_unsafe(\"HEAD\", 0, NULL, &flag))\n      +\t\t\tputs(_(\"HEAD is up to date, rebase forced.\"));\n      +\t\telse\n      +\t\t\tprintf(_(\"Current branch %s is up to date, rebase \"\n  8:  ae019dec3f !  8:  78d90e67de builtin rebase: support --force-rebase\n     @@ -10,6 +10,7 @@\n          fast-forward even if it could.\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     @@ -63,8 +64,4 @@\n      +\t\t} else if (!(options.flags & REBASE_NO_QUIET))\n       \t\t\t; /* be quiet */\n       \t\telse if (!strcmp(branch_name, \"HEAD\") &&\n     --\t\t\tresolve_ref_unsafe(\"HEAD\", 0, NULL, &flag))\n     -+\t\t\t resolve_ref_unsafe(\"HEAD\", 0, NULL, &flag))\n     - \t\t\tputs(_(\"HEAD is up to date, rebase forced.\"));\n     - \t\telse\n     - \t\t\tprintf(_(\"Current branch %s is up to date, rebase \"\n     + \t\t\t resolve_ref_unsafe(\"HEAD\", 0, NULL, &flag))\n  9:  d58d504c03 !  9:  b639bfa5a8 builtin rebase: start a new rebase only if none is in progress\n     @@ -7,6 +7,7 @@\n          ongoing rebase operation completes or is terminated.\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     @@ -84,7 +85,7 @@\n      +\t\t      \"and run me again.  I am stopping in case you still \"\n      +\t\t      \"have something\\n\"\n      +\t\t      \"valuable there.\\n\"),\n     -+\t\t    state_dir_base, cmd_live_rebase,buf.buf);\n     ++\t\t    state_dir_base, cmd_live_rebase, buf.buf);\n      +\t}\n      +\n       \tif (!(options.flags & REBASE_NO_QUIET))\n 10:  ef468bf3d7 ! 10:  aab01f0b8e builtin rebase: only store fully-qualified refs in `options.head_name`\n     @@ -12,6 +12,7 @@\n          \"detached HEAD\" for display only. Make it so.\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:  9a26fc3fac ! 11:  e64190d8ed builtin rebase: support `git rebase <upstream> <switch-to>`\n     @@ -7,6 +7,7 @@\n          `git-legacy-rebase.sh` is converted to builtin `rebase.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":"357353","messageId":"fba1b3e2a91a85e68ccfcca8ad0a84c7758936a3.1536096424.git.gitgitgadget@gmail.com","threadId":"49071","inReplyTo":"pull.32.v2.git.gitgitgadget@gmail.com","subject":"[PATCH v2 01/11] builtin rebase: support --onto","fromName":"Pratik Karki via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2018-09-04T21:27:07Z","receivedAt":"2018-09-04T21:27: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\nThe `--onto` option is important, as it allows to rebase a range of\ncommits onto a different base commit (which gave the command its odd\nname: \"rebase\").\n\nThis commit introduces options parsing so that different options can\nbe added in future commits.\n\nNote: As this commit introduces to the parse_options() call (which\n\"eats\" argv[0]), the argc is now expected to be lower by one after this\npatch, compared to before this patch: argv[0] no longer refers to the\ncommand name, but to the first (non-option) command-line parameter.\n\nSigned-off-by: Pratik Karki <predatoramigo@gmail.com>\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n builtin/rebase.c | 35 ++++++++++++++++++++++++++++++-----\n 1 file changed, 30 insertions(+), 5 deletions(-)\n\ndiff --git a/builtin/rebase.c b/builtin/rebase.c\nindex e695d8a430..742ed31498 100644\n--- a/builtin/rebase.c\n+++ b/builtin/rebase.c\n@@ -16,6 +16,16 @@\n #include \"cache-tree.h\"\n #include \"unpack-trees.h\"\n #include \"lockfile.h\"\n+#include \"parse-options.h\"\n+\n+static char const * const builtin_rebase_usage[] = {\n+\tN_(\"git rebase [-i] [options] [--exec <cmd>] [--onto <newbase>] \"\n+\t\t\"[<upstream>] [<branch>]\"),\n+\tN_(\"git rebase [-i] [options] [--exec <cmd>] [--onto <newbase>] \"\n+\t\t\"--root [<branch>]\"),\n+\tN_(\"git rebase --continue | --abort | --skip | --edit-todo\"),\n+\tNULL\n+};\n \n static GIT_PATH_FUNC(apply_dir, \"rebase-apply\")\n static GIT_PATH_FUNC(merge_dir, \"rebase-merge\")\n@@ -301,6 +311,12 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \tint ret, flags;\n \tstruct strbuf msg = STRBUF_INIT;\n \tstruct strbuf revisions = STRBUF_INIT;\n+\tstruct option builtin_rebase_options[] = {\n+\t\tOPT_STRING(0, \"onto\", &options.onto_name,\n+\t\t\t   N_(\"revision\"),\n+\t\t\t   N_(\"rebase onto given branch instead of upstream\")),\n+\t\tOPT_END(),\n+\t};\n \n \t/*\n \t * NEEDSWORK: Once the builtin rebase has been tested enough\n@@ -318,13 +334,22 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \t\t\tBUG(\"sane_execvp() returned???\");\n \t}\n \n-\tif (argc != 2)\n-\t\tdie(_(\"Usage: %s <base>\"), argv[0]);\n+\tif (argc == 2 && !strcmp(argv[1], \"-h\"))\n+\t\tusage_with_options(builtin_rebase_usage,\n+\t\t\t\t   builtin_rebase_options);\n+\n \tprefix = setup_git_directory();\n \ttrace_repo_setup(prefix);\n \tsetup_work_tree();\n \n \tgit_config(git_default_config, NULL);\n+\targc = parse_options(argc, argv, prefix,\n+\t\t\t     builtin_rebase_options,\n+\t\t\t     builtin_rebase_usage, 0);\n+\n+\tif (argc > 2)\n+\t\tusage_with_options(builtin_rebase_usage,\n+\t\t\t\t   builtin_rebase_options);\n \n \tswitch (options.type) {\n \tcase REBASE_MERGE:\n@@ -343,10 +368,10 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \t}\n \n \tif (!options.root) {\n-\t\tif (argc < 2)\n+\t\tif (argc < 1)\n \t\t\tdie(\"TODO: handle @{upstream}\");\n \t\telse {\n-\t\t\toptions.upstream_name = argv[1];\n+\t\t\toptions.upstream_name = argv[0];\n \t\t\targc--;\n \t\t\targv++;\n \t\t\tif (!strcmp(options.upstream_name, \"-\"))\n@@ -377,7 +402,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \t * orig_head -- commit object name of tip of the branch before rebasing\n \t * head_name -- refs/heads/<that-branch> or \"detached HEAD\"\n \t */\n-\tif (argc > 1)\n+\tif (argc > 0)\n \t\t die(\"TODO: handle switch_to\");\n \telse {\n \t\t/* Do not need to switch branches, we are already on it. */\n-- \ngitgitgadget\n\n"},{"id":"357354","messageId":"f9826ab58f73d4ebca4d69134f4f75b5831bbd74.1536096424.git.gitgitgadget@gmail.com","threadId":"49071","inReplyTo":"pull.32.v2.git.gitgitgadget@gmail.com","subject":"[PATCH v2 02/11] builtin rebase: support `git rebase --onto A...B`","fromName":"Pratik Karki via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2018-09-04T21:27:09Z","receivedAt":"2018-09-04T21:27: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\nThis commit implements support for an --onto argument that is actually a\n\"symmetric range\" i.e. `<rev1>...<rev2>`.\n\nThe equivalent shell script version of the code offers two different\nerror messages for the cases where there is no merge base vs more than\none merge base.\n\nThough it would be nice to retain this distinction, dropping it makes it\npossible to simply use the `get_oid_mb()` function. Besides, it happens\nrarely in real-world scenarios.\n\nTherefore, in the interest of keeping the code less complex, let's just\nuse that function, and live with an error message that does not\ndistinguish between those two error conditions.\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, 7 insertions(+), 1 deletion(-)\n\ndiff --git a/builtin/rebase.c b/builtin/rebase.c\nindex 742ed31498..38c496dd10 100644\n--- a/builtin/rebase.c\n+++ b/builtin/rebase.c\n@@ -17,6 +17,7 @@\n #include \"unpack-trees.h\"\n #include \"lockfile.h\"\n #include \"parse-options.h\"\n+#include \"commit.h\"\n \n static char const * const builtin_rebase_usage[] = {\n \tN_(\"git rebase [-i] [options] [--exec <cmd>] [--onto <newbase>] \"\n@@ -311,6 +312,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \tint ret, flags;\n \tstruct strbuf msg = STRBUF_INIT;\n \tstruct strbuf revisions = STRBUF_INIT;\n+\tstruct object_id merge_base;\n \tstruct option builtin_rebase_options[] = {\n \t\tOPT_STRING(0, \"onto\", &options.onto_name,\n \t\t\t   N_(\"revision\"),\n@@ -387,7 +389,11 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \tif (!options.onto_name)\n \t\toptions.onto_name = options.upstream_name;\n \tif (strstr(options.onto_name, \"...\")) {\n-\t\tdie(\"TODO\");\n+\t\tif (get_oid_mb(options.onto_name, &merge_base) < 0)\n+\t\t\tdie(_(\"'%s': need exactly one merge base\"),\n+\t\t\t    options.onto_name);\n+\t\toptions.onto = lookup_commit_or_die(&merge_base,\n+\t\t\t\t\t\t    options.onto_name);\n \t} else {\n \t\toptions.onto = peel_committish(options.onto_name);\n \t\tif (!options.onto)\n-- \ngitgitgadget\n\n"},{"id":"357355","messageId":"7100820def2f2805cf4726e0501ca9208bbaffaa.1536096424.git.gitgitgadget@gmail.com","threadId":"49071","inReplyTo":"pull.32.v2.git.gitgitgadget@gmail.com","subject":"[PATCH v2 03/11] builtin rebase: handle the pre-rebase hook and --no-verify","fromName":"Pratik Karki via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2018-09-04T21:27:10Z","receivedAt":"2018-09-04T21:27: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 converts the equivalent part of the shell script\n`git-legacy-rebase.sh` to run the pre-rebase hook (unless disabled), and\nto interrupt the rebase with error if the hook fails.\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 38c496dd10..b79f9b0a9f 100644\n--- a/builtin/rebase.c\n+++ b/builtin/rebase.c\n@@ -70,6 +70,7 @@ struct rebase_options {\n \tconst char *state_dir;\n \tstruct commit *upstream;\n \tconst char *upstream_name;\n+\tconst char *upstream_arg;\n \tchar *head_name;\n \tstruct object_id orig_head;\n \tstruct commit *onto;\n@@ -310,6 +311,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \t};\n \tconst char *branch_name;\n \tint ret, flags;\n+\tint ok_to_skip_pre_rebase = 0;\n \tstruct strbuf msg = STRBUF_INIT;\n \tstruct strbuf revisions = STRBUF_INIT;\n \tstruct object_id merge_base;\n@@ -317,6 +319,8 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \t\tOPT_STRING(0, \"onto\", &options.onto_name,\n \t\t\t   N_(\"revision\"),\n \t\t\t   N_(\"rebase onto given branch instead of upstream\")),\n+\t\tOPT_BOOL(0, \"no-verify\", &ok_to_skip_pre_rebase,\n+\t\t\t N_(\"allow pre-rebase hook to run\")),\n \t\tOPT_END(),\n \t};\n \n@@ -382,6 +386,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \t\toptions.upstream = peel_committish(options.upstream_name);\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 \n@@ -430,6 +435,12 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \t\t\tdie(_(\"Could not resolve HEAD to a revision\"));\n \t}\n \n+\t/* If a hook exists, give it a chance to interrupt*/\n+\tif (!ok_to_skip_pre_rebase &&\n+\t    run_hook_le(NULL, \"pre-rebase\", options.upstream_arg,\n+\t\t\targc ? argv[0] : NULL, NULL))\n+\t\tdie(_(\"The pre-rebase hook refused to rebase.\"));\n+\n \tstrbuf_addf(&msg, \"rebase: checkout %s\", options.onto_name);\n \tif (reset_head(&options.onto->object.oid, \"checkout\", NULL, 1))\n \t\tdie(_(\"Could not detach HEAD\"));\n-- \ngitgitgadget\n\n"},{"id":"357356","messageId":"5034f5302493ce44fb49ef3d064b5a5a3b67ac7f.1536096424.git.gitgitgadget@gmail.com","threadId":"49071","inReplyTo":"pull.32.v2.git.gitgitgadget@gmail.com","subject":"[PATCH v2 04/11] builtin rebase: support --quiet","fromName":"Pratik Karki via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2018-09-04T21:27:12Z","receivedAt":"2018-09-04T21:27: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\nThis commit introduces a rebase option `--quiet`. While `--quiet` is\ncommonly perceived as opposite to `--verbose`, this is not the case for\nthe rebase command: both `--quiet` and `--verbose` default to `false` if\nneither `--quiet` nor `--verbose` is present.\n\nDespite the default being `false` for both verbose and quiet mode,\npassing the `--quiet` option will turn off verbose mode, and `--verbose`\nwill turn off quiet mode.\n\nThis patch introduces the `flags` bit field, with `REBASE_NO_QUIET`\nas first user (with many more to come).\n\nWe do *not* use `REBASE_QUIET` here for an important reason: To keep the\nimplementation simple, this commit introduces `--no-quiet` instead of\n`--quiet`, so that a single `OPT_NEGBIT()` can turn on quiet mode and\nturn off verbose and diffstat mode at the same time. Likewise, the\ncompanion commit which will introduce support for `--verbose` will have\na single `OPT_BIT()` that turns off quiet mode and turns on verbose and\ndiffstat mode at the same time.\n\nSigned-off-by: Pratik Karki <predatoramigo@gmail.com>\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n builtin/rebase.c | 15 +++++++++++++++\n 1 file changed, 15 insertions(+)\n\ndiff --git a/builtin/rebase.c b/builtin/rebase.c\nindex b79f9b0a9f..19fa4d3fc4 100644\n--- a/builtin/rebase.c\n+++ b/builtin/rebase.c\n@@ -79,6 +79,10 @@ struct rebase_options {\n \tint root;\n \tstruct commit *restrict_revision;\n \tint dont_finish_rebase;\n+\tenum {\n+\t\tREBASE_NO_QUIET = 1<<0,\n+\t} flags;\n+\tstruct strbuf git_am_opt;\n };\n \n /* Returns the filename prefixed by the state_dir */\n@@ -159,6 +163,9 @@ static int run_specific_rebase(struct rebase_options *opts)\n \tadd_var(&script_snippet, \"revisions\", opts->revisions);\n \tadd_var(&script_snippet, \"restrict_revision\", opts->restrict_revision ?\n \t\toid_to_hex(&opts->restrict_revision->object.oid) : NULL);\n+\tadd_var(&script_snippet, \"GIT_QUIET\",\n+\t\topts->flags & REBASE_NO_QUIET ? \"\" : \"t\");\n+\tadd_var(&script_snippet, \"git_am_opt\", opts->git_am_opt.buf);\n \n \tswitch (opts->type) {\n \tcase REBASE_AM:\n@@ -308,6 +315,8 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n {\n \tstruct rebase_options options = {\n \t\t.type = REBASE_UNSPECIFIED,\n+\t\t.flags = REBASE_NO_QUIET,\n+\t\t.git_am_opt = STRBUF_INIT,\n \t};\n \tconst char *branch_name;\n \tint ret, flags;\n@@ -321,6 +330,9 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \t\t\t   N_(\"rebase onto given branch instead of upstream\")),\n \t\tOPT_BOOL(0, \"no-verify\", &ok_to_skip_pre_rebase,\n \t\t\t N_(\"allow pre-rebase hook to run\")),\n+\t\tOPT_NEGBIT('q', \"quiet\", &options.flags,\n+\t\t\t   N_(\"be quiet. implies --no-stat\"),\n+\t\t\t   REBASE_NO_QUIET),\n \t\tOPT_END(),\n \t};\n \n@@ -357,6 +369,9 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \t\tusage_with_options(builtin_rebase_usage,\n \t\t\t\t   builtin_rebase_options);\n \n+\tif (!(options.flags & REBASE_NO_QUIET))\n+\t\tstrbuf_addstr(&options.git_am_opt, \" -q\");\n+\n \tswitch (options.type) {\n \tcase REBASE_MERGE:\n \tcase REBASE_INTERACTIVE:\n-- \ngitgitgadget\n\n"},{"id":"357357","messageId":"ce1e1f266a8ec6c31576dfe871b1482015159af0.1536096424.git.gitgitgadget@gmail.com","threadId":"49071","inReplyTo":"pull.32.v2.git.gitgitgadget@gmail.com","subject":"[PATCH v2 05/11] builtin rebase: support the `verbose` and `diffstat` options","fromName":"Pratik Karki via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2018-09-04T21:27:13Z","receivedAt":"2018-09-04T21:27: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 commit introduces support for the `-v` and `--stat` options of\nrebase.\n\nThe --stat option can also be configured via the Git config setting\nrebase.stat. To support this, we also add a custom rebase_config()\nfunction in this commit that will be used instead of (and falls back to\ncalling) 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 | 60 ++++++++++++++++++++++++++++++++++++++++++++++--\n 1 file changed, 58 insertions(+), 2 deletions(-)\n\ndiff --git a/builtin/rebase.c b/builtin/rebase.c\nindex 19fa4d3fc4..2d3f1d65fb 100644\n--- a/builtin/rebase.c\n+++ b/builtin/rebase.c\n@@ -18,6 +18,7 @@\n #include \"lockfile.h\"\n #include \"parse-options.h\"\n #include \"commit.h\"\n+#include \"diff.h\"\n \n static char const * const builtin_rebase_usage[] = {\n \tN_(\"git rebase [-i] [options] [--exec <cmd>] [--onto <newbase>] \"\n@@ -81,6 +82,8 @@ struct rebase_options {\n \tint dont_finish_rebase;\n \tenum {\n \t\tREBASE_NO_QUIET = 1<<0,\n+\t\tREBASE_VERBOSE = 1<<1,\n+\t\tREBASE_DIFFSTAT = 1<<2,\n \t} flags;\n \tstruct strbuf git_am_opt;\n };\n@@ -166,6 +169,10 @@ static int run_specific_rebase(struct rebase_options *opts)\n \tadd_var(&script_snippet, \"GIT_QUIET\",\n \t\topts->flags & REBASE_NO_QUIET ? \"\" : \"t\");\n \tadd_var(&script_snippet, \"git_am_opt\", opts->git_am_opt.buf);\n+\tadd_var(&script_snippet, \"verbose\",\n+\t\topts->flags & REBASE_VERBOSE ? \"t\" : \"\");\n+\tadd_var(&script_snippet, \"diffstat\",\n+\t\topts->flags & REBASE_DIFFSTAT ? \"t\" : \"\");\n \n \tswitch (opts->type) {\n \tcase REBASE_AM:\n@@ -311,6 +318,21 @@ static int reset_head(struct object_id *oid, const char *action,\n \treturn ret;\n }\n \n+static int rebase_config(const char *var, const char *value, void *data)\n+{\n+\tstruct rebase_options *opts = data;\n+\n+\tif (!strcmp(var, \"rebase.stat\")) {\n+\t\tif (git_config_bool(var, value))\n+\t\t\topts->flags |= REBASE_DIFFSTAT;\n+\t\telse\n+\t\t\topts->flags &= !REBASE_DIFFSTAT;\n+\t\treturn 0;\n+\t}\n+\n+\treturn git_default_config(var, value, data);\n+}\n+\n int cmd_rebase(int argc, const char **argv, const char *prefix)\n {\n \tstruct rebase_options options = {\n@@ -332,7 +354,13 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \t\t\t N_(\"allow pre-rebase hook to run\")),\n \t\tOPT_NEGBIT('q', \"quiet\", &options.flags,\n \t\t\t   N_(\"be quiet. implies --no-stat\"),\n-\t\t\t   REBASE_NO_QUIET),\n+\t\t\t   REBASE_NO_QUIET| REBASE_VERBOSE | REBASE_DIFFSTAT),\n+\t\tOPT_BIT('v', \"verbose\", &options.flags,\n+\t\t\tN_(\"display a diffstat of what changed upstream\"),\n+\t\t\tREBASE_NO_QUIET | REBASE_VERBOSE | REBASE_DIFFSTAT),\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_END(),\n \t};\n \n@@ -360,7 +388,8 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \ttrace_repo_setup(prefix);\n \tsetup_work_tree();\n \n-\tgit_config(git_default_config, NULL);\n+\tgit_config(rebase_config, &options);\n+\n \targc = parse_options(argc, argv, prefix,\n \t\t\t     builtin_rebase_options,\n \t\t\t     builtin_rebase_usage, 0);\n@@ -456,6 +485,33 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \t\t\targc ? argv[0] : NULL, NULL))\n \t\tdie(_(\"The pre-rebase hook refused to rebase.\"));\n \n+\tif (options.flags & REBASE_DIFFSTAT) {\n+\t\tstruct diff_options opts;\n+\n+\t\tif (options.flags & REBASE_VERBOSE)\n+\t\t\tprintf(_(\"Changes from %s to %s:\\n\"),\n+\t\t\t\toid_to_hex(&merge_base),\n+\t\t\t\toid_to_hex(&options.onto->object.oid));\n+\n+\t\t/* We want color (if set), but no pager */\n+\t\tdiff_setup(&opts);\n+\t\topts.stat_width = -1; /* use full terminal width */\n+\t\topts.stat_graph_width = -1; /* respect statGraphWidth config */\n+\t\topts.output_format |=\n+\t\t\tDIFF_FORMAT_SUMMARY | DIFF_FORMAT_DIFFSTAT;\n+\t\topts.detect_rename = DIFF_DETECT_RENAME;\n+\t\tdiff_setup_done(&opts);\n+\t\tdiff_tree_oid(&merge_base, &options.onto->object.oid,\n+\t\t\t      \"\", &opts);\n+\t\tdiffcore_std(&opts);\n+\t\tdiff_flush(&opts);\n+\t}\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+\t\t\t \"it...\\n\"));\n+\n \tstrbuf_addf(&msg, \"rebase: checkout %s\", options.onto_name);\n \tif (reset_head(&options.onto->object.oid, \"checkout\", NULL, 1))\n \t\tdie(_(\"Could not detach HEAD\"));\n-- \ngitgitgadget\n\n"},{"id":"357358","messageId":"f11f21d5c68e66c15e8845cdde09a0c70c98d2e0.1536096424.git.gitgitgadget@gmail.com","threadId":"49071","inReplyTo":"pull.32.v2.git.gitgitgadget@gmail.com","subject":"[PATCH v2 06/11] builtin rebase: require a clean worktree","fromName":"Pratik Karki via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2018-09-04T21:27:14Z","receivedAt":"2018-09-04T21:27:17Z","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 reads the index of the repository for rebase and checks\nwhether the repository is ready for rebase.\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 2d3f1d65fb..afef0b0046 100644\n--- a/builtin/rebase.c\n+++ b/builtin/rebase.c\n@@ -19,6 +19,7 @@\n #include \"parse-options.h\"\n #include \"commit.h\"\n #include \"diff.h\"\n+#include \"wt-status.h\"\n \n static char const * const builtin_rebase_usage[] = {\n \tN_(\"git rebase [-i] [options] [--exec <cmd>] [--onto <newbase>] \"\n@@ -479,6 +480,15 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \t\t\tdie(_(\"Could not resolve HEAD to a revision\"));\n \t}\n \n+\tif (read_index(the_repository->index) < 0)\n+\t\tdie(_(\"could not read index\"));\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+\t\tgoto cleanup;\n+\t}\n+\n \t/* If a hook exists, give it a chance to interrupt*/\n \tif (!ok_to_skip_pre_rebase &&\n \t    run_hook_le(NULL, \"pre-rebase\", options.upstream_arg,\n@@ -528,6 +538,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \n \tret = !!run_specific_rebase(&options);\n \n+cleanup:\n \tstrbuf_release(&revisions);\n \tfree(options.head_name);\n \treturn ret;\n-- \ngitgitgadget\n\n"},{"id":"357360","messageId":"2ec0b744bf13b5991fb4205e7d665f807668de4f.1536096424.git.gitgitgadget@gmail.com","threadId":"49071","inReplyTo":"pull.32.v2.git.gitgitgadget@gmail.com","subject":"[PATCH v2 07/11] builtin rebase: try to fast forward when possible","fromName":"Pratik Karki via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2018-09-04T21:27:16Z","receivedAt":"2018-09-04T21:27:19Z","isPatch":true,"sender":{"key":"predatoramigo@gmail.com","avatar":"https://avatars.githubusercontent.com/u/12194950?v=4"},"body":"From: Pratik Karki <predatoramigo@gmail.com>\n\nIn this commit, we add support to fast forward.\n\nNote: we will need the merge base later, therefore the call to\ncan_fast_forward() really needs to be the first one when testing whether\nwe can skip the rebase entirely (otherwise, it would make more sense to\nskip the possibly expensive operation if, say, running an interactive\nrebase).\n\nSigned-off-by: Pratik Karki <predatoramigo@gmail.com>\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n builtin/rebase.c | 72 ++++++++++++++++++++++++++++++++++++++++++++++++\n 1 file changed, 72 insertions(+)\n\ndiff --git a/builtin/rebase.c b/builtin/rebase.c\nindex afef0b0046..d67df28efc 100644\n--- a/builtin/rebase.c\n+++ b/builtin/rebase.c\n@@ -20,6 +20,7 @@\n #include \"commit.h\"\n #include \"diff.h\"\n #include \"wt-status.h\"\n+#include \"revision.h\"\n \n static char const * const builtin_rebase_usage[] = {\n \tN_(\"git rebase [-i] [options] [--exec <cmd>] [--onto <newbase>] \"\n@@ -89,6 +90,12 @@ struct rebase_options {\n \tstruct strbuf git_am_opt;\n };\n \n+static int is_interactive(struct rebase_options *opts)\n+{\n+\treturn opts->type == REBASE_INTERACTIVE ||\n+\t\topts->type == REBASE_PRESERVE_MERGES;\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@@ -334,6 +341,46 @@ static int rebase_config(const char *var, const char *value, void *data)\n \treturn git_default_config(var, value, data);\n }\n \n+/*\n+ * Determines whether the commits in from..to are linear, i.e. contain\n+ * no merge commits. This function *expects* `from` to be an ancestor of\n+ * `to`.\n+ */\n+static int is_linear_history(struct commit *from, struct commit *to)\n+{\n+\twhile (to && to != from) {\n+\t\tparse_commit(to);\n+\t\tif (!to->parents)\n+\t\t\treturn 1;\n+\t\tif (to->parents->next)\n+\t\t\treturn 0;\n+\t\tto = to->parents->item;\n+\t}\n+\treturn 1;\n+}\n+\n+static int can_fast_forward(struct commit *onto, struct object_id *head_oid,\n+\t\t\t    struct object_id *merge_base)\n+{\n+\tstruct commit *head = lookup_commit(the_repository, head_oid);\n+\tstruct commit_list *merge_bases;\n+\tint res;\n+\n+\tif (!head)\n+\t\treturn 0;\n+\n+\tmerge_bases = get_merge_bases(onto, head);\n+\tif (merge_bases && !merge_bases->next) {\n+\t\toidcpy(merge_base, &merge_bases->item->object.oid);\n+\t\tres = !oidcmp(merge_base, &onto->object.oid);\n+\t} else {\n+\t\toidcpy(merge_base, &null_oid);\n+\t\tres = 0;\n+\t}\n+\tfree_commit_list(merge_bases);\n+\treturn res && is_linear_history(onto, head);\n+}\n+\n int cmd_rebase(int argc, const char **argv, const char *prefix)\n {\n \tstruct rebase_options options = {\n@@ -489,6 +536,31 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \t\tgoto cleanup;\n \t}\n \n+\t/*\n+\t * Now we are rebasing commits upstream..orig_head (or with --root,\n+\t * everything leading up to orig_head) on top of onto.\n+\t */\n+\n+\t/*\n+\t * Check if we are already based on onto with linear history,\n+\t * but this should be done only when upstream and onto are the same\n+\t * and if this is not an interactive rebase.\n+\t */\n+\tif (can_fast_forward(options.onto, &options.orig_head, &merge_base) &&\n+\t    !is_interactive(&options) && !options.restrict_revision &&\n+\t    !oidcmp(&options.upstream->object.oid, &options.onto->object.oid)) {\n+\t\tint flag;\n+\n+\t\tif (!(options.flags & REBASE_NO_QUIET))\n+\t\t\t; /* be quiet */\n+\t\telse if (!strcmp(branch_name, \"HEAD\") &&\n+\t\t\t resolve_ref_unsafe(\"HEAD\", 0, NULL, &flag))\n+\t\t\tputs(_(\"HEAD is up to date, rebase forced.\"));\n+\t\telse\n+\t\t\tprintf(_(\"Current branch %s is up to date, rebase \"\n+\t\t\t\t \"forced.\\n\"), branch_name);\n+\t}\n+\n \t/* If a hook exists, give it a chance to interrupt*/\n \tif (!ok_to_skip_pre_rebase &&\n \t    run_hook_le(NULL, \"pre-rebase\", options.upstream_arg,\n-- \ngitgitgadget\n\n"},{"id":"357359","messageId":"78d90e67de746bdf7269a1bf500852ed924eed87.1536096424.git.gitgitgadget@gmail.com","threadId":"49071","inReplyTo":"pull.32.v2.git.gitgitgadget@gmail.com","subject":"[PATCH v2 08/11] builtin rebase: support --force-rebase","fromName":"Pratik Karki via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2018-09-04T21:27:17Z","receivedAt":"2018-09-04T21:27:20Z","isPatch":true,"sender":{"key":"predatoramigo@gmail.com","avatar":"https://avatars.githubusercontent.com/u/12194950?v=4"},"body":"From: Pratik Karki <predatoramigo@gmail.com>\n\nIn this commit, we add support to `--force-rebase` option. The\nequivalent part of the shell script found in `git-legacy-rebase.sh` is\nconverted as faithfully as possible to C.\n\nThe --force-rebase option ensures that the rebase does not simply\nfast-forward even if it could.\n\nSigned-off-by: Pratik Karki <predatoramigo@gmail.com>\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n builtin/rebase.c | 22 +++++++++++++++++++++-\n 1 file changed, 21 insertions(+), 1 deletion(-)\n\ndiff --git a/builtin/rebase.c b/builtin/rebase.c\nindex d67df28efc..8a7bf3d468 100644\n--- a/builtin/rebase.c\n+++ b/builtin/rebase.c\n@@ -86,6 +86,7 @@ struct rebase_options {\n \t\tREBASE_NO_QUIET = 1<<0,\n \t\tREBASE_VERBOSE = 1<<1,\n \t\tREBASE_DIFFSTAT = 1<<2,\n+\t\tREBASE_FORCE = 1<<3,\n \t} flags;\n \tstruct strbuf git_am_opt;\n };\n@@ -181,6 +182,8 @@ static int run_specific_rebase(struct rebase_options *opts)\n \t\topts->flags & REBASE_VERBOSE ? \"t\" : \"\");\n \tadd_var(&script_snippet, \"diffstat\",\n \t\topts->flags & REBASE_DIFFSTAT ? \"t\" : \"\");\n+\tadd_var(&script_snippet, \"force_rebase\",\n+\t\topts->flags & REBASE_FORCE ? \"t\" : \"\");\n \n \tswitch (opts->type) {\n \tcase REBASE_AM:\n@@ -409,6 +412,12 @@ 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_BIT('f', \"force-rebase\", &options.flags,\n+\t\t\tN_(\"cherry-pick all commits, even if unchanged\"),\n+\t\t\tREBASE_FORCE),\n+\t\tOPT_BIT(0, \"no-ff\", &options.flags,\n+\t\t\tN_(\"cherry-pick all commits, even if unchanged\"),\n+\t\t\tREBASE_FORCE),\n \t\tOPT_END(),\n \t};\n \n@@ -551,7 +560,18 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \t    !oidcmp(&options.upstream->object.oid, &options.onto->object.oid)) {\n \t\tint flag;\n \n-\t\tif (!(options.flags & REBASE_NO_QUIET))\n+\t\tif (!(options.flags & REBASE_FORCE)) {\n+\t\t\tif (!(options.flags & REBASE_NO_QUIET))\n+\t\t\t\t; /* be quiet */\n+\t\t\telse if (!strcmp(branch_name, \"HEAD\") &&\n+\t\t\t\t resolve_ref_unsafe(\"HEAD\", 0, NULL, &flag))\n+\t\t\t\tputs(_(\"HEAD is up to date.\"));\n+\t\t\telse\n+\t\t\t\tprintf(_(\"Current branch %s is up to date.\\n\"),\n+\t\t\t\t       branch_name);\n+\t\t\tret = !!finish_rebase(&options);\n+\t\t\tgoto cleanup;\n+\t\t} else if (!(options.flags & REBASE_NO_QUIET))\n \t\t\t; /* be quiet */\n \t\telse if (!strcmp(branch_name, \"HEAD\") &&\n \t\t\t resolve_ref_unsafe(\"HEAD\", 0, NULL, &flag))\n-- \ngitgitgadget\n\n"},{"id":"357361","messageId":"b639bfa5a828ed15fc960450dd813136408b5c70.1536096424.git.gitgitgadget@gmail.com","threadId":"49071","inReplyTo":"pull.32.v2.git.gitgitgadget@gmail.com","subject":"[PATCH v2 09/11] builtin rebase: start a new rebase only if none is in progress","fromName":"Pratik Karki via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2018-09-04T21:27:18Z","receivedAt":"2018-09-04T21:27:21Z","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 run a new rebase, there needs to be a check to assure that no other\nrebase is in progress. New rebase operation cannot start until an\nongoing rebase operation completes or is terminated.\n\nSigned-off-by: Pratik Karki <predatoramigo@gmail.com>\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n builtin/rebase.c | 48 +++++++++++++++++++++++++++++++++++++++++++++++-\n 1 file changed, 47 insertions(+), 1 deletion(-)\n\ndiff --git a/builtin/rebase.c b/builtin/rebase.c\nindex 8a7bf3d468..d45f8f9008 100644\n--- a/builtin/rebase.c\n+++ b/builtin/rebase.c\n@@ -87,6 +87,7 @@ struct rebase_options {\n \t\tREBASE_VERBOSE = 1<<1,\n \t\tREBASE_DIFFSTAT = 1<<2,\n \t\tREBASE_FORCE = 1<<3,\n+\t\tREBASE_INTERACTIVE_EXPLICIT = 1<<4,\n \t} flags;\n \tstruct strbuf git_am_opt;\n };\n@@ -392,10 +393,11 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \t\t.git_am_opt = STRBUF_INIT,\n \t};\n \tconst char *branch_name;\n-\tint ret, flags;\n+\tint ret, flags, in_progress = 0;\n \tint ok_to_skip_pre_rebase = 0;\n \tstruct strbuf msg = STRBUF_INIT;\n \tstruct strbuf revisions = STRBUF_INIT;\n+\tstruct strbuf buf = STRBUF_INIT;\n \tstruct object_id merge_base;\n \tstruct option builtin_rebase_options[] = {\n \t\tOPT_STRING(0, \"onto\", &options.onto_name,\n@@ -447,6 +449,30 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \n \tgit_config(rebase_config, &options);\n \n+\tif (is_directory(apply_dir())) {\n+\t\toptions.type = REBASE_AM;\n+\t\toptions.state_dir = apply_dir();\n+\t} else if (is_directory(merge_dir())) {\n+\t\tstrbuf_reset(&buf);\n+\t\tstrbuf_addf(&buf, \"%s/rewritten\", merge_dir());\n+\t\tif (is_directory(buf.buf)) {\n+\t\t\toptions.type = REBASE_PRESERVE_MERGES;\n+\t\t\toptions.flags |= REBASE_INTERACTIVE_EXPLICIT;\n+\t\t} else {\n+\t\t\tstrbuf_reset(&buf);\n+\t\t\tstrbuf_addf(&buf, \"%s/interactive\", merge_dir());\n+\t\t\tif(file_exists(buf.buf)) {\n+\t\t\t\toptions.type = REBASE_INTERACTIVE;\n+\t\t\t\toptions.flags |= REBASE_INTERACTIVE_EXPLICIT;\n+\t\t\t} else\n+\t\t\t\toptions.type = REBASE_MERGE;\n+\t\t}\n+\t\toptions.state_dir = merge_dir();\n+\t}\n+\n+\tif (options.type != REBASE_UNSPECIFIED)\n+\t\tin_progress = 1;\n+\n \targc = parse_options(argc, argv, prefix,\n \t\t\t     builtin_rebase_options,\n \t\t\t     builtin_rebase_usage, 0);\n@@ -455,6 +481,26 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \t\tusage_with_options(builtin_rebase_usage,\n \t\t\t\t   builtin_rebase_options);\n \n+\t/* Make sure no rebase is in progress */\n+\tif (in_progress) {\n+\t\tconst char *last_slash = strrchr(options.state_dir, '/');\n+\t\tconst char *state_dir_base =\n+\t\t\tlast_slash ? last_slash + 1 : options.state_dir;\n+\t\tconst char *cmd_live_rebase =\n+\t\t\t\"git rebase (--continue | --abort | --skip)\";\n+\t\tstrbuf_reset(&buf);\n+\t\tstrbuf_addf(&buf, \"rm -fr \\\"%s\\\"\", options.state_dir);\n+\t\tdie(_(\"It seems that there is already a %s directory, and\\n\"\n+\t\t      \"I wonder if you are in the middle of another rebase.  \"\n+\t\t      \"If that is the\\n\"\n+\t\t      \"case, please try\\n\\t%s\\n\"\n+\t\t      \"If that is not the case, please\\n\\t%s\\n\"\n+\t\t      \"and run me again.  I am stopping in case you still \"\n+\t\t      \"have something\\n\"\n+\t\t      \"valuable there.\\n\"),\n+\t\t    state_dir_base, cmd_live_rebase, buf.buf);\n+\t}\n+\n \tif (!(options.flags & REBASE_NO_QUIET))\n \t\tstrbuf_addstr(&options.git_am_opt, \" -q\");\n \n-- \ngitgitgadget\n\n"},{"id":"357362","messageId":"aab01f0b8e15db37bc17630b4298148aeacf41e2.1536096424.git.gitgitgadget@gmail.com","threadId":"49071","inReplyTo":"pull.32.v2.git.gitgitgadget@gmail.com","subject":"[PATCH v2 10/11] builtin rebase: only store fully-qualified refs in `options.head_name`","fromName":"Pratik Karki via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2018-09-04T21:27:20Z","receivedAt":"2018-09-04T21:27:23Z","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 on a detached HEAD, we currently store the string\n\"detached HEAD\" in options.head_name. That is a faithful translation of\nthe shell script version, and we still kind of need it for the purposes of\nthe scripted backends.\n\nIt is poor style for C, though, where we would really only want a valid,\nfully-qualified ref name as value, and NULL for detached HEADs, using\n\"detached HEAD\" for display only. Make it so.\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, 8 insertions(+), 3 deletions(-)\n\ndiff --git a/builtin/rebase.c b/builtin/rebase.c\nindex d45f8f9008..afc75fe731 100644\n--- a/builtin/rebase.c\n+++ b/builtin/rebase.c\n@@ -169,7 +169,8 @@ static int run_specific_rebase(struct rebase_options *opts)\n \tadd_var(&script_snippet, \"upstream_name\", opts->upstream_name);\n \tadd_var(&script_snippet, \"upstream\",\n \t\t\t\t oid_to_hex(&opts->upstream->object.oid));\n-\tadd_var(&script_snippet, \"head_name\", opts->head_name);\n+\tadd_var(&script_snippet, \"head_name\",\n+\t\topts->head_name ? opts->head_name : \"detached HEAD\");\n \tadd_var(&script_snippet, \"orig_head\", oid_to_hex(&opts->orig_head));\n \tadd_var(&script_snippet, \"onto\", oid_to_hex(&opts->onto->object.oid));\n \tadd_var(&script_snippet, \"onto_name\", opts->onto_name);\n@@ -251,6 +252,9 @@ static int reset_head(struct object_id *oid, const char *action,\n \t\t*old_orig = NULL, oid_old_orig;\n \tint ret = 0;\n \n+\tif (switch_to_branch && !starts_with(switch_to_branch, \"refs/\"))\n+\t\tBUG(\"Not a fully qualified branch: '%s'\", switch_to_branch);\n+\n \tif (hold_locked_index(&lock, LOCK_REPORT_ON_ERROR) < 0)\n \t\treturn -1;\n \n@@ -558,7 +562,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \t * branch_name -- branch/commit being rebased, or\n \t * \t\t  HEAD (already detached)\n \t * orig_head -- commit object name of tip of the branch before rebasing\n-\t * head_name -- refs/heads/<that-branch> or \"detached HEAD\"\n+\t * head_name -- refs/heads/<that-branch> or NULL (detached HEAD)\n \t */\n \tif (argc > 0)\n \t\t die(\"TODO: handle switch_to\");\n@@ -575,7 +579,8 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \t\t\t\tbranch_name = options.head_name;\n \n \t\t} else {\n-\t\t\toptions.head_name = xstrdup(\"detached HEAD\");\n+\t\t\tfree(options.head_name);\n+\t\t\toptions.head_name = NULL;\n \t\t\tbranch_name = \"HEAD\";\n \t\t}\n \t\tif (get_oid(\"HEAD\", &options.orig_head))\n-- \ngitgitgadget\n\n"},{"id":"357363","messageId":"e64190d8edbb1d085074e91acd64f0b7dfc97c86.1536096424.git.gitgitgadget@gmail.com","threadId":"49071","inReplyTo":"pull.32.v2.git.gitgitgadget@gmail.com","subject":"[PATCH v2 11/11] builtin rebase: support `git rebase <upstream> <switch-to>`","fromName":"Pratik Karki via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2018-09-04T21:27:21Z","receivedAt":"2018-09-04T21:27:24Z","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 `switch-to` which is used to switch to the\ntarget branch if needed. The equivalent codes found in shell script\n`git-legacy-rebase.sh` is converted to builtin `rebase.c`.\n\nSigned-off-by: Pratik Karki <predatoramigo@gmail.com>\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n builtin/rebase.c | 48 ++++++++++++++++++++++++++++++++++++++++++++----\n 1 file changed, 44 insertions(+), 4 deletions(-)\n\ndiff --git a/builtin/rebase.c b/builtin/rebase.c\nindex afc75fe731..e817956d96 100644\n--- a/builtin/rebase.c\n+++ b/builtin/rebase.c\n@@ -79,6 +79,7 @@ struct rebase_options {\n \tstruct commit *onto;\n \tconst char *onto_name;\n \tconst char *revisions;\n+\tconst char *switch_to;\n \tint root;\n \tstruct commit *restrict_revision;\n \tint dont_finish_rebase;\n@@ -186,6 +187,8 @@ static int run_specific_rebase(struct rebase_options *opts)\n \t\topts->flags & REBASE_DIFFSTAT ? \"t\" : \"\");\n \tadd_var(&script_snippet, \"force_rebase\",\n \t\topts->flags & REBASE_FORCE ? \"t\" : \"\");\n+\tif (opts->switch_to)\n+\t\tadd_var(&script_snippet, \"switch_to\", opts->switch_to);\n \n \tswitch (opts->type) {\n \tcase REBASE_AM:\n@@ -564,9 +567,23 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \t * orig_head -- commit object name of tip of the branch before rebasing\n \t * head_name -- refs/heads/<that-branch> or NULL (detached HEAD)\n \t */\n-\tif (argc > 0)\n-\t\t die(\"TODO: handle switch_to\");\n-\telse {\n+\tif (argc == 1) {\n+\t\t/* Is it \"rebase other branchname\" or \"rebase other commit\"? */\n+\t\tbranch_name = argv[0];\n+\t\toptions.switch_to = argv[0];\n+\n+\t\t/* Is it a local branch? */\n+\t\tstrbuf_reset(&buf);\n+\t\tstrbuf_addf(&buf, \"refs/heads/%s\", branch_name);\n+\t\tif (!read_ref(buf.buf, &options.orig_head))\n+\t\t\toptions.head_name = xstrdup(buf.buf);\n+\t\t/* If not is it a valid ref (branch or commit)? */\n+\t\telse if (!get_oid(branch_name, &options.orig_head))\n+\t\t\toptions.head_name = NULL;\n+\t\telse\n+\t\t\tdie(_(\"fatal: no such branch/commit '%s'\"),\n+\t\t\t    branch_name);\n+\t} else if (argc == 0) {\n \t\t/* Do not need to switch branches, we are already on it. */\n \t\toptions.head_name =\n \t\t\txstrdup_or_null(resolve_ref_unsafe(\"HEAD\", 0, NULL,\n@@ -585,7 +602,8 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \t\t}\n \t\tif (get_oid(\"HEAD\", &options.orig_head))\n \t\t\tdie(_(\"Could not resolve HEAD to a revision\"));\n-\t}\n+\t} else\n+\t\tBUG(\"unexpected number of arguments left to parse\");\n \n \tif (read_index(the_repository->index) < 0)\n \t\tdie(_(\"could not read index\"));\n@@ -612,6 +630,28 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \t\tint flag;\n \n \t\tif (!(options.flags & REBASE_FORCE)) {\n+\t\t\t/* Lazily switch to the target branch if needed... */\n+\t\t\tif (options.switch_to) {\n+\t\t\t\tstruct object_id oid;\n+\n+\t\t\t\tif (get_oid(options.switch_to, &oid) < 0) {\n+\t\t\t\t\tret = !!error(_(\"could not parse '%s'\"),\n+\t\t\t\t\t\t      options.switch_to);\n+\t\t\t\t\tgoto cleanup;\n+\t\t\t\t}\n+\n+\t\t\t\tstrbuf_reset(&buf);\n+\t\t\t\tstrbuf_addf(&buf, \"rebase: checkout %s\",\n+\t\t\t\t\t    options.switch_to);\n+\t\t\t\tif (reset_head(&oid, \"checkout\",\n+\t\t\t\t\t       options.head_name, 0) < 0) {\n+\t\t\t\t\tret = !!error(_(\"could not switch to \"\n+\t\t\t\t\t\t\t\"%s\"),\n+\t\t\t\t\t\t      options.switch_to);\n+\t\t\t\t\tgoto cleanup;\n+\t\t\t\t}\n+\t\t\t}\n+\n \t\t\tif (!(options.flags & REBASE_NO_QUIET))\n \t\t\t\t; /* be quiet */\n \t\t\telse if (!strcmp(branch_name, \"HEAD\") &&\n-- \ngitgitgadget\n"},{"id":"357682","messageId":"20180908085207.GB10370@localhost","threadId":"49071","inReplyTo":"aab01f0b8e15db37bc17630b4298148aeacf41e2.1536096424.git.gitgitgadget@gmail.com","subject":"Re: [PATCH v2 10/11] builtin rebase: only store fully-qualified refs in `options.head_name`","fromName":"SZEDER Gábor","fromEmail":"szeder.dev@gmail.com","sentAt":"2018-09-08T08:52:07Z","receivedAt":"2018-09-08T08:52:14Z","isPatch":true,"sender":{"key":"szeder.dev@gmail.com","avatar":"https://avatars.githubusercontent.com/u/116324?v=4"},"body":"On Tue, Sep 04, 2018 at 02:27:20PM -0700, Pratik Karki via GitGitGadget wrote:\n> From: Pratik Karki <predatoramigo@gmail.com>\n> \n> When running a rebase on a detached HEAD, we currently store the string\n> \"detached HEAD\" in options.head_name. That is a faithful translation of\n> the shell script version, and we still kind of need it for the purposes of\n> the scripted backends.\n> \n> It is poor style for C, though, where we would really only want a valid,\n> fully-qualified ref name as value, and NULL for detached HEADs, using\n> \"detached HEAD\" for display only. Make it so.\n> \n> Signed-off-by: Pratik Karki <predatoramigo@gmail.com>\n> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n> ---\n>  builtin/rebase.c | 11 ++++++++---\n>  1 file changed, 8 insertions(+), 3 deletions(-)\n> \n> diff --git a/builtin/rebase.c b/builtin/rebase.c\n> index d45f8f9008..afc75fe731 100644\n> --- a/builtin/rebase.c\n> +++ b/builtin/rebase.c\n\n> @@ -575,7 +579,8 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n>  \t\t\t\tbranch_name = options.head_name;\n>  \n>  \t\t} else {\n> -\t\t\toptions.head_name = xstrdup(\"detached HEAD\");\n> +\t\t\tfree(options.head_name);\n> +\t\t\toptions.head_name = NULL;\n\nPlease use FREE_AND_NULL(options.head_name) here.\n\n>  \t\t\tbranch_name = \"HEAD\";\n>  \t\t}\n>  \t\tif (get_oid(\"HEAD\", &options.orig_head))\n> -- \n> gitgitgadget\n> \n"},{"id":"357796","messageId":"xmqqva7dthq5.fsf@gitster-ct.c.googlers.com","threadId":"49071","inReplyTo":"20180908085207.GB10370@localhost","subject":"Re: [PATCH v2 10/11] builtin rebase: only store fully-qualified refs in `options.head_name`","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2018-09-10T16:55:30Z","receivedAt":"2018-09-10T16:55:35Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"SZEDER Gábor <szeder.dev@gmail.com> writes:\n\n>>  \t\t} else {\n>> -\t\t\toptions.head_name = xstrdup(\"detached HEAD\");\n>> +\t\t\tfree(options.head_name);\n>> +\t\t\toptions.head_name = NULL;\n>\n> Please use FREE_AND_NULL(options.head_name) here.\n\nGood; did contrib/coccinelle/free.cocci catch this?\n\n>\n>>  \t\t\tbranch_name = \"HEAD\";\n>>  \t\t}\n>>  \t\tif (get_oid(\"HEAD\", &options.orig_head))\n>> -- \n>> gitgitgadget\n>> \n"},{"id":"357828","messageId":"20180910202527.GC17224@localhost","threadId":"49071","inReplyTo":"xmqqva7dthq5.fsf@gitster-ct.c.googlers.com","subject":"Re: [PATCH v2 10/11] builtin rebase: only store fully-qualified refs in `options.head_name`","fromName":"SZEDER Gábor","fromEmail":"szeder.dev@gmail.com","sentAt":"2018-09-10T20:25:27Z","receivedAt":"2018-09-10T20:25:33Z","isPatch":true,"sender":{"key":"szeder.dev@gmail.com","avatar":"https://avatars.githubusercontent.com/u/116324?v=4"},"body":"On Mon, Sep 10, 2018 at 09:55:30AM -0700, Junio C Hamano wrote:\n> SZEDER Gábor <szeder.dev@gmail.com> writes:\n> \n> >>  \t\t} else {\n> >> -\t\t\toptions.head_name = xstrdup(\"detached HEAD\");\n> >> +\t\t\tfree(options.head_name);\n> >> +\t\t\toptions.head_name = NULL;\n> >\n> > Please use FREE_AND_NULL(options.head_name) here.\n> \n> Good; did contrib/coccinelle/free.cocci catch this?\n\nYes.\n\nBut now that you mention it, I see that it didn't catch it in 'pu' or\nin most of the later 'pk/rebase-in-c-X-...' branches, even though they\nall have these lines.  It bisects to 0073df2bd3 (builtin rebase:\nsupport --rebase-merges[=[no-]rebase-cousins], 2018-09-04), which\ndoesn't touch these lines at all.\n\nStrange; I have no idea what's going on.\n\n"}]}