{"thread":{"id":"49075","subject":"[GSoC] [PATCH 0/6] builtin rebase rest","startedAt":"2018-08-08T15:38:19Z","lastAt":"2018-08-08T15:38:41Z","messageCount":7,"participants":["Pratik Karki"],"isPatch":true,"patchVersion":1,"patchTotal":6},"messages":[{"id":"354844","messageId":"20180808153635.19944-1-predatoramigo@gmail.com","threadId":"49075","inReplyTo":null,"subject":"[GSoC] [PATCH 0/6] builtin rebase rest","fromName":"Pratik Karki","fromEmail":"predatoramigo@gmail.com","sentAt":"2018-08-08T15:36:29Z","receivedAt":"2018-08-08T15:38:19Z","isPatch":true,"sender":{"key":"predatoramigo@gmail.com","avatar":"https://avatars.githubusercontent.com/u/12194950?v=4"},"body":"This patch pretty much converts all what is remaining from the shell-script\nversion of `git rebase` to the builtin version. After the conversion of\nactions and different options which are important for builtin rebase and have\nbeen organized to make a patch series of their own. There were still some\nleftover shell scripts on the original rebase and hence, this patch series\naddresses those by converting them and this completes the builtin rebase.\n\nIt adds the functionality to the previous patch series,\n(https://public-inbox.org/git/20180808152140.14585-1-predatoramigo@gmail.com/).\n\nThis is the fifth patch series that brings us more closer to a builtin\n\"git rebase\".\n\nIf you like to view the development branch, you can view\n(https://github.com/git/git/pull/505), where I have kept my commits up to date\nand leveraged Travis(there is sporadic failures in t5520 for macos gcc and\nisn't due to my patches) for extra testing other than my system.\n\nThe next in line patch series which I'll be sending out today are:\n\ndefault to builtin rebase: This will turn on the feature-complete builtin\nrebase to on.\n\nThese patch series are built on top of each other, i.e. they depend on this\norder.\n\nPratik Karki (6):\n  builtin rebase: optionally auto-detect the upstream\n  builtin rebase: optionally pass custom reflogs to reset_head()\n  builtin rebase: fast-forward to onto if it is a proper descendant\n  builtin rebase: show progress when connected to a terminal\n  builtin rebase: use no-op editor when interactive is \"implied\"\n  builtin rebase: error out on incompatible option/mode combinations\n\n builtin/rebase.c | 150 ++++++++++++++++++++++++++++++++++++++++++-----\n 1 file changed, 135 insertions(+), 15 deletions(-)\n\n-- \n2.18.0\n\n"},{"id":"354845","messageId":"20180808153635.19944-2-predatoramigo@gmail.com","threadId":"49075","inReplyTo":"20180808153635.19944-1-predatoramigo@gmail.com","subject":"[PATCH 1/6] builtin rebase: optionally auto-detect the upstream","fromName":"Pratik Karki","fromEmail":"predatoramigo@gmail.com","sentAt":"2018-08-08T15:36:30Z","receivedAt":"2018-08-08T15:38:23Z","isPatch":true,"sender":{"key":"predatoramigo@gmail.com","avatar":"https://avatars.githubusercontent.com/u/12194950?v=4"},"body":"The `git rebase` command, when called without the `<upstream>`\ncommand-line argument, automatically looks for the upstream\nbranch configured for the current branch.\n\nWith this commit, the builtin rebase learned that trick, too.\n\nSigned-off-by: Pratik Karki <predatoramigo@gmail.com>\n---\n builtin/rebase.c | 44 +++++++++++++++++++++++++++++++++++++++++---\n 1 file changed, 41 insertions(+), 3 deletions(-)\n\ndiff --git a/builtin/rebase.c b/builtin/rebase.c\nindex 94abaaa890..c5b2534717 100644\n--- a/builtin/rebase.c\n+++ b/builtin/rebase.c\n@@ -622,6 +622,36 @@ static int parse_opt_interactive(const struct option *opt, const char *arg,\n \treturn 0;\n }\n \n+static void NORETURN error_on_missing_default_upstream(void)\n+{\n+\tstruct branch *current_branch = branch_get(NULL);\n+\n+\tprintf(_(\"%s\\n\"\n+\t\t \"Please specify which branch you want to rebase against.\\n\"\n+\t\t \"See git-rebase(1) for details.\\n\"\n+\t\t \"\\n\"\n+\t\t \"    git rebase '<branch>'\\n\"\n+\t\t \"\\n\"),\n+\t\tcurrent_branch ? _(\"There is no tracking information for \"\n+\t\t\t\"the current branch.\") :\n+\t\t\t_(\"You are not currently on a branch.\"));\n+\n+\tif (current_branch) {\n+\t\tconst char *remote = current_branch->remote_name;\n+\n+\t\tif (!remote)\n+\t\t\tremote = _(\"<remote>\");\n+\n+\t\tprintf(_(\"If you wish to set tracking information for this \"\n+\t\t\t \"branch you can do so with:\\n\"\n+\t\t\t \"\\n\"\n+\t\t\t \"    git branch --set-upstream-to=%s/<branch> %s\\n\"\n+\t\t\t \"\\n\"),\n+\t\t       remote, current_branch->name);\n+\t}\n+\texit(1);\n+}\n+\n int cmd_rebase(int argc, const char **argv, const char *prefix)\n {\n \tstruct rebase_options options = {\n@@ -1056,9 +1086,17 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \t}\n \n \tif (!options.root) {\n-\t\tif (argc < 1)\n-\t\t\tdie(\"TODO: handle @{upstream}\");\n-\t\telse {\n+\t\tif (argc < 1) {\n+\t\t\tstruct branch *branch;\n+\n+\t\t\tbranch = branch_get(NULL);\n+\t\t\toptions.upstream_name = branch_get_upstream(branch,\n+\t\t\t\t\t\t\t\t    NULL);\n+\t\t\tif (!options.upstream_name)\n+\t\t\t\terror_on_missing_default_upstream();\n+\t\t\tif (fork_point < 0)\n+\t\t\t\tfork_point = 1;\n+\t\t} else {\n \t\t\toptions.upstream_name = argv[0];\n \t\t\targc--;\n \t\t\targv++;\n-- \n2.18.0\n\n"},{"id":"354846","messageId":"20180808153635.19944-3-predatoramigo@gmail.com","threadId":"49075","inReplyTo":"20180808153635.19944-1-predatoramigo@gmail.com","subject":"[PATCH 2/6] builtin rebase: optionally pass custom reflogs to reset_head()","fromName":"Pratik Karki","fromEmail":"predatoramigo@gmail.com","sentAt":"2018-08-08T15:36:31Z","receivedAt":"2018-08-08T15:38:27Z","isPatch":true,"sender":{"key":"predatoramigo@gmail.com","avatar":"https://avatars.githubusercontent.com/u/12194950?v=4"},"body":"In the next patch, we will make use of that in the code that\nfast-forwards to `onto` whenever possible.\n\nSigned-off-by: Pratik Karki <predatoramigo@gmail.com>\n---\n builtin/rebase.c | 33 +++++++++++++++++++++------------\n 1 file changed, 21 insertions(+), 12 deletions(-)\n\ndiff --git a/builtin/rebase.c b/builtin/rebase.c\nindex c5b2534717..c51b9d288a 100644\n--- a/builtin/rebase.c\n+++ b/builtin/rebase.c\n@@ -431,7 +431,8 @@ static int run_specific_rebase(struct rebase_options *opts)\n #define GIT_REFLOG_ACTION_ENVIRONMENT \"GIT_REFLOG_ACTION\"\n \n static int reset_head(struct object_id *oid, const char *action,\n-\t\t      const char *switch_to_branch, int detach_head)\n+\t\t      const char *switch_to_branch, int detach_head,\n+\t\t      const char *reflog_orig_head, const char *reflog_head)\n {\n \tstruct object_id head_oid;\n \tstruct tree_desc desc;\n@@ -506,20 +507,26 @@ static int reset_head(struct object_id *oid, const char *action,\n \t\told_orig = &oid_old_orig;\n \tif (!get_oid(\"HEAD\", &oid_orig)) {\n \t\torig = &oid_orig;\n-\t\tstrbuf_addstr(&msg, \"updating ORIG_HEAD\");\n-\t\tupdate_ref(msg.buf, \"ORIG_HEAD\", orig, old_orig, 0,\n+\t\tif (!reflog_orig_head) {\n+\t\t\tstrbuf_addstr(&msg, \"updating ORIG_HEAD\");\n+\t\t\treflog_orig_head = msg.buf;\n+\t\t}\n+\t\tupdate_ref(reflog_orig_head, \"ORIG_HEAD\", orig, old_orig, 0,\n \t\t\t   UPDATE_REFS_MSG_ON_ERR);\n \t} else if (old_orig)\n \t\tdelete_ref(NULL, \"ORIG_HEAD\", old_orig, 0);\n-\tstrbuf_setlen(&msg, prefix_len);\n-\tstrbuf_addstr(&msg, \"updating HEAD\");\n+\tif (!reflog_head) {\n+\t\tstrbuf_setlen(&msg, prefix_len);\n+\t\tstrbuf_addstr(&msg, \"updating HEAD\");\n+\t\treflog_head = msg.buf;\n+\t}\n \tif (!switch_to_branch)\n-\t\tret = update_ref(msg.buf, \"HEAD\", oid, orig, REF_NO_DEREF,\n+\t\tret = update_ref(reflog_head, \"HEAD\", oid, orig, REF_NO_DEREF,\n \t\t\t\t UPDATE_REFS_MSG_ON_ERR);\n \telse {\n \t\tret = create_symref(\"HEAD\", switch_to_branch, msg.buf);\n \t\tif (!ret)\n-\t\t\tret = update_ref(msg.buf, \"HEAD\", oid, NULL, 0,\n+\t\t\tret = update_ref(reflog_head, \"HEAD\", oid, NULL, 0,\n \t\t\t\t\t UPDATE_REFS_MSG_ON_ERR);\n \t}\n \n@@ -899,7 +906,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \t\trerere_clear(&merge_rr);\n \t\tstring_list_clear(&merge_rr, 1);\n \n-\t\tif (reset_head(NULL, \"reset\", NULL, 0) < 0)\n+\t\tif (reset_head(NULL, \"reset\", NULL, 0, NULL, NULL) < 0)\n \t\t\tdie(_(\"could not discard worktree changes\"));\n \t\tif (read_basic_state(&options))\n \t\t\texit(1);\n@@ -915,7 +922,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \t\tif (read_basic_state(&options))\n \t\t\texit(1);\n \t\tif (reset_head(&options.orig_head, \"reset\",\n-\t\t\t       options.head_name, 0) < 0)\n+\t\t\t       options.head_name, 0, NULL, NULL) < 0)\n \t\t\tdie(_(\"could not move back to %s\"),\n \t\t\t    oid_to_hex(&options.orig_head));\n \t\tret = finish_rebase(&options);\n@@ -1235,7 +1242,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \t\t\twrite_file(autostash, \"%s\", buf.buf);\n \t\t\tprintf(_(\"Created autostash: %s\\n\"), buf.buf);\n \t\t\tif (reset_head(&head->object.oid, \"reset --hard\",\n-\t\t\t\t       NULL, 0) < 0)\n+\t\t\t\t       NULL, 0, NULL, NULL) < 0)\n \t\t\t\tdie(_(\"could not reset --hard\"));\n \t\t\tprintf(_(\"HEAD is now at %s\"),\n \t\t\t       find_unique_abbrev(&head->object.oid,\n@@ -1289,7 +1296,8 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\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\t       options.head_name, 0,\n+\t\t\t\t\t       NULL, NULL) < 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@@ -1354,7 +1362,8 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\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+\tif (reset_head(&options.onto->object.oid, \"checkout\", NULL, 1,\n+\t    NULL, msg.buf))\n \t\tdie(_(\"Could not detach HEAD\"));\n \tstrbuf_release(&msg);\n \n-- \n2.18.0\n\n"},{"id":"354847","messageId":"20180808153635.19944-4-predatoramigo@gmail.com","threadId":"49075","inReplyTo":"20180808153635.19944-1-predatoramigo@gmail.com","subject":"[PATCH 3/6] builtin rebase: fast-forward to onto if it is a proper descendant","fromName":"Pratik Karki","fromEmail":"predatoramigo@gmail.com","sentAt":"2018-08-08T15:36:32Z","receivedAt":"2018-08-08T15:38:30Z","isPatch":true,"sender":{"key":"predatoramigo@gmail.com","avatar":"https://avatars.githubusercontent.com/u/12194950?v=4"},"body":"When trying to rebase onto a direct descendant of HEAD, we can\ntake a shortcut and fast-forward instead. This commit makes it so.\n\nSigned-off-by: Pratik Karki <predatoramigo@gmail.com>\n---\n builtin/rebase.c | 18 ++++++++++++++++++\n 1 file changed, 18 insertions(+)\n\ndiff --git a/builtin/rebase.c b/builtin/rebase.c\nindex c51b9d288a..1bb64e7cd7 100644\n--- a/builtin/rebase.c\n+++ b/builtin/rebase.c\n@@ -1367,6 +1367,24 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \t\tdie(_(\"Could not detach HEAD\"));\n \tstrbuf_release(&msg);\n \n+\t/*\n+\t * If the onto is a proper descendant of the tip of the branch, then\n+\t * we just fast-forwarded.\n+\t */\n+\tstrbuf_reset(&msg);\n+\tif (!oidcmp(&merge_base, &options.orig_head)) {\n+\t\tprintf(_(\"Fast-forwarded %s to %s. \\n\"),\n+\t\t\tbranch_name, options.onto_name);\n+\t\tstrbuf_addf(&msg, \"rebase finished: %s onto %s\",\n+\t\t\toptions.head_name ? options.head_name : \"detached HEAD\",\n+\t\t\toid_to_hex(&options.onto->object.oid));\n+\t\treset_head(NULL, \"Fast-forwarded\", options.head_name, 0,\n+\t\t\t   \"HEAD\", msg.buf);\n+\t\tstrbuf_release(&msg);\n+\t\tret = !!finish_rebase(&options);\n+\t\tgoto cleanup;\n+\t}\n+\n \tstrbuf_addf(&revisions, \"%s..%s\",\n \t\t    options.root ? oid_to_hex(&options.onto->object.oid) :\n \t\t    (options.restrict_revision ?\n-- \n2.18.0\n\n"},{"id":"354848","messageId":"20180808153635.19944-5-predatoramigo@gmail.com","threadId":"49075","inReplyTo":"20180808153635.19944-1-predatoramigo@gmail.com","subject":"[PATCH 4/6] builtin rebase: show progress when connected to a terminal","fromName":"Pratik Karki","fromEmail":"predatoramigo@gmail.com","sentAt":"2018-08-08T15:36:33Z","receivedAt":"2018-08-08T15:38:34Z","isPatch":true,"sender":{"key":"predatoramigo@gmail.com","avatar":"https://avatars.githubusercontent.com/u/12194950?v=4"},"body":"In this commit, we pass `--progress` to the `format-patch` command if\nstderr is connected to an interactive terminal, unless we're in quiet\nmode.\n\nThis `--progress` option will be used in `format-patch` to show progress\nreports on stderr as patches are generated.\n\nSigned-off-by: Pratik Karki <predatoramigo@gmail.com>\n---\n builtin/rebase.c | 7 +++++++\n 1 file changed, 7 insertions(+)\n\ndiff --git a/builtin/rebase.c b/builtin/rebase.c\nindex 1bb64e7cd7..04974dff6e 100644\n--- a/builtin/rebase.c\n+++ b/builtin/rebase.c\n@@ -98,6 +98,7 @@ struct rebase_options {\n \tint allow_empty_message;\n \tint rebase_merges, rebase_cousins;\n \tchar *strategy, *strategy_opts;\n+\tstruct strbuf git_format_patch_opt;\n };\n \n static int is_interactive(struct rebase_options *opts)\n@@ -379,6 +380,8 @@ static int run_specific_rebase(struct rebase_options *opts)\n \tadd_var(&script_snippet, \"rebase_root\", opts->root ? \"t\" : \"\");\n \tadd_var(&script_snippet, \"squash_onto\",\n \t\topts->squash_onto ? oid_to_hex(opts->squash_onto) : \"\");\n+\tadd_var(&script_snippet, \"git_format_patch_opt\",\n+\t\topts->git_format_patch_opt.buf);\n \n \tswitch (opts->type) {\n \tcase REBASE_AM:\n@@ -667,6 +670,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \t\t.git_am_opt = STRBUF_INIT,\n \t\t.allow_rerere_autoupdate  = -1,\n \t\t.allow_empty_message = 1,\n+\t\t.git_format_patch_opt = STRBUF_INIT,\n \t};\n \tconst char *branch_name;\n \tint ret, flags, total_argc, in_progress = 0;\n@@ -1068,6 +1072,9 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \tif (options.root && !options.onto_name)\n \t\timply_interactive(&options, \"--root without --onto\");\n \n+\tif (isatty(2) && options.flags & REBASE_NO_QUIET)\n+\t\tstrbuf_addstr(&options.git_format_patch_opt, \" --progress\");\n+\n \tswitch (options.type) {\n \tcase REBASE_MERGE:\n \tcase REBASE_INTERACTIVE:\n-- \n2.18.0\n\n"},{"id":"354849","messageId":"20180808153635.19944-6-predatoramigo@gmail.com","threadId":"49075","inReplyTo":"20180808153635.19944-1-predatoramigo@gmail.com","subject":"[PATCH 5/6] builtin rebase: use no-op editor when interactive is \"implied\"","fromName":"Pratik Karki","fromEmail":"predatoramigo@gmail.com","sentAt":"2018-08-08T15:36:34Z","receivedAt":"2018-08-08T15:38:37Z","isPatch":true,"sender":{"key":"predatoramigo@gmail.com","avatar":"https://avatars.githubusercontent.com/u/12194950?v=4"},"body":"Some options are only handled by the git-rebase--interactive backend,\neven if run non-interactively. For this awkward situation (run\nnon-interactively, but use the interactive backend), the shell scripted\nversion of `git rebase` introduced the concept of an \"implied\ninteractive rebase\". All it does is to replace the editor by a dummy one\n(`:` is the Unix command that takes arbitrary command-line parameters,\nignores them and simply exits with success).\n\nSigned-off-by: Pratik Karki <predatoramigo@gmail.com>\n---\n builtin/rebase.c | 7 +++++++\n 1 file changed, 7 insertions(+)\n\ndiff --git a/builtin/rebase.c b/builtin/rebase.c\nindex 04974dff6e..fb8ab5a177 100644\n--- a/builtin/rebase.c\n+++ b/builtin/rebase.c\n@@ -383,6 +383,13 @@ static int run_specific_rebase(struct rebase_options *opts)\n \tadd_var(&script_snippet, \"git_format_patch_opt\",\n \t\topts->git_format_patch_opt.buf);\n \n+\tif (is_interactive(opts) &&\n+\t    !(opts->flags & REBASE_INTERACTIVE_EXPLICIT)) {\n+\t\tstrbuf_addstr(&script_snippet,\n+\t\t\t      \"GIT_EDITOR=:; export GIT_EDITOR; \");\n+\t\topts->autosquash = 0;\n+\t}\n+\n \tswitch (opts->type) {\n \tcase REBASE_AM:\n \t\tbackend = \"git-rebase--am\";\n-- \n2.18.0\n\n"},{"id":"354850","messageId":"20180808153635.19944-7-predatoramigo@gmail.com","threadId":"49075","inReplyTo":"20180808153635.19944-1-predatoramigo@gmail.com","subject":"[PATCH 6/6] builtin rebase: error out on incompatible option/mode combinations","fromName":"Pratik Karki","fromEmail":"predatoramigo@gmail.com","sentAt":"2018-08-08T15:36:35Z","receivedAt":"2018-08-08T15:38:41Z","isPatch":true,"sender":{"key":"predatoramigo@gmail.com","avatar":"https://avatars.githubusercontent.com/u/12194950?v=4"},"body":"While working on the GSoC project to convert the rebase command to a\nbuiltin, the rebase command learned to error out on certain command-line\noption combinations that cannot work, such as --whitespace=fix with\n--interactive.\n\nThis commit converts that code.\n\nSigned-off-by: Pratik Karki <predatoramigo@gmail.com>\n---\n builtin/rebase.c | 41 +++++++++++++++++++++++++++++++++++++++++\n 1 file changed, 41 insertions(+)\n\ndiff --git a/builtin/rebase.c b/builtin/rebase.c\nindex fb8ab5a177..4e69458161 100644\n--- a/builtin/rebase.c\n+++ b/builtin/rebase.c\n@@ -1098,6 +1098,28 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \t\tbreak;\n \t}\n \n+\tif (options.git_am_opt.len) {\n+\t\tconst char *p;\n+\n+\t\t/* all am options except -q are compatible only with --am */\n+\t\tstrbuf_reset(&buf);\n+\t\tstrbuf_addbuf(&buf, &options.git_am_opt);\n+\t\tstrbuf_addch(&buf, ' ');\n+\t\twhile ((p = strstr(buf.buf, \" -q \")))\n+\t\t\tstrbuf_splice(&buf, p - buf.buf, 4, \" \", 1);\n+\t\tstrbuf_trim(&buf);\n+\n+\t\tif (is_interactive(&options) && buf.len)\n+\t\t\tdie(_(\"error: cannot combine interactive options \"\n+\t\t\t      \"(--interactive, --exec, --rebase-merges, \"\n+\t\t\t      \"--preserve-merges, --keep-empty, --root + \"\n+\t\t\t      \"--onto) with am options (%s)\"), buf.buf);\n+\t\tif (options.type == REBASE_MERGE && buf.len)\n+\t\t\tdie(_(\"error: cannot combine merge options (--merge, \"\n+\t\t\t      \"--strategy, --strategy-option) with am options \"\n+\t\t\t      \"(%s)\"), buf.buf);\n+\t}\n+\n \tif (options.signoff) {\n \t\tif (options.type == REBASE_PRESERVE_MERGES)\n \t\t\tdie(\"cannot combine '--signoff' with \"\n@@ -1106,6 +1128,25 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \t\toptions.flags |= REBASE_FORCE;\n \t}\n \n+\tif (options.type == REBASE_PRESERVE_MERGES)\n+\t\t/*\n+\t\t * Note: incompatibility with --signoff handled in signoff block above\n+\t\t * Note: incompatibility with --interactive is just a strong warning;\n+\t\t *       git-rebase.txt caveats with \"unless you know what you are doing\"\n+\t\t */\n+\t\tif (options.rebase_merges)\n+\t\t\tdie(_(\"error: cannot combine '--preserve_merges' with \"\n+\t\t\t      \"'--rebase-merges'\"));\n+\n+\tif (options.rebase_merges) {\n+\t\tif (strategy_options.nr)\n+\t\t\tdie(_(\"error: cannot combine '--rebase_merges' with \"\n+\t\t\t      \"'--strategy-option'\"));\n+\t\tif (options.strategy)\n+\t\t\tdie(_(\"error: cannot combine '--rebase_merges' with \"\n+\t\t\t      \"'--strategy'\"));\n+\t}\n+\n \tif (!options.root) {\n \t\tif (argc < 1) {\n \t\t\tstruct branch *branch;\n-- \n2.18.0\n\n"}]}