{"thread":{"id":"48795","subject":"[GSoC] [PATCH 0/5] rebase: rewrite rebase in C","startedAt":"2018-06-28T07:48:10Z","lastAt":"2018-08-16T21:43:09Z","messageCount":61,"participants":["Pratik Karki","Christian Couder","Stefan Beller","Junio C Hamano","Johannes Schindelin","Andrei Rybak","Eric Sunshine","Beat Bolli","Duy Nguyen"],"isPatch":true,"patchVersion":1,"patchTotal":5},"messages":[{"id":"351184","messageId":"20180628074655.5756-1-predatoramigo@gmail.com","threadId":"48795","inReplyTo":null,"subject":"[GSoC] [PATCH 0/5] rebase: rewrite rebase in C","fromName":"Pratik Karki","fromEmail":"predatoramigo@gmail.com","sentAt":"2018-06-28T07:46:50Z","receivedAt":"2018-06-28T07:48:10Z","isPatch":true,"sender":{"key":"predatoramigo@gmail.com","avatar":"https://avatars.githubusercontent.com/u/12194950?v=4"},"body":"As a GSoC project, I have been working on the builtin rebase.\n\nThe motivation behind the rewrite of rebase i.e. from shell script to C\nare for following reasons:\n\n1.  Writing shell scripts and getting it to production is much faster\n    than doing the equivalent in C but lacks in performance and extra\n    workarounds are needed for non-POSIX platforms.\n\n2.  Git for Windows is at loss as the installer size increases due to\n    addition of extra dependencies for the shell scripts which are usually\n    available in POSIX compliant platforms.\n\nThis series of patches serves to demonstrate a minimal builtin rebase\nwhich supports running `git rebase <upstream>` and also serves to ask for\nreviews.\n\n\nPratik Karki (5):\n  Start TODO-rebase.sh\n  rebase: start implementing it as a builtin\n  rebase: refactor common shell functions into their own file\n  sequencer: refactor the code to detach HEAD to checkout.c\n  builtin/rebase: support running \"git rebase <upstream>\"\n\n .gitignore                      |   2 +\n Makefile                        |   4 +-\n git-rebase.sh => TODO-rebase.sh |   0\n builtin.h                       |   1 +\n builtin/rebase.c                | 282 +++++++++++++\n checkout.c                      |  64 +++\n checkout.h                      |   3 +\n git-legacy-rebase.sh            | 678 ++++++++++++++++++++++++++++++++\n git-rebase--common.sh           |  61 +++\n git.c                           |   6 +\n sequencer.c                     |  58 +--\n 11 files changed, 1105 insertions(+), 54 deletions(-)\n rename git-rebase.sh => TODO-rebase.sh (100%)\n create mode 100644 builtin/rebase.c\n create mode 100755 git-legacy-rebase.sh\n create mode 100644 git-rebase--common.sh\n\n-- \n2.18.0\n\n"},{"id":"351185","messageId":"20180628074655.5756-2-predatoramigo@gmail.com","threadId":"48795","inReplyTo":"20180628074655.5756-1-predatoramigo@gmail.com","subject":"[PATCH 1/5] Start TODO-rebase.sh","fromName":"Pratik Karki","fromEmail":"predatoramigo@gmail.com","sentAt":"2018-06-28T07:46:51Z","receivedAt":"2018-06-28T07:48:31Z","isPatch":true,"sender":{"key":"predatoramigo@gmail.com","avatar":"https://avatars.githubusercontent.com/u/12194950?v=4"},"body":"This is a verbatim copy of `git-rebase.sh`. This acts as a tracker\nfor components to be converted and to find the progress of current\nconversion of `git-rebase.sh` to `builtin/rebase.c`. The commented\nparts denote the converted parts.\n\nSigned-off-by: Pratik Karki <predatoramigo@gmail.com>\n---\n TODO-rebase.sh | 738 +++++++++++++++++++++++++++++++++++++++++++++++++\n 1 file changed, 738 insertions(+)\n create mode 100755 TODO-rebase.sh\n\ndiff --git a/TODO-rebase.sh b/TODO-rebase.sh\nnew file mode 100755\nindex 000000000..19bdebb48\n--- /dev/null\n+++ b/TODO-rebase.sh\n@@ -0,0 +1,738 @@\n+#!/bin/sh\n+#\n+# Copyright (c) 2005 Junio C Hamano.\n+#\n+\n+SUBDIRECTORY_OK=Yes\n+OPTIONS_KEEPDASHDASH=\n+OPTIONS_STUCKLONG=t\n+OPTIONS_SPEC=\"\\\n+git rebase [-i] [options] [--exec <cmd>] [--onto <newbase>] [<upstream>] [<branch>]\n+git rebase [-i] [options] [--exec <cmd>] [--onto <newbase>] --root [<branch>]\n+git rebase --continue | --abort | --skip | --edit-todo\n+--\n+ Available options are\n+v,verbose!         display a diffstat of what changed upstream\n+q,quiet!           be quiet. implies --no-stat\n+autostash          automatically stash/stash pop before and after\n+fork-point         use 'merge-base --fork-point' to refine upstream\n+onto=!             rebase onto given branch instead of upstream\n+r,rebase-merges?   try to rebase merges instead of skipping them\n+p,preserve-merges! try to recreate merges instead of ignoring them\n+s,strategy=!       use the given merge strategy\n+no-ff!             cherry-pick all commits, even if unchanged\n+m,merge!           use merging strategies to rebase\n+i,interactive!     let the user edit the list of commits to rebase\n+x,exec=!           add exec lines after each commit of the editable list\n+k,keep-empty\t   preserve empty commits during rebase\n+allow-empty-message allow rebasing commits with empty messages\n+f,force-rebase!    force rebase even if branch is up to date\n+X,strategy-option=! pass the argument through to the merge strategy\n+stat!              display a diffstat of what changed upstream\n+n,no-stat!         do not show diffstat of what changed upstream\n+verify             allow pre-rebase hook to run\n+rerere-autoupdate  allow rerere to update index with resolved conflicts\n+root!              rebase all reachable commits up to the root(s)\n+autosquash         move commits that begin with squash!/fixup! under -i\n+committer-date-is-author-date! passed to 'git am'\n+ignore-date!       passed to 'git am'\n+signoff            passed to 'git am'\n+whitespace=!       passed to 'git apply'\n+ignore-whitespace! passed to 'git apply'\n+C=!                passed to 'git apply'\n+S,gpg-sign?        GPG-sign commits\n+ Actions:\n+continue!          continue\n+abort!             abort and check out the original branch\n+skip!              skip current patch and continue\n+edit-todo!         edit the todo list during an interactive rebase\n+quit!              abort but keep HEAD where it is\n+show-current-patch! show the patch file being applied or merged\n+\"\n+. git-sh-setup\n+set_reflog_action rebase\n+require_work_tree_exists\n+cd_to_toplevel\n+\n+LF='\n+'\n+ok_to_skip_pre_rebase=\n+resolvemsg=\"\n+$(gettext 'Resolve all conflicts manually, mark them as resolved with\n+\"git add/rm <conflicted_files>\", then run \"git rebase --continue\".\n+You can instead skip this commit: run \"git rebase --skip\".\n+To abort and get back to the state before \"git rebase\", run \"git rebase --abort\".')\n+\"\n+squash_onto=\n+unset onto\n+unset restrict_revision\n+cmd=\n+strategy=\n+strategy_opts=\n+do_merge=\n+merge_dir=\"$GIT_DIR\"/rebase-merge\n+apply_dir=\"$GIT_DIR\"/rebase-apply\n+verbose=\n+diffstat=\n+test \"$(git config --bool rebase.stat)\" = true && diffstat=t\n+autostash=\"$(git config --bool rebase.autostash || echo false)\"\n+fork_point=auto\n+git_am_opt=\n+git_format_patch_opt=\n+rebase_root=\n+force_rebase=\n+allow_rerere_autoupdate=\n+# Non-empty if a rebase was in progress when 'git rebase' was invoked\n+in_progress=\n+# One of {am, merge, interactive}\n+type=\n+# One of {\"$GIT_DIR\"/rebase-apply, \"$GIT_DIR\"/rebase-merge}\n+state_dir=\n+# One of {'', continue, skip, abort}, as parsed from command line\n+action=\n+rebase_merges=\n+rebase_cousins=\n+preserve_merges=\n+autosquash=\n+keep_empty=\n+allow_empty_message=\n+signoff=\n+test \"$(git config --bool rebase.autosquash)\" = \"true\" && autosquash=t\n+case \"$(git config --bool commit.gpgsign)\" in\n+true)\tgpg_sign_opt=-S ;;\n+*)\tgpg_sign_opt= ;;\n+esac\n+\n+read_basic_state () {\n+\ttest -f \"$state_dir/head-name\" &&\n+\ttest -f \"$state_dir/onto\" &&\n+\thead_name=$(cat \"$state_dir\"/head-name) &&\n+\tonto=$(cat \"$state_dir\"/onto) &&\n+\t# We always write to orig-head, but interactive rebase used to write to\n+\t# head. Fall back to reading from head to cover for the case that the\n+\t# user upgraded git with an ongoing interactive rebase.\n+\tif test -f \"$state_dir\"/orig-head\n+\tthen\n+\t\torig_head=$(cat \"$state_dir\"/orig-head)\n+\telse\n+\t\torig_head=$(cat \"$state_dir\"/head)\n+\tfi &&\n+\tGIT_QUIET=$(cat \"$state_dir\"/quiet) &&\n+\ttest -f \"$state_dir\"/verbose && verbose=t\n+\ttest -f \"$state_dir\"/strategy && strategy=\"$(cat \"$state_dir\"/strategy)\"\n+\ttest -f \"$state_dir\"/strategy_opts &&\n+\t\tstrategy_opts=\"$(cat \"$state_dir\"/strategy_opts)\"\n+\ttest -f \"$state_dir\"/allow_rerere_autoupdate &&\n+\t\tallow_rerere_autoupdate=\"$(cat \"$state_dir\"/allow_rerere_autoupdate)\"\n+\ttest -f \"$state_dir\"/gpg_sign_opt &&\n+\t\tgpg_sign_opt=\"$(cat \"$state_dir\"/gpg_sign_opt)\"\n+\ttest -f \"$state_dir\"/signoff && {\n+\t\tsignoff=\"$(cat \"$state_dir\"/signoff)\"\n+\t\tforce_rebase=t\n+\t}\n+}\n+\n+write_basic_state () {\n+\techo \"$head_name\" > \"$state_dir\"/head-name &&\n+\techo \"$onto\" > \"$state_dir\"/onto &&\n+\techo \"$orig_head\" > \"$state_dir\"/orig-head &&\n+\techo \"$GIT_QUIET\" > \"$state_dir\"/quiet &&\n+\ttest t = \"$verbose\" && : > \"$state_dir\"/verbose\n+\ttest -n \"$strategy\" && echo \"$strategy\" > \"$state_dir\"/strategy\n+\ttest -n \"$strategy_opts\" && echo \"$strategy_opts\" > \\\n+\t\t\"$state_dir\"/strategy_opts\n+\ttest -n \"$allow_rerere_autoupdate\" && echo \"$allow_rerere_autoupdate\" > \\\n+\t\t\"$state_dir\"/allow_rerere_autoupdate\n+\ttest -n \"$gpg_sign_opt\" && echo \"$gpg_sign_opt\" > \"$state_dir\"/gpg_sign_opt\n+\ttest -n \"$signoff\" && echo \"$signoff\" >\"$state_dir\"/signoff\n+}\n+\n+output () {\n+\tcase \"$verbose\" in\n+\t'')\n+\t\toutput=$(\"$@\" 2>&1 )\n+\t\tstatus=$?\n+\t\ttest $status != 0 && printf \"%s\\n\" \"$output\"\n+\t\treturn $status\n+\t\t;;\n+\t*)\n+\t\t\"$@\"\n+\t\t;;\n+\tesac\n+}\n+\n+move_to_original_branch () {\n+\tcase \"$head_name\" in\n+\trefs/*)\n+\t\tmessage=\"rebase finished: $head_name onto $onto\"\n+\t\tgit update-ref -m \"$message\" \\\n+\t\t\t$head_name $(git rev-parse HEAD) $orig_head &&\n+\t\tgit symbolic-ref \\\n+\t\t\t-m \"rebase finished: returning to $head_name\" \\\n+\t\t\tHEAD $head_name ||\n+\t\tdie \"$(eval_gettext \"Could not move back to \\$head_name\")\"\n+\t\t;;\n+\tesac\n+}\n+\n+apply_autostash () {\n+\tif test -f \"$state_dir/autostash\"\n+\tthen\n+\t\tstash_sha1=$(cat \"$state_dir/autostash\")\n+\t\tif git stash apply $stash_sha1 >/dev/null 2>&1\n+\t\tthen\n+\t\t\techo \"$(gettext 'Applied autostash.')\" >&2\n+\t\telse\n+\t\t\tgit stash store -m \"autostash\" -q $stash_sha1 ||\n+\t\t\tdie \"$(eval_gettext \"Cannot store \\$stash_sha1\")\"\n+\t\t\tgettext 'Applying autostash resulted in conflicts.\n+Your changes are safe in the stash.\n+You can run \"git stash pop\" or \"git stash drop\" at any time.\n+' >&2\n+\t\tfi\n+\tfi\n+}\n+\n+finish_rebase () {\n+\trm -f \"$(git rev-parse --git-path REBASE_HEAD)\"\n+\tapply_autostash &&\n+\t{ git gc --auto || true; } &&\n+\trm -rf \"$state_dir\"\n+}\n+\n+run_specific_rebase () {\n+\tif [ \"$interactive_rebase\" = implied ]; then\n+\t\tGIT_EDITOR=:\n+\t\texport GIT_EDITOR\n+\t\tautosquash=\n+\tfi\n+\t. git-rebase--$type\n+\n+\tif test -z \"$preserve_merges\"\n+\tthen\n+\t\tgit_rebase__$type\n+\telse\n+\t\tgit_rebase__preserve_merges\n+\tfi\n+\n+\tret=$?\n+\tif test $ret -eq 0\n+\tthen\n+\t\tfinish_rebase\n+\telif test $ret -eq 2 # special exit status for rebase -i\n+\tthen\n+\t\tapply_autostash &&\n+\t\trm -rf \"$state_dir\" &&\n+\t\tdie \"Nothing to do\"\n+\tfi\n+\texit $ret\n+}\n+\n+run_pre_rebase_hook () {\n+\tif test -z \"$ok_to_skip_pre_rebase\" &&\n+\t   test -x \"$(git rev-parse --git-path hooks/pre-rebase)\"\n+\tthen\n+\t\t\"$(git rev-parse --git-path hooks/pre-rebase)\" ${1+\"$@\"} ||\n+\t\tdie \"$(gettext \"The pre-rebase hook refused to rebase.\")\"\n+\tfi\n+}\n+\n+test -f \"$apply_dir\"/applying &&\n+\tdie \"$(gettext \"It looks like 'git am' is in progress. Cannot rebase.\")\"\n+\n+if test -d \"$apply_dir\"\n+then\n+\ttype=am\n+\tstate_dir=\"$apply_dir\"\n+elif test -d \"$merge_dir\"\n+then\n+\tif test -d \"$merge_dir\"/rewritten\n+\tthen\n+\t\ttype=preserve-merges\n+\t\tinteractive_rebase=explicit\n+\t\tpreserve_merges=t\n+\telif test -f \"$merge_dir\"/interactive\n+\tthen\n+\t\ttype=interactive\n+\t\tinteractive_rebase=explicit\n+\telse\n+\t\ttype=merge\n+\tfi\n+\tstate_dir=\"$merge_dir\"\n+fi\n+test -n \"$type\" && in_progress=t\n+\n+total_argc=$#\n+while test $# != 0\n+do\n+\tcase \"$1\" in\n+\t--no-verify)\n+\t\tok_to_skip_pre_rebase=yes\n+\t\t;;\n+\t--verify)\n+\t\tok_to_skip_pre_rebase=\n+\t\t;;\n+\t--continue|--skip|--abort|--quit|--edit-todo|--show-current-patch)\n+\t\ttest $total_argc -eq 2 || usage\n+\t\taction=${1##--}\n+\t\t;;\n+\t--onto=*)\n+\t\tonto=\"${1#--onto=}\"\n+\t\t;;\n+\t--exec=*)\n+\t\tcmd=\"${cmd}exec ${1#--exec=}${LF}\"\n+\t\ttest -z \"$interactive_rebase\" && interactive_rebase=implied\n+\t\t;;\n+\t--interactive)\n+\t\tinteractive_rebase=explicit\n+\t\t;;\n+\t--keep-empty)\n+\t\tkeep_empty=yes\n+\t\t;;\n+\t--allow-empty-message)\n+\t\tallow_empty_message=--allow-empty-message\n+\t\t;;\n+\t--no-keep-empty)\n+\t\tkeep_empty=\n+\t\t;;\n+\t--rebase-merges)\n+\t\trebase_merges=t\n+\t\ttest -z \"$interactive_rebase\" && interactive_rebase=implied\n+\t\t;;\n+\t--rebase-merges=*)\n+\t\trebase_merges=t\n+\t\tcase \"${1#*=}\" in\n+\t\trebase-cousins) rebase_cousins=t;;\n+\t\tno-rebase-cousins) rebase_cousins=;;\n+\t\t*) die \"Unknown mode: $1\";;\n+\t\tesac\n+\t\ttest -z \"$interactive_rebase\" && interactive_rebase=implied\n+\t\t;;\n+\t--preserve-merges)\n+\t\tpreserve_merges=t\n+\t\ttest -z \"$interactive_rebase\" && interactive_rebase=implied\n+\t\t;;\n+\t--autosquash)\n+\t\tautosquash=t\n+\t\t;;\n+\t--no-autosquash)\n+\t\tautosquash=\n+\t\t;;\n+\t--fork-point)\n+\t\tfork_point=t\n+\t\t;;\n+\t--no-fork-point)\n+\t\tfork_point=\n+\t\t;;\n+\t--merge)\n+\t\tdo_merge=t\n+\t\t;;\n+\t--strategy-option=*)\n+\t\tstrategy_opts=\"$strategy_opts $(git rev-parse --sq-quote \"--${1#--strategy-option=}\")\"\n+\t\tdo_merge=t\n+\t\ttest -z \"$strategy\" && strategy=recursive\n+\t\t;;\n+\t--strategy=*)\n+\t\tstrategy=\"${1#--strategy=}\"\n+\t\tdo_merge=t\n+\t\t;;\n+\t--no-stat)\n+\t\tdiffstat=\n+\t\t;;\n+\t--stat)\n+\t\tdiffstat=t\n+\t\t;;\n+\t--autostash)\n+\t\tautostash=true\n+\t\t;;\n+\t--no-autostash)\n+\t\tautostash=false\n+\t\t;;\n+\t--verbose)\n+\t\tverbose=t\n+\t\tdiffstat=t\n+\t\tGIT_QUIET=\n+\t\t;;\n+\t--quiet)\n+\t\tGIT_QUIET=t\n+\t\tgit_am_opt=\"$git_am_opt -q\"\n+\t\tverbose=\n+\t\tdiffstat=\n+\t\t;;\n+\t--whitespace=*)\n+\t\tgit_am_opt=\"$git_am_opt --whitespace=${1#--whitespace=}\"\n+\t\tcase \"${1#--whitespace=}\" in\n+\t\tfix|strip)\n+\t\t\tforce_rebase=t\n+\t\t\t;;\n+\t\tesac\n+\t\t;;\n+\t--ignore-whitespace)\n+\t\tgit_am_opt=\"$git_am_opt $1\"\n+\t\t;;\n+\t--signoff)\n+\t\tsignoff=--signoff\n+\t\t;;\n+\t--no-signoff)\n+\t\tsignoff=\n+\t\t;;\n+\t--committer-date-is-author-date|--ignore-date)\n+\t\tgit_am_opt=\"$git_am_opt $1\"\n+\t\tforce_rebase=t\n+\t\t;;\n+\t-C*)\n+\t\tgit_am_opt=\"$git_am_opt $1\"\n+\t\t;;\n+\t--root)\n+\t\trebase_root=t\n+\t\t;;\n+\t--force-rebase|--no-ff)\n+\t\tforce_rebase=t\n+\t\t;;\n+\t--rerere-autoupdate|--no-rerere-autoupdate)\n+\t\tallow_rerere_autoupdate=\"$1\"\n+\t\t;;\n+\t--gpg-sign)\n+\t\tgpg_sign_opt=-S\n+\t\t;;\n+\t--gpg-sign=*)\n+\t\tgpg_sign_opt=\"-S${1#--gpg-sign=}\"\n+\t\t;;\n+\t--)\n+\t\tshift\n+\t\tbreak\n+\t\t;;\n+\t*)\n+\t\tusage\n+\t\t;;\n+\tesac\n+\tshift\n+done\n+test $# -gt 2 && usage\n+\n+if test -n \"$action\"\n+then\n+\ttest -z \"$in_progress\" && die \"$(gettext \"No rebase in progress?\")\"\n+\t# Only interactive rebase uses detailed reflog messages\n+\tif test -n \"$interactive_rebase\" && test \"$GIT_REFLOG_ACTION\" = rebase\n+\tthen\n+\t\tGIT_REFLOG_ACTION=\"rebase -i ($action)\"\n+\t\texport GIT_REFLOG_ACTION\n+\tfi\n+fi\n+\n+if test \"$action\" = \"edit-todo\" && test -z \"$interactive_rebase\"\n+then\n+\tdie \"$(gettext \"The --edit-todo action can only be used during interactive rebase.\")\"\n+fi\n+\n+case \"$action\" in\n+continue)\n+\t# Sanity check\n+\tgit rev-parse --verify HEAD >/dev/null ||\n+\t\tdie \"$(gettext \"Cannot read HEAD\")\"\n+\tgit update-index --ignore-submodules --refresh &&\n+\tgit diff-files --quiet --ignore-submodules || {\n+\t\techo \"$(gettext \"You must edit all merge conflicts and then\n+mark them as resolved using git add\")\"\n+\t\texit 1\n+\t}\n+\tread_basic_state\n+\trun_specific_rebase\n+\t;;\n+skip)\n+\toutput git reset --hard HEAD || exit $?\n+\tread_basic_state\n+\trun_specific_rebase\n+\t;;\n+abort)\n+\tgit rerere clear\n+\tread_basic_state\n+\tcase \"$head_name\" in\n+\trefs/*)\n+\t\tgit symbolic-ref -m \"rebase: aborting\" HEAD $head_name ||\n+\t\tdie \"$(eval_gettext \"Could not move back to \\$head_name\")\"\n+\t\t;;\n+\tesac\n+\toutput git reset --hard $orig_head\n+\tfinish_rebase\n+\texit\n+\t;;\n+quit)\n+\texec rm -rf \"$state_dir\"\n+\t;;\n+edit-todo)\n+\trun_specific_rebase\n+\t;;\n+show-current-patch)\n+\trun_specific_rebase\n+\tdie \"BUG: run_specific_rebase is not supposed to return here\"\n+\t;;\n+esac\n+\n+# Make sure no rebase is in progress\n+if test -n \"$in_progress\"\n+then\n+\tstate_dir_base=${state_dir##*/}\n+\tcmd_live_rebase=\"git rebase (--continue | --abort | --skip)\"\n+\tcmd_clear_stale_rebase=\"rm -fr \\\"$state_dir\\\"\"\n+\tdie \"\n+$(eval_gettext 'It seems that there is already a $state_dir_base directory, and\n+I wonder if you are in the middle of another rebase.  If that is the\n+case, please try\n+\t$cmd_live_rebase\n+If that is not the case, please\n+\t$cmd_clear_stale_rebase\n+and run me again.  I am stopping in case you still have something\n+valuable there.')\"\n+fi\n+\n+if test -n \"$rebase_root\" && test -z \"$onto\"\n+then\n+\ttest -z \"$interactive_rebase\" && interactive_rebase=implied\n+fi\n+\n+if test -n \"$keep_empty\"\n+then\n+\ttest -z \"$interactive_rebase\" && interactive_rebase=implied\n+fi\n+\n+if test -n \"$interactive_rebase\"\n+then\n+\tif test -z \"$preserve_merges\"\n+\tthen\n+\t\ttype=interactive\n+\telse\n+\t\ttype=preserve-merges\n+\tfi\n+\n+\tstate_dir=\"$merge_dir\"\n+elif test -n \"$do_merge\"\n+then\n+\ttype=merge\n+\tstate_dir=\"$merge_dir\"\n+else\n+\ttype=am\n+\tstate_dir=\"$apply_dir\"\n+fi\n+\n+if test -t 2 && test -z \"$GIT_QUIET\"\n+then\n+\tgit_format_patch_opt=\"$git_format_patch_opt --progress\"\n+fi\n+\n+if test -n \"$signoff\"\n+then\n+\ttest -n \"$preserve_merges\" &&\n+\t\tdie \"$(gettext \"error: cannot combine '--signoff' with '--preserve-merges'\")\"\n+\tgit_am_opt=\"$git_am_opt $signoff\"\n+\tforce_rebase=t\n+fi\n+\n+if test -z \"$rebase_root\"\n+then\n+\tcase \"$#\" in\n+\t0)\n+\t\tif ! upstream_name=$(git rev-parse --symbolic-full-name \\\n+\t\t\t--verify -q @{upstream} 2>/dev/null)\n+\t\tthen\n+\t\t\t. git-parse-remote\n+\t\t\terror_on_missing_default_upstream \"rebase\" \"rebase\" \\\n+\t\t\t\t\"against\" \"git rebase $(gettext '<branch>')\"\n+\t\tfi\n+\n+\t\ttest \"$fork_point\" = auto && fork_point=t\n+\t\t;;\n+\t*)\tupstream_name=\"$1\"\n+\t\tif test \"$upstream_name\" = \"-\"\n+\t\tthen\n+\t\t\tupstream_name=\"@{-1}\"\n+\t\tfi\n+\t\tshift\n+\t\t;;\n+\tesac\n+\tupstream=$(peel_committish \"${upstream_name}\") ||\n+\tdie \"$(eval_gettext \"invalid upstream '\\$upstream_name'\")\"\n+\tupstream_arg=\"$upstream_name\"\n+else\n+\tif test -z \"$onto\"\n+\tthen\n+\t\tempty_tree=$(git hash-object -t tree /dev/null)\n+\t\tonto=$(git commit-tree $empty_tree </dev/null)\n+\t\tsquash_onto=\"$onto\"\n+\tfi\n+\tunset upstream_name\n+\tunset upstream\n+\ttest $# -gt 1 && usage\n+\tupstream_arg=--root\n+fi\n+\n+# Make sure the branch to rebase onto is valid.\n+onto_name=${onto-\"$upstream_name\"}\n+case \"$onto_name\" in\n+*...*)\n+\tif\tleft=${onto_name%...*} right=${onto_name#*...} &&\n+\t\tonto=$(git merge-base --all ${left:-HEAD} ${right:-HEAD})\n+\tthen\n+\t\tcase \"$onto\" in\n+\t\t?*\"$LF\"?*)\n+\t\t\tdie \"$(eval_gettext \"\\$onto_name: there are more than one merge bases\")\"\n+\t\t\t;;\n+\t\t'')\n+\t\t\tdie \"$(eval_gettext \"\\$onto_name: there is no merge base\")\"\n+\t\t\t;;\n+\t\tesac\n+\telse\n+\t\tdie \"$(eval_gettext \"\\$onto_name: there is no merge base\")\"\n+\tfi\n+\t;;\n+*)\n+\tonto=$(peel_committish \"$onto_name\") ||\n+\tdie \"$(eval_gettext \"Does not point to a valid commit: \\$onto_name\")\"\n+\t;;\n+esac\n+\n+# If the branch to rebase is given, that is the branch we will rebase\n+# $branch_name -- branch/commit being rebased, or HEAD (already detached)\n+# $orig_head -- commit object name of tip of the branch before rebasing\n+# $head_name -- refs/heads/<that-branch> or \"detached HEAD\"\n+switch_to=\n+case \"$#\" in\n+1)\n+\t# Is it \"rebase other $branchname\" or \"rebase other $commit\"?\n+\tbranch_name=\"$1\"\n+\tswitch_to=\"$1\"\n+\n+\t# Is it a local branch?\n+\tif git show-ref --verify --quiet -- \"refs/heads/$branch_name\" &&\n+\t   orig_head=$(git rev-parse -q --verify \"refs/heads/$branch_name\")\n+\tthen\n+\t\thead_name=\"refs/heads/$branch_name\"\n+\t# If not is it a valid ref (branch or commit)?\n+\telif orig_head=$(git rev-parse -q --verify \"$branch_name\")\n+\tthen\n+\t\thead_name=\"detached HEAD\"\n+\n+\telse\n+\t\tdie \"$(eval_gettext \"fatal: no such branch/commit '\\$branch_name'\")\"\n+\tfi\n+\t;;\n+0)\n+\t# Do not need to switch branches, we are already on it.\n+\tif branch_name=$(git symbolic-ref -q HEAD)\n+\tthen\n+\t\thead_name=$branch_name\n+\t\tbranch_name=$(expr \"z$branch_name\" : 'zrefs/heads/\\(.*\\)')\n+\telse\n+\t\thead_name=\"detached HEAD\"\n+\t\tbranch_name=HEAD\n+\tfi\n+\torig_head=$(git rev-parse --verify HEAD) || exit\n+\t;;\n+*)\n+\tdie \"BUG: unexpected number of arguments left to parse\"\n+\t;;\n+esac\n+\n+if test \"$fork_point\" = t\n+then\n+\tnew_upstream=$(git merge-base --fork-point \"$upstream_name\" \\\n+\t\t\t\"${switch_to:-HEAD}\")\n+\tif test -n \"$new_upstream\"\n+\tthen\n+\t\trestrict_revision=$new_upstream\n+\tfi\n+fi\n+\n+if test \"$autostash\" = true && ! (require_clean_work_tree) 2>/dev/null\n+then\n+\tstash_sha1=$(git stash create \"autostash\") ||\n+\tdie \"$(gettext 'Cannot autostash')\"\n+\n+\tmkdir -p \"$state_dir\" &&\n+\techo $stash_sha1 >\"$state_dir/autostash\" &&\n+\tstash_abbrev=$(git rev-parse --short $stash_sha1) &&\n+\techo \"$(eval_gettext 'Created autostash: $stash_abbrev')\" &&\n+\tgit reset --hard\n+fi\n+\n+require_clean_work_tree \"rebase\" \"$(gettext \"Please commit or stash them.\")\"\n+\n+# Now we are rebasing commits $upstream..$orig_head (or with --root,\n+# everything leading up to $orig_head) on top of $onto\n+\n+# Check if we are already based on $onto with linear history,\n+# but this should be done only when upstream and onto are the same\n+# and if this is not an interactive rebase.\n+mb=$(git merge-base \"$onto\" \"$orig_head\")\n+if test -z \"$interactive_rebase\" && test \"$upstream\" = \"$onto\" &&\n+\ttest \"$mb\" = \"$onto\" && test -z \"$restrict_revision\" &&\n+\t# linear history?\n+\t! (git rev-list --parents \"$onto\"..\"$orig_head\" | sane_grep \" .* \") > /dev/null\n+then\n+\tif test -z \"$force_rebase\"\n+\tthen\n+\t\t# Lazily switch to the target branch if needed...\n+\t\ttest -z \"$switch_to\" ||\n+\t\tGIT_REFLOG_ACTION=\"$GIT_REFLOG_ACTION: checkout $switch_to\" \\\n+\t\t\tgit checkout -q \"$switch_to\" --\n+\t\tif test \"$branch_name\" = \"HEAD\" &&\n+\t\t\t ! git symbolic-ref -q HEAD\n+\t\tthen\n+\t\t\tsay \"$(eval_gettext \"HEAD is up to date.\")\"\n+\t\telse\n+\t\t\tsay \"$(eval_gettext \"Current branch \\$branch_name is up to date.\")\"\n+\t\tfi\n+\t\tfinish_rebase\n+\t\texit 0\n+\telse\n+\t\tif test \"$branch_name\" = \"HEAD\" &&\n+\t\t\t ! git symbolic-ref -q HEAD\n+\t\tthen\n+\t\t\tsay \"$(eval_gettext \"HEAD is up to date, rebase forced.\")\"\n+\t\telse\n+\t\t\tsay \"$(eval_gettext \"Current branch \\$branch_name is up to date, rebase forced.\")\"\n+\t\tfi\n+\tfi\n+fi\n+\n+# If a hook exists, give it a chance to interrupt\n+run_pre_rebase_hook \"$upstream_arg\" \"$@\"\n+\n+if test -n \"$diffstat\"\n+then\n+\tif test -n \"$verbose\"\n+\tthen\n+\t\techo \"$(eval_gettext \"Changes from \\$mb to \\$onto:\")\"\n+\tfi\n+\t# We want color (if set), but no pager\n+\tGIT_PAGER='' git diff --stat --summary \"$mb\" \"$onto\"\n+fi\n+\n+test -n \"$interactive_rebase\" && run_specific_rebase\n+\n+# Detach HEAD and reset the tree\n+say \"$(gettext \"First, rewinding head to replay your work on top of it...\")\"\n+\n+GIT_REFLOG_ACTION=\"$GIT_REFLOG_ACTION: checkout $onto_name\" \\\n+\tgit checkout -q \"$onto^0\" || die \"could not detach HEAD\"\n+git update-ref ORIG_HEAD $orig_head\n+\n+# If the $onto is a proper descendant of the tip of the branch, then\n+# we just fast-forwarded.\n+if test \"$mb\" = \"$orig_head\"\n+then\n+\tsay \"$(eval_gettext \"Fast-forwarded \\$branch_name to \\$onto_name.\")\"\n+\tmove_to_original_branch\n+\tfinish_rebase\n+\texit 0\n+fi\n+\n+if test -n \"$rebase_root\"\n+then\n+\trevisions=\"$onto..$orig_head\"\n+else\n+\trevisions=\"${restrict_revision-$upstream}..$orig_head\"\n+fi\n+\n+run_specific_rebase\n-- \n2.18.0\n\n"},{"id":"351186","messageId":"20180628074655.5756-3-predatoramigo@gmail.com","threadId":"48795","inReplyTo":"20180628074655.5756-1-predatoramigo@gmail.com","subject":"[PATCH 2/5] rebase: start implementing it as a builtin","fromName":"Pratik Karki","fromEmail":"predatoramigo@gmail.com","sentAt":"2018-06-28T07:46:52Z","receivedAt":"2018-06-28T07:48:35Z","isPatch":true,"sender":{"key":"predatoramigo@gmail.com","avatar":"https://avatars.githubusercontent.com/u/12194950?v=4"},"body":"This commit imitates the strategy that was used to convert the\ndifftool to a builtin, see be8a90e (difftool: add a skeleton for the\nupcoming builtin, 2017-01-17) for details: This commit renames the\nshell script `git-rebase.sh` to `git-legacy-rebase.sh` and hands off to\nit by default.\n\nThe current version of the builtin rebase does not, however, make full\nuse of the internals but instead chooses to spawn a couple of Git\nprocesses to find out if we run the builtin or legacy rebase as that\nkeeps the directory that we are in correct. There remains a lot\nof room for improvement, left for a later date. The following commits\nwill recreate the functionality of the shell script, in pure C.\n\nWe intentionally avoid reading the config directly to avoid\nmessing up the GIT_* environment variables when we need to fall back to\nexec()ing the shell script. The test of builtin rebase can be done by\n`git -c rebase.useBuiltin=true rebase ...`\n\nSigned-off-by: Pratik Karki <predatoramigo@gmail.com>\n---\n .gitignore                            |  1 +\n Makefile                              |  3 +-\n builtin.h                             |  1 +\n builtin/rebase.c                      | 55 +++++++++++++++++++++++++++\n git-rebase.sh => git-legacy-rebase.sh |  0\n git.c                                 |  6 +++\n 6 files changed, 65 insertions(+), 1 deletion(-)\n create mode 100644 builtin/rebase.c\n rename git-rebase.sh => git-legacy-rebase.sh (100%)\n\ndiff --git a/.gitignore b/.gitignore\nindex 3284a1e9b..ec2395901 100644\n--- a/.gitignore\n+++ b/.gitignore\n@@ -78,6 +78,7 @@\n /git-init-db\n /git-interpret-trailers\n /git-instaweb\n+/git-legacy-rebase\n /git-log\n /git-ls-files\n /git-ls-remote\ndiff --git a/Makefile b/Makefile\nindex 0cb6590f2..e88fe2e5f 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -609,7 +609,7 @@ SCRIPT_SH += git-merge-one-file.sh\n SCRIPT_SH += git-merge-resolve.sh\n SCRIPT_SH += git-mergetool.sh\n SCRIPT_SH += git-quiltimport.sh\n-SCRIPT_SH += git-rebase.sh\n+SCRIPT_SH += git-legacy-rebase.sh\n SCRIPT_SH += git-remote-testgit.sh\n SCRIPT_SH += git-request-pull.sh\n SCRIPT_SH += git-stash.sh\n@@ -1059,6 +1059,7 @@ BUILTIN_OBJS += builtin/prune.o\n BUILTIN_OBJS += builtin/pull.o\n BUILTIN_OBJS += builtin/push.o\n BUILTIN_OBJS += builtin/read-tree.o\n+BUILTIN_OBJS += builtin/rebase.o\n BUILTIN_OBJS += builtin/rebase--helper.o\n BUILTIN_OBJS += builtin/receive-pack.o\n BUILTIN_OBJS += builtin/reflog.o\ndiff --git a/builtin.h b/builtin.h\nindex 0362f1ce2..44651a447 100644\n--- a/builtin.h\n+++ b/builtin.h\n@@ -202,6 +202,7 @@ extern int cmd_prune_packed(int argc, const char **argv, const char *prefix);\n extern int cmd_pull(int argc, const char **argv, const char *prefix);\n extern int cmd_push(int argc, const char **argv, const char *prefix);\n extern int cmd_read_tree(int argc, const char **argv, const char *prefix);\n+extern int cmd_rebase(int argc, const char **argv, const char *prefix);\n extern int cmd_rebase__helper(int argc, const char **argv, const char *prefix);\n extern int cmd_receive_pack(int argc, const char **argv, const char *prefix);\n extern int cmd_reflog(int argc, const char **argv, const char *prefix);\ndiff --git a/builtin/rebase.c b/builtin/rebase.c\nnew file mode 100644\nindex 000000000..1152b7229\n--- /dev/null\n+++ b/builtin/rebase.c\n@@ -0,0 +1,55 @@\n+/*\n+ * \"git rebase\" builtin command\n+ *\n+ * Copyright (c) 2018 Pratik Karki\n+ */\n+\n+#include \"builtin.h\"\n+#include \"run-command.h\"\n+#include \"exec-cmd.h\"\n+#include \"argv-array.h\"\n+#include \"dir.h\"\n+\n+static int use_builtin_rebase(void)\n+{\n+\tstruct child_process cp = CHILD_PROCESS_INIT;\n+\tstruct strbuf out = STRBUF_INIT;\n+\tint ret;\n+\n+\targv_array_pushl(&cp.args,\n+\t\t\t \"config\", \"--bool\", \"rebase.usebuiltin\", NULL);\n+\tcp.git_cmd = 1;\n+\tif (capture_command(&cp, &out, 6))\n+\t\treturn 0;\n+\n+\tstrbuf_trim(&out);\n+\tret = !strcmp(\"true\", out.buf);\n+\tstrbuf_release(&out);\n+\treturn ret;\n+}\n+\n+int cmd_rebase(int argc, const char **argv, const char *prefix)\n+{\n+\t/*\n+\t* NEEDSWORK: Once the builtin rebase has been tested enough\n+\t* and git-legacy-rebase.sh is retired to contrib/, this preamble\n+\t* can be removed.\n+\t*/\n+\tif (!use_builtin_rebase()) {\n+\t\tconst char *path = mkpath(\"%s/git-legacy-rebase\",\n+\t\t\t\t\t  git_exec_path());\n+\n+\t\tif (sane_execvp(path, (char **)argv) < 0)\n+\t\t\tdie_errno(\"could not exec %s\", path);\n+\n+\t\treturn 0;\n+\t}\n+\n+\tif (argc != 2)\n+\t\tdie(\"Usage: %s <base>\", argv[0]);\n+\tprefix = setup_git_directory();\n+\ttrace_repo_setup(prefix);\n+\tsetup_work_tree();\n+\n+\tdie(\"TODO\");\n+}\n\\ No newline at end of file\ndiff --git a/git-rebase.sh b/git-legacy-rebase.sh\nsimilarity index 100%\nrename from git-rebase.sh\nrename to git-legacy-rebase.sh\ndiff --git a/git.c b/git.c\nindex 9dbe6ffaa..bacfefb2d 100644\n--- a/git.c\n+++ b/git.c\n@@ -518,6 +518,12 @@ static struct cmd_struct commands[] = {\n \t{ \"pull\", cmd_pull, RUN_SETUP | NEED_WORK_TREE },\n \t{ \"push\", cmd_push, RUN_SETUP },\n \t{ \"read-tree\", cmd_read_tree, RUN_SETUP | SUPPORT_SUPER_PREFIX},\n+\t/*\n+\t *NEEDSWORK: Until the rebase is independent and needs no redirection\n+\t to rebase shell script this is kept as is, then should be changed to\n+\t RUN_SETUP | NEED_WORK_TREE\n+\t*/\n+\t{ \"rebase\", cmd_rebase },\n \t{ \"rebase--helper\", cmd_rebase__helper, RUN_SETUP | NEED_WORK_TREE },\n \t{ \"receive-pack\", cmd_receive_pack },\n \t{ \"reflog\", cmd_reflog, RUN_SETUP },\n-- \n2.18.0\n\n"},{"id":"351187","messageId":"20180628074655.5756-4-predatoramigo@gmail.com","threadId":"48795","inReplyTo":"20180628074655.5756-1-predatoramigo@gmail.com","subject":"[PATCH 3/5] rebase: refactor common shell functions into their own file","fromName":"Pratik Karki","fromEmail":"predatoramigo@gmail.com","sentAt":"2018-06-28T07:46:53Z","receivedAt":"2018-06-28T07:48:39Z","isPatch":true,"sender":{"key":"predatoramigo@gmail.com","avatar":"https://avatars.githubusercontent.com/u/12194950?v=4"},"body":"The function present in `git-legacy-rebase.sh` are used by backends\nso, this refactor tries to extract the functions out so that, the\n`git-legacy-rebase.sh` can be retired easily as the\n`git-rebase--common.sh` will provide the functions for now.\n\nThe motivation behind this is to call the backend functions\n*directly* from C, bypassing `git-rebase.sh`. Therefore those functions\nneed to live in a separate file: we need to be able to call\n`.git-rebase--common` in that script snippet so that those functions\nare defined.\n\nSigned-off-by: Pratik Karki <predatoramigo@gmail.com>\n---\n .gitignore            |  1 +\n Makefile              |  1 +\n git-legacy-rebase.sh  | 62 +------------------------------------------\n git-rebase--common.sh | 61 ++++++++++++++++++++++++++++++++++++++++++\n 4 files changed, 64 insertions(+), 61 deletions(-)\n create mode 100644 git-rebase--common.sh\n\ndiff --git a/.gitignore b/.gitignore\nindex ec2395901..824141cba 100644\n--- a/.gitignore\n+++ b/.gitignore\n@@ -117,6 +117,7 @@\n /git-read-tree\n /git-rebase\n /git-rebase--am\n+/git-rebase--common\n /git-rebase--helper\n /git-rebase--interactive\n /git-rebase--merge\ndiff --git a/Makefile b/Makefile\nindex e88fe2e5f..163e52ad1 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -619,6 +619,7 @@ SCRIPT_SH += git-web--browse.sh\n SCRIPT_LIB += git-mergetool--lib\n SCRIPT_LIB += git-parse-remote\n SCRIPT_LIB += git-rebase--am\n+SCRIPT_LIB += git-rebase--common\n SCRIPT_LIB += git-rebase--interactive\n SCRIPT_LIB += git-rebase--preserve-merges\n SCRIPT_LIB += git-rebase--merge\ndiff --git a/git-legacy-rebase.sh b/git-legacy-rebase.sh\nindex 19bdebb48..240aac507 100755\n--- a/git-legacy-rebase.sh\n+++ b/git-legacy-rebase.sh\n@@ -102,6 +102,7 @@ case \"$(git config --bool commit.gpgsign)\" in\n true)\tgpg_sign_opt=-S ;;\n *)\tgpg_sign_opt= ;;\n esac\n+. git-rebase--common\n \n read_basic_state () {\n \ttest -f \"$state_dir/head-name\" &&\n@@ -132,67 +133,6 @@ read_basic_state () {\n \t}\n }\n \n-write_basic_state () {\n-\techo \"$head_name\" > \"$state_dir\"/head-name &&\n-\techo \"$onto\" > \"$state_dir\"/onto &&\n-\techo \"$orig_head\" > \"$state_dir\"/orig-head &&\n-\techo \"$GIT_QUIET\" > \"$state_dir\"/quiet &&\n-\ttest t = \"$verbose\" && : > \"$state_dir\"/verbose\n-\ttest -n \"$strategy\" && echo \"$strategy\" > \"$state_dir\"/strategy\n-\ttest -n \"$strategy_opts\" && echo \"$strategy_opts\" > \\\n-\t\t\"$state_dir\"/strategy_opts\n-\ttest -n \"$allow_rerere_autoupdate\" && echo \"$allow_rerere_autoupdate\" > \\\n-\t\t\"$state_dir\"/allow_rerere_autoupdate\n-\ttest -n \"$gpg_sign_opt\" && echo \"$gpg_sign_opt\" > \"$state_dir\"/gpg_sign_opt\n-\ttest -n \"$signoff\" && echo \"$signoff\" >\"$state_dir\"/signoff\n-}\n-\n-output () {\n-\tcase \"$verbose\" in\n-\t'')\n-\t\toutput=$(\"$@\" 2>&1 )\n-\t\tstatus=$?\n-\t\ttest $status != 0 && printf \"%s\\n\" \"$output\"\n-\t\treturn $status\n-\t\t;;\n-\t*)\n-\t\t\"$@\"\n-\t\t;;\n-\tesac\n-}\n-\n-move_to_original_branch () {\n-\tcase \"$head_name\" in\n-\trefs/*)\n-\t\tmessage=\"rebase finished: $head_name onto $onto\"\n-\t\tgit update-ref -m \"$message\" \\\n-\t\t\t$head_name $(git rev-parse HEAD) $orig_head &&\n-\t\tgit symbolic-ref \\\n-\t\t\t-m \"rebase finished: returning to $head_name\" \\\n-\t\t\tHEAD $head_name ||\n-\t\tdie \"$(eval_gettext \"Could not move back to \\$head_name\")\"\n-\t\t;;\n-\tesac\n-}\n-\n-apply_autostash () {\n-\tif test -f \"$state_dir/autostash\"\n-\tthen\n-\t\tstash_sha1=$(cat \"$state_dir/autostash\")\n-\t\tif git stash apply $stash_sha1 >/dev/null 2>&1\n-\t\tthen\n-\t\t\techo \"$(gettext 'Applied autostash.')\" >&2\n-\t\telse\n-\t\t\tgit stash store -m \"autostash\" -q $stash_sha1 ||\n-\t\t\tdie \"$(eval_gettext \"Cannot store \\$stash_sha1\")\"\n-\t\t\tgettext 'Applying autostash resulted in conflicts.\n-Your changes are safe in the stash.\n-You can run \"git stash pop\" or \"git stash drop\" at any time.\n-' >&2\n-\t\tfi\n-\tfi\n-}\n-\n finish_rebase () {\n \trm -f \"$(git rev-parse --git-path REBASE_HEAD)\"\n \tapply_autostash &&\ndiff --git a/git-rebase--common.sh b/git-rebase--common.sh\nnew file mode 100644\nindex 000000000..5ba060392\n--- /dev/null\n+++ b/git-rebase--common.sh\n@@ -0,0 +1,61 @@\n+\n+write_basic_state () {\n+\techo \"$head_name\" > \"$state_dir\"/head-name &&\n+\techo \"$onto\" > \"$state_dir\"/onto &&\n+\techo \"$orig_head\" > \"$state_dir\"/orig-head &&\n+\techo \"$GIT_QUIET\" > \"$state_dir\"/quiet &&\n+\ttest t = \"$verbose\" && : > \"$state_dir\"/verbose\n+\ttest -n \"$strategy\" && echo \"$strategy\" > \"$state_dir\"/strategy\n+\ttest -n \"$strategy_opts\" && echo \"$strategy_opts\" > \\\n+\t\t\"$state_dir\"/strategy_opts\n+\ttest -n \"$allow_rerere_autoupdate\" && echo \"$allow_rerere_autoupdate\" > \\\n+\t\t\"$state_dir\"/allow_rerere_autoupdate\n+\ttest -n \"$gpg_sign_opt\" && echo \"$gpg_sign_opt\" > \"$state_dir\"/gpg_sign_opt\n+\ttest -n \"$signoff\" && echo \"$signoff\" >\"$state_dir\"/signoff\n+}\n+\n+apply_autostash () {\n+\tif test -f \"$state_dir/autostash\"\n+\tthen\n+\t\tstash_sha1=$(cat \"$state_dir/autostash\")\n+\t\tif git stash apply $stash_sha1 >/dev/null 2>&1\n+\t\tthen\n+\t\t\techo \"$(gettext 'Applied autostash.')\" >&2\n+\t\telse\n+\t\t\tgit stash store -m \"autostash\" -q $stash_sha1 ||\n+\t\t\tdie \"$(eval_gettext \"Cannot store \\$stash_sha1\")\"\n+\t\t\tgettext 'Applying autostash resulted in conflicts.\n+Your changes are safe in the stash.\n+You can run \"git stash pop\" or \"git stash drop\" at any time.\n+' >&2\n+\t\tfi\n+\tfi\n+}\n+\n+move_to_original_branch () {\n+\tcase \"$head_name\" in\n+\trefs/*)\n+\t\tmessage=\"rebase finished: $head_name onto $onto\"\n+\t\tgit update-ref -m \"$message\" \\\n+\t\t\t$head_name $(git rev-parse HEAD) $orig_head &&\n+\t\tgit symbolic-ref \\\n+\t\t\t-m \"rebase finished: returning to $head_name\" \\\n+\t\t\tHEAD $head_name ||\n+\t\tdie \"$(eval_gettext \"Could not move back to \\$head_name\")\"\n+\t\t;;\n+\tesac\n+}\n+\n+output () {\n+\tcase \"$verbose\" in\n+\t'')\n+\t\toutput=$(\"$@\" 2>&1 )\n+\t\tstatus=$?\n+\t\ttest $status != 0 && printf \"%s\\n\" \"$output\"\n+\t\treturn $status\n+\t\t;;\n+\t*)\n+\t\t\"$@\"\n+\t\t;;\n+\tesac\n+}\n-- \n2.18.0\n\n"},{"id":"351188","messageId":"20180628074655.5756-5-predatoramigo@gmail.com","threadId":"48795","inReplyTo":"20180628074655.5756-1-predatoramigo@gmail.com","subject":"[PATCH 4/5] sequencer: refactor the code to detach HEAD to checkout.c","fromName":"Pratik Karki","fromEmail":"predatoramigo@gmail.com","sentAt":"2018-06-28T07:46:54Z","receivedAt":"2018-06-28T07:48:41Z","isPatch":true,"sender":{"key":"predatoramigo@gmail.com","avatar":"https://avatars.githubusercontent.com/u/12194950?v=4"},"body":"The motivation behind this commit is to extract the core part of\ndo_reset() from sequencer.c and move it to a new detach_head_to()\nfunction in checkout.c.\n\nHere the index only gets locked after performing the first part of\n`do_reset()` rather than before which essentially derives the `oid`\nfrom the specified label/name passed to the `do_reset()` function.\nIt also fixes two bugs: there were two `return error()` statements in\nthe `[new root]` case that would have failed to unlock the index.\n\nThe new function will be used in the next commit by the builtin rebase,\nto perform the initial checkout.\n\nSigned-off-by: Pratik Karki <predatoramigo@gmail.com>\n---\n checkout.c  | 64 +++++++++++++++++++++++++++++++++++++++++++++++++++++\n checkout.h  |  3 +++\n sequencer.c | 58 +++++-------------------------------------------\n 3 files changed, 72 insertions(+), 53 deletions(-)\n\ndiff --git a/checkout.c b/checkout.c\nindex bdefc888b..da68915fd 100644\n--- a/checkout.c\n+++ b/checkout.c\n@@ -2,6 +2,11 @@\n #include \"remote.h\"\n #include \"refspec.h\"\n #include \"checkout.h\"\n+#include \"unpack-trees.h\"\n+#include \"lockfile.h\"\n+#include \"refs.h\"\n+#include \"tree.h\"\n+#include \"cache-tree.h\"\n \n struct tracking_name_data {\n \t/* const */ char *src_ref;\n@@ -42,3 +47,62 @@ const char *unique_tracking_name(const char *name, struct object_id *oid)\n \tfree(cb_data.dst_ref);\n \treturn NULL;\n }\n+\n+int detach_head_to(struct object_id *oid, const char *action,\n+\t\t   const char *reflog_message)\n+{\n+\tstruct strbuf ref_name = STRBUF_INIT;\n+\tstruct tree_desc desc;\n+\tstruct lock_file lock = LOCK_INIT;\n+\tstruct unpack_trees_options unpack_tree_opts;\n+\tstruct tree *tree;\n+\tint ret = 0;\n+\n+\tif (hold_locked_index(&lock, LOCK_REPORT_ON_ERROR) < 0)\n+\t\treturn -1;\n+\n+\tmemset(&unpack_tree_opts, 0, sizeof(unpack_tree_opts));\n+\tsetup_unpack_trees_porcelain(&unpack_tree_opts, action);\n+\tunpack_tree_opts.head_idx = 1;\n+\tunpack_tree_opts.src_index = &the_index;\n+\tunpack_tree_opts.dst_index = &the_index;\n+\tunpack_tree_opts.fn = oneway_merge;\n+\tunpack_tree_opts.merge = 1;\n+\tunpack_tree_opts.update = 1;\n+\n+\tif (read_cache_unmerged()) {\n+\t\trollback_lock_file(&lock);\n+\t\tstrbuf_release(&ref_name);\n+\t\treturn error_resolve_conflict(_(action));\n+\t}\n+\n+\tif (!fill_tree_descriptor(&desc, oid)) {\n+\t\terror(_(\"failed to find tree of %s\"), oid_to_hex(oid));\n+\t\trollback_lock_file(&lock);\n+\t\tfree((void *)desc.buffer);\n+\t\tstrbuf_release(&ref_name);\n+\t\treturn -1;\n+\t}\n+\n+\tif (unpack_trees(1, &desc, &unpack_tree_opts)) {\n+\t\trollback_lock_file(&lock);\n+\t\tfree((void *)desc.buffer);\n+\t\tstrbuf_release(&ref_name);\n+\t\treturn -1;\n+\t}\n+\n+\ttree = parse_tree_indirect(oid);\n+\tprime_cache_tree(&the_index, tree);\n+\n+\tif (write_locked_index(&the_index, &lock, COMMIT_LOCK) < 0)\n+\t\tret = error(_(\"could not write index\"));\n+\tfree((void *)desc.buffer);\n+\n+\tif (!ret)\n+\t\tret = update_ref(reflog_message, \"HEAD\", oid,\n+\t\t\t\t NULL, 0, UPDATE_REFS_MSG_ON_ERR);\n+\n+\tstrbuf_release(&ref_name);\n+\treturn ret;\n+\n+}\ndiff --git a/checkout.h b/checkout.h\nindex 998071117..6ce46cf4e 100644\n--- a/checkout.h\n+++ b/checkout.h\n@@ -10,4 +10,7 @@\n  */\n extern const char *unique_tracking_name(const char *name, struct object_id *oid);\n \n+int detach_head_to(struct object_id *oid, const char *action,\n+\t\t   const char *reflog_message);\n+\n #endif /* CHECKOUT_H */\ndiff --git a/sequencer.c b/sequencer.c\nindex 5354d4d51..106d518f4 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -29,6 +29,7 @@\n #include \"oidset.h\"\n #include \"commit-slab.h\"\n #include \"alias.h\"\n+#include \"checkout.h\"\n \n #define GIT_REFLOG_ACTION \"GIT_REFLOG_ACTION\"\n \n@@ -2756,14 +2757,7 @@ static int do_reset(const char *name, int len, struct replay_opts *opts)\n {\n \tstruct strbuf ref_name = STRBUF_INIT;\n \tstruct object_id oid;\n-\tstruct lock_file lock = LOCK_INIT;\n-\tstruct tree_desc desc;\n-\tstruct tree *tree;\n-\tstruct unpack_trees_options unpack_tree_opts;\n-\tint ret = 0, i;\n-\n-\tif (hold_locked_index(&lock, LOCK_REPORT_ON_ERROR) < 0)\n-\t\treturn -1;\n+\tint i;\n \n \tif (len == 10 && !strncmp(\"[new root]\", name, len)) {\n \t\tif (!opts->have_squash_onto) {\n@@ -2789,56 +2783,14 @@ static int do_reset(const char *name, int len, struct replay_opts *opts)\n \t\tif (get_oid(ref_name.buf, &oid) &&\n \t\t    get_oid(ref_name.buf + strlen(\"refs/rewritten/\"), &oid)) {\n \t\t\terror(_(\"could not read '%s'\"), ref_name.buf);\n-\t\t\trollback_lock_file(&lock);\n \t\t\tstrbuf_release(&ref_name);\n \t\t\treturn -1;\n \t\t}\n \t}\n \n-\tmemset(&unpack_tree_opts, 0, sizeof(unpack_tree_opts));\n-\tsetup_unpack_trees_porcelain(&unpack_tree_opts, \"reset\");\n-\tunpack_tree_opts.head_idx = 1;\n-\tunpack_tree_opts.src_index = &the_index;\n-\tunpack_tree_opts.dst_index = &the_index;\n-\tunpack_tree_opts.fn = oneway_merge;\n-\tunpack_tree_opts.merge = 1;\n-\tunpack_tree_opts.update = 1;\n-\n-\tif (read_cache_unmerged()) {\n-\t\trollback_lock_file(&lock);\n-\t\tstrbuf_release(&ref_name);\n-\t\treturn error_resolve_conflict(_(action_name(opts)));\n-\t}\n-\n-\tif (!fill_tree_descriptor(&desc, &oid)) {\n-\t\terror(_(\"failed to find tree of %s\"), oid_to_hex(&oid));\n-\t\trollback_lock_file(&lock);\n-\t\tfree((void *)desc.buffer);\n-\t\tstrbuf_release(&ref_name);\n-\t\treturn -1;\n-\t}\n-\n-\tif (unpack_trees(1, &desc, &unpack_tree_opts)) {\n-\t\trollback_lock_file(&lock);\n-\t\tfree((void *)desc.buffer);\n-\t\tstrbuf_release(&ref_name);\n-\t\treturn -1;\n-\t}\n-\n-\ttree = parse_tree_indirect(&oid);\n-\tprime_cache_tree(&the_index, tree);\n-\n-\tif (write_locked_index(&the_index, &lock, COMMIT_LOCK) < 0)\n-\t\tret = error(_(\"could not write index\"));\n-\tfree((void *)desc.buffer);\n-\n-\tif (!ret)\n-\t\tret = update_ref(reflog_message(opts, \"reset\", \"'%.*s'\",\n-\t\t\t\t\t\tlen, name), \"HEAD\", &oid,\n-\t\t\t\t NULL, 0, UPDATE_REFS_MSG_ON_ERR);\n-\n-\tstrbuf_release(&ref_name);\n-\treturn ret;\n+\treturn detach_head_to(&oid, action_name(opts),\n+\t\t\t      reflog_message(opts, \"reset\", \"'%.*s'\",\n+\t\t\t\t\t     len, name));\n }\n \n static int do_merge(struct commit *commit, const char *arg, int arg_len,\n-- \n2.18.0\n\n"},{"id":"351189","messageId":"20180628074655.5756-6-predatoramigo@gmail.com","threadId":"48795","inReplyTo":"20180628074655.5756-1-predatoramigo@gmail.com","subject":"[PATCH 5/5] builtin/rebase: support running \"git rebase <upstream>\"","fromName":"Pratik Karki","fromEmail":"predatoramigo@gmail.com","sentAt":"2018-06-28T07:46:55Z","receivedAt":"2018-06-28T07:48:45Z","isPatch":true,"sender":{"key":"predatoramigo@gmail.com","avatar":"https://avatars.githubusercontent.com/u/12194950?v=4"},"body":"This patch gives life to the skeleton added in the previous patch.\nThis patch makes real operation happen i.e. by using\n`git -c rebase.usebuiltin=true rebase <upstream>`.\nWith this patch, the basic operation of rebase can be done.\n\nThe current version of the builtin rebase does not, however, make full\nuse of the internals but instead chooses to spawn a couple of Git\nprocesses, still, to make for an easier conversion. There remains a lot\nof room for improvement, left later.\n\nThese backends use Unix shell functions defined both by git-sh-setup.sh\nand git-rebase.sh (we move the latter's into git-rebase--common.sh to\naccommodate for that), so we not only have to source the backend file\nbefore calling the respective Unix shell script function, but we have\nto source git-sh-setup and git-rebase--common before that.\nAnd since this is all done in a Unix shell script snippet, all of this\nis in argv[0]. There never will be a non-NULL argv[1].\n\nThis patch does the *bare* minimum to get `git rebase <upstream>` to\nwork: there is still no option parsing, and only the bare minimum set\nof environment variables are set (in particular, the current revision\nwould be susceptible to bugs where e.g. `rebase_root` could be set by\nmistake before running `git rebase` and the `git-rebase--am` backend\nwould pick up that variable and use it).\n\nIt still calls original `git-legacy-rebase.sh` unless the config\nsetting rebase.useBuiltin is set to true. This patch uses the\ndetach_head_to() function from checkout.c introduced by a previous\ncommit to perform initial checkout.\n\nSigned-off-by: Pratik Karki <predatoramigo@gmail.com>\n---\n builtin/rebase.c | 231 ++++++++++++++++++++++++++++++++++++++++++++++-\n 1 file changed, 229 insertions(+), 2 deletions(-)\n\ndiff --git a/builtin/rebase.c b/builtin/rebase.c\nindex 1152b7229..2f90389c2 100644\n--- a/builtin/rebase.c\n+++ b/builtin/rebase.c\n@@ -9,6 +9,19 @@\n #include \"exec-cmd.h\"\n #include \"argv-array.h\"\n #include \"dir.h\"\n+#include \"packfile.h\"\n+#include \"checkout.h\"\n+#include \"refs.h\"\n+\n+static GIT_PATH_FUNC(apply_dir, \"rebase-apply\");\n+static GIT_PATH_FUNC(merge_dir, \"rebase-merge\");\n+\n+enum rebase_type {\n+\tREBASE_AM,\n+\tREBASE_MERGE,\n+\tREBASE_INTERACTIVE,\n+\tREBASE_PRESERVE_MERGES\n+};\n \n static int use_builtin_rebase(void)\n {\n@@ -28,8 +41,129 @@ static int use_builtin_rebase(void)\n \treturn ret;\n }\n \n+static int apply_autostash(void)\n+{\n+\twarning(\"TODO\");\n+\treturn 0;\n+}\n+\n+struct rebase_options {\n+\tenum rebase_type type;\n+\tconst char *state_dir;\n+\tstruct commit *upstream;\n+\tconst char *upstream_name;\n+\tchar *head_name;\n+\tstruct object_id orig_head;\n+\tstruct commit *onto;\n+\tconst char *onto_name;\n+\tconst char *revisions;\n+\tconst char *root;\n+};\n+\n+static int finish_rebase(struct rebase_options *opts)\n+{\n+\tstruct strbuf dir = STRBUF_INIT;\n+\tconst char *argv_gc_auto[] = { \"gc\", \"--auto\", NULL };\n+\n+\tdelete_ref(NULL, \"REBASE_HEAD\", NULL, REF_NO_DEREF);\n+\tapply_autostash();\n+\tclose_all_packs(the_repository->objects);\n+\t/*\n+\t * We ignore errors in 'gc --auto', since the\n+\t * user should see them.\n+\t */\n+\trun_command_v_opt(argv_gc_auto, RUN_GIT_CMD);\n+\tstrbuf_addstr(&dir, opts->state_dir);\n+\tremove_dir_recursively(&dir, 0);\n+\tstrbuf_release(&dir);\n+\n+\treturn 0;\n+}\n+\n+static struct commit *peel_committish(const char *name)\n+{\n+\tstruct object *obj;\n+\tstruct object_id oid;\n+\tif (get_oid(name, &oid))\n+\t\treturn NULL;\n+\tobj = parse_object(&oid);\n+\treturn (struct commit *)peel_to_type(name, 0, obj, OBJ_COMMIT);\n+}\n+\n+static int run_specific_rebase(struct rebase_options *opts)\n+{\n+\tconst char *argv[] = { NULL, NULL };\n+\tstruct strbuf script_snippet = STRBUF_INIT;\n+\tstruct argv_array env = ARGV_ARRAY_INIT;\n+\tint status;\n+\tconst char *backend, *backend_func;\n+\n+\targv_array_pushf(&env, \"upstream_name=%s\", opts->upstream_name);\n+\targv_array_pushf(&env, \"GIT_DIR=%s\", absolute_path(get_git_dir()));\n+\targv_array_pushf(&env, \"upstream=%s\",\n+\t\t\t\toid_to_hex(&opts->upstream->object.oid));\n+\targv_array_pushf(&env, \"orig_head=%s\", oid_to_hex(&opts->orig_head));\n+\targv_array_pushf(&env, \"onto=%s\",\n+\t\t\t\toid_to_hex(&opts->onto->object.oid));\n+\targv_array_pushf(&env, \"onto_name=%s\", opts->onto_name);\n+\targv_array_pushf(&env, \"revisions=%s\", opts->revisions);\n+\n+\tswitch (opts->type) {\n+\t\tcase REBASE_AM:\n+\t\t\tbackend = \"git-rebase--am\";\n+\t\t\tbackend_func = \"git_rebase__am\";\n+\t\t\tbreak;\n+\t\tcase REBASE_INTERACTIVE:\n+\t\t\tbackend = \"git-rebase--interactive\";\n+\t\t\tbackend_func = \"git_rebase__interactive\";\n+\t\t\tbreak;\n+\t\tcase REBASE_MERGE:\n+\t\t\tbackend = \"git-rebase--merge\";\n+\t\t\tbackend_func = \"git_rebase__merge\";\n+\t\t\tbreak;\n+\t\tcase REBASE_PRESERVE_MERGES:\n+\t\t\tbackend = \"git-rebase--preserve-merges\";\n+\t\t\tbackend_func = \"git_rebase__preserve_merges\";\n+\t\t\tbreak;\n+\t\tdefault:\n+\t\t\tBUG(\"Unhandled rebase type %d\", opts->type);\n+\t\t\tbreak;\n+\t}\n+\n+\tstrbuf_addf(&script_snippet,\n+\t\t    \". git-rebase--common && . %s && %s\",\n+\t\t    backend, backend_func);\n+\targv[0] = script_snippet.buf;\n+\n+\tstatus = run_command_v_opt_cd_env(argv, RUN_USING_SHELL, NULL,\n+\t\t\t\t\t  env.argv);\n+\tif (status == 0)\n+\t\tfinish_rebase(opts);\n+\telse if (status == 2) {\n+\t\tstruct strbuf dir = STRBUF_INIT;\n+\n+\t\tapply_autostash();\n+\t\tstrbuf_addstr(&dir, opts->state_dir);\n+\t\tremove_dir_recursively(&dir, 0);\n+\t\tstrbuf_release(&dir);\n+\t\tdie(\"Nothing to do\");\n+\t}\n+\n+\tstrbuf_release(&script_snippet);\n+\targv_array_clear(&env);\n+\n+\treturn status ? -1 : 0;\n+}\n+\n int cmd_rebase(int argc, const char **argv, const char *prefix)\n {\n+\tstruct rebase_options options = { -1 };\n+\tconst char *branch_name;\n+\tint ret, flags, quiet = 0;\n+\tstruct strbuf msg = STRBUF_INIT;\n+\tstruct strbuf revisions = STRBUF_INIT;\n+\tconst char *restrict_revision = NULL;\n+\n \t/*\n \t* NEEDSWORK: Once the builtin rebase has been tested enough\n \t* and git-legacy-rebase.sh is retired to contrib/, this preamble\n@@ -51,5 +185,98 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \ttrace_repo_setup(prefix);\n \tsetup_work_tree();\n \n-\tdie(\"TODO\");\n-}\n\\ No newline at end of file\n+\toptions.type = REBASE_AM;\n+\n+\tswitch (options.type) {\n+\tcase REBASE_AM:\n+\t\toptions.state_dir = apply_dir();\n+\t\tbreak;\n+\tcase REBASE_MERGE:\n+\tcase REBASE_INTERACTIVE:\n+\tcase REBASE_PRESERVE_MERGES:\n+\t\toptions.state_dir = merge_dir();\n+\t\tbreak;\n+\t}\n+\tif (!options.root) {\n+\t\tif(!argc)\n+\t\t\tdie(\"TODO: handle @{upstream}\");\n+\t\telse {\n+\t\t\toptions.upstream_name = argv[1];\n+\t\t\targc--;\n+\t\t\targv++;\n+\t\t\tif (!strcmp(options.upstream_name, \"-\"))\n+\t\t\t\toptions.upstream_name = \"@{-1}\";\n+\t\t}\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} else\n+\t\tdie(\"TODO: upstream for --root\");\n+\n+\t/* Make sure the branch to rebase onto is valid. */\n+\toptions.onto_name = (const char *) options.onto ?\n+\t\t(const char *) options.onto : options.upstream_name;\n+\tif (strstr(options.onto_name, \"...\")) {\n+\t\tdie(\"TODO\");\n+\t} else {\n+\t\toptions.onto = peel_committish(options.onto_name);\n+\t\tif (!options.onto)\n+\t\t\tdie(_(\"Does not point to a valid commit '%s'\"),\n+\t\t\t\toptions.onto_name);\n+\t}\n+\n+\t/*\n+\t* If the branch to rebase is given, that is the branch we will rebase\n+\t* branch_name -- branch/commit being rebased, or 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*/\n+\tif (argc > 1)\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+\t\toptions.head_name =\n+\t\t\txstrdup_or_null(resolve_ref_unsafe(\"HEAD\", 0, NULL,\n+\t\t\t\t\t &flags));\n+\t\tif (!options.head_name)\n+\t\t\tdie(_(\"No such ref: %s\"), \"HEAD\");\n+\t\tif (flags & REF_ISSYMREF) {\n+\t\t\tif (!skip_prefix(options.head_name,\n+\t\t\t\t\t \"refs/heads/\", &branch_name))\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\tbranch_name = \"HEAD\";\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+\n+\t/* Detach HEAD and reset the tree */\n+\tif (!quiet)\n+\t\tprintf(\"First, rewinding head to replay your work on top of it...\");\n+\n+\tstrbuf_addf(&msg, \"rebase: checkout %s\", options.onto_name);\n+\tif (detach_head_to(&options.onto->object.oid, \"checkout\", msg.buf))\n+\t\tdie(_(\"Could not detach HEAD\"));\n+\tstrbuf_release(&msg);\n+\tif (update_ref(\"rebase\", \"ORIG_HEAD\", &options.orig_head, NULL, 0,\n+\t\t       UPDATE_REFS_MSG_ON_ERR) < 0)\n+\t\tdie(_(\"Could not update ORIG_HEAD to '%s'\"),\n+\t\t    oid_to_hex(&options.orig_head));\n+\n+\tstrbuf_addf(&revisions, \"%s..%s\",\n+\t\t!options.root ? oid_to_hex(&options.onto->object.oid) :\n+\t\t    (restrict_revision ? restrict_revision :\n+\t\t\t    oid_to_hex(&options.upstream->object.oid)),\n+\t\t\t    oid_to_hex(&options.orig_head));\n+\n+\toptions.revisions = revisions.buf;\n+\n+\tret = !!run_specific_rebase(&options);\n+\n+\tstrbuf_release(&revisions);\n+\tfree(options.head_name);\n+\treturn ret;\n+}\n-- \n2.18.0\n\n"},{"id":"351190","messageId":"CAP8UFD1+r6LszVXf=Nv8cR4RoDWdXQV26su1oXN+WzbSdmrr+g@mail.gmail.com","threadId":"48795","inReplyTo":"20180628074655.5756-4-predatoramigo@gmail.com","subject":"Re: [PATCH 3/5] rebase: refactor common shell functions into their own file","fromName":"Christian Couder","fromEmail":"christian.couder@gmail.com","sentAt":"2018-06-28T08:02:53Z","receivedAt":"2018-06-28T08:02:58Z","isPatch":true,"sender":{"key":"christian.couder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/208954?v=4"},"body":"On Thu, Jun 28, 2018 at 9:46 AM, Pratik Karki <predatoramigo@gmail.com> wrote:\n\n> The motivation behind this is to call the backend functions\n> *directly* from C, bypassing `git-rebase.sh`. Therefore those functions\n> need to live in a separate file: we need to be able to call\n> `.git-rebase--common` in that script snippet so that those functions\n\nI think it should be `. git-rebase--common` (space missing between .\nand git-rebase--common).\n\n> are defined.\n"},{"id":"351191","messageId":"CAP8UFD2+7hRAHOTrYRZZad6OkGDM3CjnOJ3qcWUhS3R9-dn6bg@mail.gmail.com","threadId":"48795","inReplyTo":"20180628074655.5756-3-predatoramigo@gmail.com","subject":"Re: [PATCH 2/5] rebase: start implementing it as a builtin","fromName":"Christian Couder","fromEmail":"christian.couder@gmail.com","sentAt":"2018-06-28T08:08:12Z","receivedAt":"2018-06-28T08:08:19Z","isPatch":true,"sender":{"key":"christian.couder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/208954?v=4"},"body":"On Thu, Jun 28, 2018 at 9:46 AM, Pratik Karki <predatoramigo@gmail.com> wrote:\n\n> diff --git a/builtin/rebase.c b/builtin/rebase.c\n> new file mode 100644\n> index 000000000..1152b7229\n> --- /dev/null\n> +++ b/builtin/rebase.c\n> @@ -0,0 +1,55 @@\n> +/*\n> + * \"git rebase\" builtin command\n> + *\n> + * Copyright (c) 2018 Pratik Karki\n> + */\n\n[...]\n\n> +       die(\"TODO\");\n> +}\n> \\ No newline at end of file\n\nPlease add a newline at the end of the files you create.\n"},{"id":"351192","messageId":"CAP8UFD06HO_j5-4wt=efB1Wr-52OcnZyn=bXAVra=ZpdxKXusA@mail.gmail.com","threadId":"48795","inReplyTo":"20180628074655.5756-5-predatoramigo@gmail.com","subject":"Re: [PATCH 4/5] sequencer: refactor the code to detach HEAD to checkout.c","fromName":"Christian Couder","fromEmail":"christian.couder@gmail.com","sentAt":"2018-06-28T08:14:22Z","receivedAt":"2018-06-28T08:14:28Z","isPatch":true,"sender":{"key":"christian.couder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/208954?v=4"},"body":"On Thu, Jun 28, 2018 at 9:46 AM, Pratik Karki <predatoramigo@gmail.com> wrote:\n> The motivation behind this commit is to extract the core part of\n> do_reset() from sequencer.c and move it to a new detach_head_to()\n> function in checkout.c.\n\nIf this is independent from your other patches and if this can be used\nby Alban's work, then it might be a good idea to send this patch\nseparately (and then to state in this patch series that it depends on\nthe separate patch) or at least to move this patch to the beginning of\nthe patch series.\n"},{"id":"351193","messageId":"CAOZc8M8u4RPsqRfy1nuuWgjPSAhjbO5ZTtZbR6HY1n3fH5-Q6g@mail.gmail.com","threadId":"48795","inReplyTo":"20180628074655.5756-2-predatoramigo@gmail.com","subject":"Re: [PATCH 1/5] Start TODO-rebase.sh","fromName":"Pratik Karki","fromEmail":"predatoramigo@gmail.com","sentAt":"2018-06-28T09:17:49Z","receivedAt":"2018-06-28T09:18:06Z","isPatch":true,"sender":{"key":"predatoramigo@gmail.com","avatar":"https://avatars.githubusercontent.com/u/12194950?v=4"},"body":"Hi,\n\nThis is a patch I keep in wip-rebase branch[1][2].\nIt shouldn't be applied to `pu`.\n\nThis main objective of this file in the branch is to keep track of\nthe converted shell scripts of `git-rebase.sh` and plan on the\nconversion of other remaining parts.\n\n[1]: https://github.com/prertik/git/tree/wip-rebase\n[2]: https://github.com/git/git/pull/505\n\nThanks,\nPratik\n"},{"id":"351255","messageId":"CAGZ79kZe46nkNd9yRZfwDG_-D-oBV5221qvB5zaj4Vw909U7fw@mail.gmail.com","threadId":"48795","inReplyTo":"20180628074655.5756-3-predatoramigo@gmail.com","subject":"Re: [PATCH 2/5] rebase: start implementing it as a builtin","fromName":"Stefan Beller","fromEmail":"sbeller@google.com","sentAt":"2018-06-28T18:49:01Z","receivedAt":"2018-06-28T18:49:17Z","isPatch":true,"sender":{"key":"stefanbeller@gmail.com","avatar":"https://avatars.githubusercontent.com/u/455868?v=4"},"body":"On Thu, Jun 28, 2018 at 12:48 AM Pratik Karki <predatoramigo@gmail.com> wrote:\n>\n> This commit imitates the strategy that was used to convert the\n> difftool to a builtin, see be8a90e (difftool: add a skeleton for the\n> upcoming builtin, 2017-01-17) for details: This commit renames the\n> shell script `git-rebase.sh` to `git-legacy-rebase.sh` and hands off to\n> it by default.\n\nThat is a good way to start, imitating Johannes approach on rewriting\nthe difftool. Thanks for pointing this out.\n\n> The current version of the builtin rebase does not, however, make full\n> use of the internals but instead chooses to spawn a couple of Git\n> processes to find out if we run the builtin or legacy rebase as that\n> keeps the directory that we are in correct. There remains a lot\n> of room for improvement, left for a later date. The following commits\n> will recreate the functionality of the shell script, in pure C.\n>\n> We intentionally avoid reading the config directly to avoid\n> messing up the GIT_* environment variables when we need to fall back to\n> exec()ing the shell script.\n\nThanks for calling this out!\n\nThe test of builtin rebase can be done by\n> `git -c rebase.useBuiltin=true rebase ...`\n>\n> Signed-off-by: Pratik Karki <predatoramigo@gmail.com>\n> ---\n>  .gitignore                            |  1 +\n>  Makefile                              |  3 +-\n>  builtin.h                             |  1 +\n>  builtin/rebase.c                      | 55 +++++++++++++++++++++++++++\n>  git-rebase.sh => git-legacy-rebase.sh |  0\n>  git.c                                 |  6 +++\n>  6 files changed, 65 insertions(+), 1 deletion(-)\n>  create mode 100644 builtin/rebase.c\n>  rename git-rebase.sh => git-legacy-rebase.sh (100%)\n>\n> diff --git a/.gitignore b/.gitignore\n> index 3284a1e9b..ec2395901 100644\n> --- a/.gitignore\n> +++ b/.gitignore\n> @@ -78,6 +78,7 @@\n>  /git-init-db\n>  /git-interpret-trailers\n>  /git-instaweb\n> +/git-legacy-rebase\n>  /git-log\n>  /git-ls-files\n>  /git-ls-remote\n> diff --git a/Makefile b/Makefile\n> index 0cb6590f2..e88fe2e5f 100644\n> --- a/Makefile\n> +++ b/Makefile\n> @@ -609,7 +609,7 @@ SCRIPT_SH += git-merge-one-file.sh\n>  SCRIPT_SH += git-merge-resolve.sh\n>  SCRIPT_SH += git-mergetool.sh\n>  SCRIPT_SH += git-quiltimport.sh\n> -SCRIPT_SH += git-rebase.sh\n> +SCRIPT_SH += git-legacy-rebase.sh\n>  SCRIPT_SH += git-remote-testgit.sh\n>  SCRIPT_SH += git-request-pull.sh\n>  SCRIPT_SH += git-stash.sh\n> @@ -1059,6 +1059,7 @@ BUILTIN_OBJS += builtin/prune.o\n>  BUILTIN_OBJS += builtin/pull.o\n>  BUILTIN_OBJS += builtin/push.o\n>  BUILTIN_OBJS += builtin/read-tree.o\n> +BUILTIN_OBJS += builtin/rebase.o\n>  BUILTIN_OBJS += builtin/rebase--helper.o\n>  BUILTIN_OBJS += builtin/receive-pack.o\n>  BUILTIN_OBJS += builtin/reflog.o\n> diff --git a/builtin.h b/builtin.h\n> index 0362f1ce2..44651a447 100644\n> --- a/builtin.h\n> +++ b/builtin.h\n> @@ -202,6 +202,7 @@ extern int cmd_prune_packed(int argc, const char **argv, const char *prefix);\n>  extern int cmd_pull(int argc, const char **argv, const char *prefix);\n>  extern int cmd_push(int argc, const char **argv, const char *prefix);\n>  extern int cmd_read_tree(int argc, const char **argv, const char *prefix);\n> +extern int cmd_rebase(int argc, const char **argv, const char *prefix);\n>  extern int cmd_rebase__helper(int argc, const char **argv, const char *prefix);\n>  extern int cmd_receive_pack(int argc, const char **argv, const char *prefix);\n>  extern int cmd_reflog(int argc, const char **argv, const char *prefix);\n> diff --git a/builtin/rebase.c b/builtin/rebase.c\n> new file mode 100644\n> index 000000000..1152b7229\n> --- /dev/null\n> +++ b/builtin/rebase.c\n> @@ -0,0 +1,55 @@\n> +/*\n> + * \"git rebase\" builtin command\n> + *\n> + * Copyright (c) 2018 Pratik Karki\n> + */\n> +\n> +#include \"builtin.h\"\n> +#include \"run-command.h\"\n> +#include \"exec-cmd.h\"\n> +#include \"argv-array.h\"\n> +#include \"dir.h\"\n> +\n> +static int use_builtin_rebase(void)\n> +{\n> +       struct child_process cp = CHILD_PROCESS_INIT;\n> +       struct strbuf out = STRBUF_INIT;\n> +       int ret;\n> +\n> +       argv_array_pushl(&cp.args,\n> +                        \"config\", \"--bool\", \"rebase.usebuiltin\", NULL);\n\n--bool is documented as \"Historical options for selecting\na type specifier. Prefer instead --type, (see: above).\" in the\nman page of git-config. But as this code will go away once\nthe conversion is done, this is not kept around for long.\nSo we should be fine using the --bool option.\n\n> +       cp.git_cmd = 1;\n> +       if (capture_command(&cp, &out, 6))\n> +               return 0;\n> +\n> +       strbuf_trim(&out);\n> +       ret = !strcmp(\"true\", out.buf);\n\nAs --bool will make sure that the config command\nprints \"true\" or \"false\", even when the user configured\n0 or 1 instead, this is fine.\n\n> +       if (argc != 2)\n> +               die(\"Usage: %s <base>\", argv[0]);\n> +       prefix = setup_git_directory();\n> +       trace_repo_setup(prefix);\n> +       setup_work_tree();\n> +\n> +       die(\"TODO\");\n\nWhen reading the last sentence in the commit message\n(\"This can be tested ...\") I shortly wondered how we adapt the tests\nbut as this is really just the skeleton, there is no need to adapt any tests.\n\nThis patch looks fine to me except for the nit that Christian points out.\n\nThanks!\nStefan\n"},{"id":"351258","messageId":"CAGZ79kaVXVu9BWtQfpNturhLMJtCuc7MSuTa6aRwwC8q=nXsgQ@mail.gmail.com","threadId":"48795","inReplyTo":"20180628074655.5756-4-predatoramigo@gmail.com","subject":"Re: [PATCH 3/5] rebase: refactor common shell functions into their own file","fromName":"Stefan Beller","fromEmail":"sbeller@google.com","sentAt":"2018-06-28T19:17:58Z","receivedAt":"2018-06-28T19:18:14Z","isPatch":true,"sender":{"key":"stefanbeller@gmail.com","avatar":"https://avatars.githubusercontent.com/u/455868?v=4"},"body":"On Thu, Jun 28, 2018 at 12:48 AM Pratik Karki <predatoramigo@gmail.com> wrote:\n>\n> The function present in `git-legacy-rebase.sh` are used by backends\n> so, this refactor tries to extract the functions out so that, the\n\nit not only tries to, it actually does. :)\n\n> `git-legacy-rebase.sh` can be retired easily as the\n> `git-rebase--common.sh` will provide the functions for now.\n>\n> The motivation behind this is to call the backend functions\n> *directly* from C, bypassing `git-rebase.sh`. Therefore those functions\n> need to live in a separate file: we need to be able to call\n> `.git-rebase--common` in that script snippet so that those functions\n> are defined.\n\nMakes sense.\n\nI applied the patch (and checked the move via the --color-moved option\nto see if there are discrepancies that slip in easily via rebases as there is\nmore work currently going on in the rebase area) and the found the functions\nwere moved as-is, just reordered. Can you give a hint on why you choose a\ndifferent order for the moved functions (not as an email reply, but as part\nof the commit message, later on people may ask the same question only\nto find this commit via git-blame or git-log for example)\n\nThanks,\nStefan\n"},{"id":"351260","messageId":"CAGZ79kZbrk6rSNYx9XP+PWEgghMrgR6JKtdyS+3ku8eOk0X+-w@mail.gmail.com","threadId":"48795","inReplyTo":"20180628074655.5756-5-predatoramigo@gmail.com","subject":"Re: [PATCH 4/5] sequencer: refactor the code to detach HEAD to checkout.c","fromName":"Stefan Beller","fromEmail":"sbeller@google.com","sentAt":"2018-06-28T21:19:22Z","receivedAt":"2018-06-28T21:19:37Z","isPatch":true,"sender":{"key":"stefanbeller@gmail.com","avatar":"https://avatars.githubusercontent.com/u/455868?v=4"},"body":"Hi Pratik,\nOn Thu, Jun 28, 2018 at 12:48 AM Pratik Karki <predatoramigo@gmail.com> wrote:\n>\n> The motivation behind this commit is to extract the core part of\n> do_reset() from sequencer.c and move it to a new detach_head_to()\n> function in checkout.c.\n>\n[...]\n>\n> The new function will be used in the next commit by the builtin rebase,\n> to perform the initial checkout.\n\nThis sounds like the actual motivation, which is fine.\n\n> Here the index only gets locked after performing the first part of\n> `do_reset()` rather than before which essentially derives the `oid`\n> from the specified label/name passed to the `do_reset()` function.\n> It also fixes two bugs: there were two `return error()` statements in\n> the `[new root]` case that would have failed to unlock the index.\n\nThis sounds as if this fixes a problem? If so it would be nice to have\na test that demonstrates that these specific problems go away.\n(but I think we could just argue based on the motivation above that this\nis a good change on its own, with or without demonstrating these\nadditional issues)\n\n> Signed-off-by: Pratik Karki <predatoramigo@gmail.com>\n> ---\n>  checkout.c  | 64 +++++++++++++++++++++++++++++++++++++++++++++++++++++\n>  checkout.h  |  3 +++\n>  sequencer.c | 58 +++++-------------------------------------------\n>  3 files changed, 72 insertions(+), 53 deletions(-)\n>\n> diff --git a/checkout.c b/checkout.c\n> index bdefc888b..da68915fd 100644\n> --- a/checkout.c\n> +++ b/checkout.c\n> @@ -2,6 +2,11 @@\n>  #include \"remote.h\"\n>  #include \"refspec.h\"\n>  #include \"checkout.h\"\n> +#include \"unpack-trees.h\"\n> +#include \"lockfile.h\"\n> +#include \"refs.h\"\n> +#include \"tree.h\"\n> +#include \"cache-tree.h\"\n>\n>  struct tracking_name_data {\n>         /* const */ char *src_ref;\n> @@ -42,3 +47,62 @@ const char *unique_tracking_name(const char *name, struct object_id *oid)\n>         free(cb_data.dst_ref);\n>         return NULL;\n>  }\n> +\n> +int detach_head_to(struct object_id *oid, const char *action,\n> +                  const char *reflog_message)\n> +{\n> +       struct strbuf ref_name = STRBUF_INIT;\n> +       struct tree_desc desc;\n> +       struct lock_file lock = LOCK_INIT;\n> +       struct unpack_trees_options unpack_tree_opts;\n> +       struct tree *tree;\n> +       int ret = 0;\n> +\n> +       if (hold_locked_index(&lock, LOCK_REPORT_ON_ERROR) < 0)\n> +               return -1;\n> +\n> +       memset(&unpack_tree_opts, 0, sizeof(unpack_tree_opts));\n> +       setup_unpack_trees_porcelain(&unpack_tree_opts, action);\n> +       unpack_tree_opts.head_idx = 1;\n> +       unpack_tree_opts.src_index = &the_index;\n> +       unpack_tree_opts.dst_index = &the_index;\n> +       unpack_tree_opts.fn = oneway_merge;\n> +       unpack_tree_opts.merge = 1;\n> +       unpack_tree_opts.update = 1;\n> +\n> +       if (read_cache_unmerged()) {\n> +               rollback_lock_file(&lock);\n> +               strbuf_release(&ref_name);\n> +               return error_resolve_conflict(_(action));\n> +       }\n> +\n> +       if (!fill_tree_descriptor(&desc, oid)) {\n> +               error(_(\"failed to find tree of %s\"), oid_to_hex(oid));\n> +               rollback_lock_file(&lock);\n> +               free((void *)desc.buffer);\n> +               strbuf_release(&ref_name);\n\nThese lines are repeated as a very similar pattern after each\nfailing function. Maybe we can make it more readable by moving\nall these to the end and then using goto to jump there.\n\nFor example see \"write_pseudoref\" in refs.c, that has some interesting\npatterns to learn from, e.g. how the return code is constructed\n(start off with setting it -1 and only if we go through the whole\nfunction, just before the jump label, we'd set it to 0) and\nhow all the free/strbuf_releases are at the end (no need to\nrepeat them).\n\n> +               return -1;\n> +       }\n> +\n> +       if (unpack_trees(1, &desc, &unpack_tree_opts)) {\n> +               rollback_lock_file(&lock);\n> +               free((void *)desc.buffer);\n> +               strbuf_release(&ref_name);\n> +               return -1;\n> +       }\n> +\n> +       tree = parse_tree_indirect(oid);\n\nAwesome, the _indirect function can take commits/tags or trees.\n\n> +       prime_cache_tree(&the_index, tree);\n\nAs there is a larger movement to get rid of globals, and the_index is one\nof them[1]. So maybe just use the_repository->index already (the_repository\nsuffers a similar problem, but I think that is more futureproof for\nthe time being\nas we'd want to kill off the_repository in library code eventually as\nwell and pass\nthrough a repository struct. But for now I'd just use the_repository instead of\nhaving a repository argument)\n\n[1] c.f. https://public-inbox.org/git/20180616054157.32433-1-pclouds@gmail.com/\n\n\n> -       struct lock_file lock = LOCK_INIT;\n> -       struct tree_desc desc;\n> -       struct tree *tree;\n> -       struct unpack_trees_options unpack_tree_opts;\n> -       int ret = 0, i;\n\n[...]\n\nOh I misspoke above, this is moving code (I should have understood\nthe hint with 'extracting' by the commit message), so in this case we'd\nrather want to move code most verbatim to make review easier, which\nit is. So the idea with a goto cleanup could be an optional extra step.\n\nThanks,\nStefan\n"},{"id":"351262","messageId":"CAGZ79kZpf3AMqZPraCYp+KNKPo9xex3OBJLAz_foGiSPVswYHw@mail.gmail.com","threadId":"48795","inReplyTo":"20180628074655.5756-6-predatoramigo@gmail.com","subject":"Re: [PATCH 5/5] builtin/rebase: support running \"git rebase <upstream>\"","fromName":"Stefan Beller","fromEmail":"sbeller@google.com","sentAt":"2018-06-28T21:58:56Z","receivedAt":"2018-06-28T21:59:12Z","isPatch":true,"sender":{"key":"stefanbeller@gmail.com","avatar":"https://avatars.githubusercontent.com/u/455868?v=4"},"body":"On Thu, Jun 28, 2018 at 12:48 AM Pratik Karki <predatoramigo@gmail.com> wrote:\n>\n> This patch gives life to the skeleton added in the previous patch.\n> This patch makes real operation happen i.e. by using\n> `git -c rebase.usebuiltin=true rebase <upstream>`.\n> With this patch, the basic operation of rebase can be done.\n\nWould it make sense to add this config option to some basic test in the\ntest suite to show off one case in there? (Otherwise it is hard to keep this\ncode correct for the future (even if it is just a few days/weeks) as other\nseries on the list may collide with it in subtle ways, so a test would be\nfast signal to catch these subtleties).\n\nMaybe setting this in one of the early tests in t3400 would be good?\n\n> These backends use Unix shell functions defined both by git-sh-setup.sh\n> and git-rebase.sh (we move the latter's into git-rebase--common.sh to\n\ns/move/moved in a previous patch/ ? But then again we already know about\nthe earlier patch, I am on the fence whether this is worth mentioning. But\nit sure is fine to leave it here.\n\n> accommodate for that), so we not only have to source the backend file\n> before calling the respective Unix shell script function, but we have\n> to source git-sh-setup and git-rebase--common before that.\n> And since this is all done in a Unix shell script snippet, all of this\n> is in argv[0]. There never will be a non-NULL argv[1].\n\nNo double negatives are never harder to read than simple forms. ;)\nSo you are saying, there are no further arguments to that shell\ninvocation?\n\n> This patch does the *bare* minimum to get `git rebase <upstream>` to\n> work: there is still no option parsing, and only the bare minimum set\n> of environment variables are set (in particular, the current revision\n> would be susceptible to bugs where e.g. `rebase_root` could be set by\n> mistake before running `git rebase` and the `git-rebase--am` backend\n> would pick up that variable and use it).\n>\n> It still calls original `git-legacy-rebase.sh` unless the config\n> setting rebase.useBuiltin is set to true. This patch uses the\n> detach_head_to() function from checkout.c introduced by a previous\n> commit to perform initial checkout.\n>\n> Signed-off-by: Pratik Karki <predatoramigo@gmail.com>\n> ---\n>  builtin/rebase.c | 231 ++++++++++++++++++++++++++++++++++++++++++++++-\n>  1 file changed, 229 insertions(+), 2 deletions(-)\n>\n> diff --git a/builtin/rebase.c b/builtin/rebase.c\n> index 1152b7229..2f90389c2 100644\n> --- a/builtin/rebase.c\n> +++ b/builtin/rebase.c\n> @@ -9,6 +9,19 @@\n>  #include \"exec-cmd.h\"\n>  #include \"argv-array.h\"\n>  #include \"dir.h\"\n> +#include \"packfile.h\"\n> +#include \"checkout.h\"\n> +#include \"refs.h\"\n> +\n> +static GIT_PATH_FUNC(apply_dir, \"rebase-apply\");\n> +static GIT_PATH_FUNC(merge_dir, \"rebase-merge\");\n> +\n> +enum rebase_type {\n> +       REBASE_AM,\n> +       REBASE_MERGE,\n> +       REBASE_INTERACTIVE,\n> +       REBASE_PRESERVE_MERGES\n> +};\n>\n>  static int use_builtin_rebase(void)\n>  {\n> @@ -28,8 +41,129 @@ static int use_builtin_rebase(void)\n>         return ret;\n>  }\n>\n> +static int apply_autostash(void)\n> +{\n> +       warning(\"TODO\");\n\nThis comes up unconditionally here, so the automated testing\nidea from above might not be as good as I thought after all.\n\n> +static struct commit *peel_committish(const char *name)\n\nThe -ish suffix is to indicate that a wide range of notations\nthat describe commits are accepted. Another way of naming this\nfunction would be by its output, i.e. peel_to_commit, the name\nsimilar to peel_to_type. But I guess emphasizing the input\nto be anything that describes a commit is also important here,\nas we pass in the arguments eventually provided by users\n(e.g. \"master^^\") so this name sounds fine; I cannot think of\na better suggestion for now.\n"},{"id":"351510","messageId":"20180702091509.15950-1-predatoramigo@gmail.com","threadId":"48795","inReplyTo":"20180628074655.5756-1-predatoramigo@gmail.com","subject":"[GSoC] [PATCH v2 0/4] rebase: rewrite rebase in C","fromName":"Pratik Karki","fromEmail":"predatoramigo@gmail.com","sentAt":"2018-07-02T09:15:05Z","receivedAt":"2018-07-02T09:16:27Z","isPatch":true,"sender":{"key":"predatoramigo@gmail.com","avatar":"https://avatars.githubusercontent.com/u/12194950?v=4"},"body":"As a GSoC project, I have been working on the builtin rebase.\n\nThe motivation behind the rewrite of rebase i.e. from shell script to C\nare for following reasons:\n\n1.  Writing shell scripts and getting it to production is much faster\n    than doing the equivalent in C but lacks in performance and extra\n    workarounds are needed for non-POSIX platforms.\n\n2.  Git for Windows is at loss as the installer size increases due to\n    addition of extra dependencies for the shell scripts which are usually\n    available in POSIX compliant platforms.\n\nThis series of patches serves to demonstrate a minimal builtin rebase\nwhich supports running `git rebase <upstream>` and also serves to ask for\nreviews.\n\nChanges since v1:\n\n  -  Remove the TODO-rebase.sh which shouldn't be merged into `pu`.\n\n  -  Add newline at the end of the file `builtin/rebase.c` in\n     `rebase: start implementing it as a builtin`.\n\n  -  Fix unintentional ordering in `git-rebase--common.sh` and fix the commit\n     message in `rebase: refactor common shell functions into their own file`.\n\n  -  Fix wrong expression of `argc` in the handle upstream loop, fix wrong\n     type casting code, make the condition simple and fix commit message in\n     `builtin/rebase: support running \"git-rebase <upstream>\".\n\nPratik Karki (4):\n  rebase: start implementing it as a builtin\n  rebase: refactor common shell functions into their own file\n  sequencer: refactor the code to detach HEAD to checkout.c\n  builtin/rebase: support running \"git rebase <upstream>\"\n\n .gitignore                            |   2 +\n Makefile                              |   4 +-\n builtin.h                             |   1 +\n builtin/rebase.c                      | 282 ++++++++++++++++++++++++++\n checkout.c                            |  64 ++++++\n checkout.h                            |   3 +\n git-rebase.sh => git-legacy-rebase.sh |  62 +-----\n git-rebase--common.sh                 |  61 ++++++\n git.c                                 |   6 +\n sequencer.c                           |  58 +-----\n 10 files changed, 428 insertions(+), 115 deletions(-)\n create mode 100644 builtin/rebase.c\n rename git-rebase.sh => git-legacy-rebase.sh (91%)\n create mode 100644 git-rebase--common.sh\n\n-- \n2.18.0\n\n"},{"id":"351511","messageId":"20180702091509.15950-2-predatoramigo@gmail.com","threadId":"48795","inReplyTo":"20180702091509.15950-1-predatoramigo@gmail.com","subject":"[PATCH v2 1/4] rebase: start implementing it as a builtin","fromName":"Pratik Karki","fromEmail":"predatoramigo@gmail.com","sentAt":"2018-07-02T09:15:06Z","receivedAt":"2018-07-02T09:16:39Z","isPatch":true,"sender":{"key":"predatoramigo@gmail.com","avatar":"https://avatars.githubusercontent.com/u/12194950?v=4"},"body":"This commit imitates the strategy that was used to convert the\ndifftool to a builtin, see be8a90e (difftool: add a skeleton for the\nupcoming builtin, 2017-01-17) for details: This commit renames the\nshell script `git-rebase.sh` to `git-legacy-rebase.sh` and hands off to\nit by default.\n\nThe current version of the builtin rebase does not, however, make full\nuse of the internals but instead chooses to spawn a couple of Git\nprocesses to find out if we run the builtin or legacy rebase as that\nkeeps the directory that we are in correct. There remains a lot\nof room for improvement, left for a later date. The following commits\nwill recreate the functionality of the shell script, in pure C.\n\nWe intentionally avoid reading the config directly to avoid\nmessing up the GIT_* environment variables when we need to fall back to\nexec()ing the shell script. The test of builtin rebase can be done by\n`git -c rebase.useBuiltin=true rebase ...`\n\nSigned-off-by: Pratik Karki <predatoramigo@gmail.com>\n---\n .gitignore                            |  1 +\n Makefile                              |  3 +-\n builtin.h                             |  1 +\n builtin/rebase.c                      | 55 +++++++++++++++++++++++++++\n git-rebase.sh => git-legacy-rebase.sh |  0\n git.c                                 |  6 +++\n 6 files changed, 65 insertions(+), 1 deletion(-)\n create mode 100644 builtin/rebase.c\n rename git-rebase.sh => git-legacy-rebase.sh (100%)\n\ndiff --git a/.gitignore b/.gitignore\nindex 3284a1e9b..ec2395901 100644\n--- a/.gitignore\n+++ b/.gitignore\n@@ -78,6 +78,7 @@\n /git-init-db\n /git-interpret-trailers\n /git-instaweb\n+/git-legacy-rebase\n /git-log\n /git-ls-files\n /git-ls-remote\ndiff --git a/Makefile b/Makefile\nindex 0cb6590f2..e88fe2e5f 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -609,7 +609,7 @@ SCRIPT_SH += git-merge-one-file.sh\n SCRIPT_SH += git-merge-resolve.sh\n SCRIPT_SH += git-mergetool.sh\n SCRIPT_SH += git-quiltimport.sh\n-SCRIPT_SH += git-rebase.sh\n+SCRIPT_SH += git-legacy-rebase.sh\n SCRIPT_SH += git-remote-testgit.sh\n SCRIPT_SH += git-request-pull.sh\n SCRIPT_SH += git-stash.sh\n@@ -1059,6 +1059,7 @@ BUILTIN_OBJS += builtin/prune.o\n BUILTIN_OBJS += builtin/pull.o\n BUILTIN_OBJS += builtin/push.o\n BUILTIN_OBJS += builtin/read-tree.o\n+BUILTIN_OBJS += builtin/rebase.o\n BUILTIN_OBJS += builtin/rebase--helper.o\n BUILTIN_OBJS += builtin/receive-pack.o\n BUILTIN_OBJS += builtin/reflog.o\ndiff --git a/builtin.h b/builtin.h\nindex 0362f1ce2..44651a447 100644\n--- a/builtin.h\n+++ b/builtin.h\n@@ -202,6 +202,7 @@ extern int cmd_prune_packed(int argc, const char **argv, const char *prefix);\n extern int cmd_pull(int argc, const char **argv, const char *prefix);\n extern int cmd_push(int argc, const char **argv, const char *prefix);\n extern int cmd_read_tree(int argc, const char **argv, const char *prefix);\n+extern int cmd_rebase(int argc, const char **argv, const char *prefix);\n extern int cmd_rebase__helper(int argc, const char **argv, const char *prefix);\n extern int cmd_receive_pack(int argc, const char **argv, const char *prefix);\n extern int cmd_reflog(int argc, const char **argv, const char *prefix);\ndiff --git a/builtin/rebase.c b/builtin/rebase.c\nnew file mode 100644\nindex 000000000..c0c9d6cd2\n--- /dev/null\n+++ b/builtin/rebase.c\n@@ -0,0 +1,55 @@\n+/*\n+ * \"git rebase\" builtin command\n+ *\n+ * Copyright (c) 2018 Pratik Karki\n+ */\n+\n+#include \"builtin.h\"\n+#include \"run-command.h\"\n+#include \"exec-cmd.h\"\n+#include \"argv-array.h\"\n+#include \"dir.h\"\n+\n+static int use_builtin_rebase(void)\n+{\n+\tstruct child_process cp = CHILD_PROCESS_INIT;\n+\tstruct strbuf out = STRBUF_INIT;\n+\tint ret;\n+\n+\targv_array_pushl(&cp.args,\n+\t\t\t \"config\", \"--bool\", \"rebase.usebuiltin\", NULL);\n+\tcp.git_cmd = 1;\n+\tif (capture_command(&cp, &out, 6))\n+\t\treturn 0;\n+\n+\tstrbuf_trim(&out);\n+\tret = !strcmp(\"true\", out.buf);\n+\tstrbuf_release(&out);\n+\treturn ret;\n+}\n+\n+int cmd_rebase(int argc, const char **argv, const char *prefix)\n+{\n+\t/*\n+\t* NEEDSWORK: Once the builtin rebase has been tested enough\n+\t* and git-legacy-rebase.sh is retired to contrib/, this preamble\n+\t* can be removed.\n+\t*/\n+\tif (!use_builtin_rebase()) {\n+\t\tconst char *path = mkpath(\"%s/git-legacy-rebase\",\n+\t\t\t\t\t  git_exec_path());\n+\n+\t\tif (sane_execvp(path, (char **)argv) < 0)\n+\t\t\tdie_errno(\"could not exec %s\", path);\n+\n+\t\treturn 0;\n+\t}\n+\n+\tif (argc != 2)\n+\t\tdie(\"Usage: %s <base>\", argv[0]);\n+\tprefix = setup_git_directory();\n+\ttrace_repo_setup(prefix);\n+\tsetup_work_tree();\n+\n+\tdie(\"TODO\");\n+}\ndiff --git a/git-rebase.sh b/git-legacy-rebase.sh\nsimilarity index 100%\nrename from git-rebase.sh\nrename to git-legacy-rebase.sh\ndiff --git a/git.c b/git.c\nindex 9dbe6ffaa..bacfefb2d 100644\n--- a/git.c\n+++ b/git.c\n@@ -518,6 +518,12 @@ static struct cmd_struct commands[] = {\n \t{ \"pull\", cmd_pull, RUN_SETUP | NEED_WORK_TREE },\n \t{ \"push\", cmd_push, RUN_SETUP },\n \t{ \"read-tree\", cmd_read_tree, RUN_SETUP | SUPPORT_SUPER_PREFIX},\n+\t/*\n+\t *NEEDSWORK: Until the rebase is independent and needs no redirection\n+\t to rebase shell script this is kept as is, then should be changed to\n+\t RUN_SETUP | NEED_WORK_TREE\n+\t*/\n+\t{ \"rebase\", cmd_rebase },\n \t{ \"rebase--helper\", cmd_rebase__helper, RUN_SETUP | NEED_WORK_TREE },\n \t{ \"receive-pack\", cmd_receive_pack },\n \t{ \"reflog\", cmd_reflog, RUN_SETUP },\n-- \n2.18.0\n\n"},{"id":"351512","messageId":"20180702091509.15950-3-predatoramigo@gmail.com","threadId":"48795","inReplyTo":"20180702091509.15950-1-predatoramigo@gmail.com","subject":"[PATCH v2 2/4] rebase: refactor common shell functions into their own file","fromName":"Pratik Karki","fromEmail":"predatoramigo@gmail.com","sentAt":"2018-07-02T09:15:07Z","receivedAt":"2018-07-02T09:16:44Z","isPatch":true,"sender":{"key":"predatoramigo@gmail.com","avatar":"https://avatars.githubusercontent.com/u/12194950?v=4"},"body":"The function present in `git-legacy-rebase.sh` are used by backends\nso, this refactor tries to extract the functions out so that, the\n`git-legacy-rebase.sh` can be retired easily as the\n`git-rebase--common.sh` will provide the functions for now.\n\nThe motivation behind this is to call the backend functions\n*directly* from C, bypassing `git-rebase.sh`. Therefore those functions\nneed to live in a separate file: we need to be able to call\n`. git-rebase--common` in that script snippet so that those functions\nare defined.\n\nSigned-off-by: Pratik Karki <predatoramigo@gmail.com>\n---\n .gitignore            |  1 +\n Makefile              |  1 +\n git-legacy-rebase.sh  | 62 +------------------------------------------\n git-rebase--common.sh | 61 ++++++++++++++++++++++++++++++++++++++++++\n 4 files changed, 64 insertions(+), 61 deletions(-)\n create mode 100644 git-rebase--common.sh\n\ndiff --git a/.gitignore b/.gitignore\nindex ec2395901..824141cba 100644\n--- a/.gitignore\n+++ b/.gitignore\n@@ -117,6 +117,7 @@\n /git-read-tree\n /git-rebase\n /git-rebase--am\n+/git-rebase--common\n /git-rebase--helper\n /git-rebase--interactive\n /git-rebase--merge\ndiff --git a/Makefile b/Makefile\nindex e88fe2e5f..163e52ad1 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -619,6 +619,7 @@ SCRIPT_SH += git-web--browse.sh\n SCRIPT_LIB += git-mergetool--lib\n SCRIPT_LIB += git-parse-remote\n SCRIPT_LIB += git-rebase--am\n+SCRIPT_LIB += git-rebase--common\n SCRIPT_LIB += git-rebase--interactive\n SCRIPT_LIB += git-rebase--preserve-merges\n SCRIPT_LIB += git-rebase--merge\ndiff --git a/git-legacy-rebase.sh b/git-legacy-rebase.sh\nindex 19bdebb48..240aac507 100755\n--- a/git-legacy-rebase.sh\n+++ b/git-legacy-rebase.sh\n@@ -102,6 +102,7 @@ case \"$(git config --bool commit.gpgsign)\" in\n true)\tgpg_sign_opt=-S ;;\n *)\tgpg_sign_opt= ;;\n esac\n+. git-rebase--common\n \n read_basic_state () {\n \ttest -f \"$state_dir/head-name\" &&\n@@ -132,67 +133,6 @@ read_basic_state () {\n \t}\n }\n \n-write_basic_state () {\n-\techo \"$head_name\" > \"$state_dir\"/head-name &&\n-\techo \"$onto\" > \"$state_dir\"/onto &&\n-\techo \"$orig_head\" > \"$state_dir\"/orig-head &&\n-\techo \"$GIT_QUIET\" > \"$state_dir\"/quiet &&\n-\ttest t = \"$verbose\" && : > \"$state_dir\"/verbose\n-\ttest -n \"$strategy\" && echo \"$strategy\" > \"$state_dir\"/strategy\n-\ttest -n \"$strategy_opts\" && echo \"$strategy_opts\" > \\\n-\t\t\"$state_dir\"/strategy_opts\n-\ttest -n \"$allow_rerere_autoupdate\" && echo \"$allow_rerere_autoupdate\" > \\\n-\t\t\"$state_dir\"/allow_rerere_autoupdate\n-\ttest -n \"$gpg_sign_opt\" && echo \"$gpg_sign_opt\" > \"$state_dir\"/gpg_sign_opt\n-\ttest -n \"$signoff\" && echo \"$signoff\" >\"$state_dir\"/signoff\n-}\n-\n-output () {\n-\tcase \"$verbose\" in\n-\t'')\n-\t\toutput=$(\"$@\" 2>&1 )\n-\t\tstatus=$?\n-\t\ttest $status != 0 && printf \"%s\\n\" \"$output\"\n-\t\treturn $status\n-\t\t;;\n-\t*)\n-\t\t\"$@\"\n-\t\t;;\n-\tesac\n-}\n-\n-move_to_original_branch () {\n-\tcase \"$head_name\" in\n-\trefs/*)\n-\t\tmessage=\"rebase finished: $head_name onto $onto\"\n-\t\tgit update-ref -m \"$message\" \\\n-\t\t\t$head_name $(git rev-parse HEAD) $orig_head &&\n-\t\tgit symbolic-ref \\\n-\t\t\t-m \"rebase finished: returning to $head_name\" \\\n-\t\t\tHEAD $head_name ||\n-\t\tdie \"$(eval_gettext \"Could not move back to \\$head_name\")\"\n-\t\t;;\n-\tesac\n-}\n-\n-apply_autostash () {\n-\tif test -f \"$state_dir/autostash\"\n-\tthen\n-\t\tstash_sha1=$(cat \"$state_dir/autostash\")\n-\t\tif git stash apply $stash_sha1 >/dev/null 2>&1\n-\t\tthen\n-\t\t\techo \"$(gettext 'Applied autostash.')\" >&2\n-\t\telse\n-\t\t\tgit stash store -m \"autostash\" -q $stash_sha1 ||\n-\t\t\tdie \"$(eval_gettext \"Cannot store \\$stash_sha1\")\"\n-\t\t\tgettext 'Applying autostash resulted in conflicts.\n-Your changes are safe in the stash.\n-You can run \"git stash pop\" or \"git stash drop\" at any time.\n-' >&2\n-\t\tfi\n-\tfi\n-}\n-\n finish_rebase () {\n \trm -f \"$(git rev-parse --git-path REBASE_HEAD)\"\n \tapply_autostash &&\ndiff --git a/git-rebase--common.sh b/git-rebase--common.sh\nnew file mode 100644\nindex 000000000..fdce7bba5\n--- /dev/null\n+++ b/git-rebase--common.sh\n@@ -0,0 +1,61 @@\n+\n+write_basic_state () {\n+\techo \"$head_name\" > \"$state_dir\"/head-name &&\n+\techo \"$onto\" > \"$state_dir\"/onto &&\n+\techo \"$orig_head\" > \"$state_dir\"/orig-head &&\n+\techo \"$GIT_QUIET\" > \"$state_dir\"/quiet &&\n+\ttest t = \"$verbose\" && : > \"$state_dir\"/verbose\n+\ttest -n \"$strategy\" && echo \"$strategy\" > \"$state_dir\"/strategy\n+\ttest -n \"$strategy_opts\" && echo \"$strategy_opts\" > \\\n+\t\t\"$state_dir\"/strategy_opts\n+\ttest -n \"$allow_rerere_autoupdate\" && echo \"$allow_rerere_autoupdate\" > \\\n+\t\t\"$state_dir\"/allow_rerere_autoupdate\n+\ttest -n \"$gpg_sign_opt\" && echo \"$gpg_sign_opt\" > \"$state_dir\"/gpg_sign_opt\n+\ttest -n \"$signoff\" && echo \"$signoff\" >\"$state_dir\"/signoff\n+}\n+\n+output () {\n+\tcase \"$verbose\" in\n+\t'')\n+\t\toutput=$(\"$@\" 2>&1 )\n+\t\tstatus=$?\n+\t\ttest $status != 0 && printf \"%s\\n\" \"$output\"\n+\t\treturn $status\n+\t\t;;\n+\t*)\n+\t\t\"$@\"\n+\t\t;;\n+\tesac\n+}\n+\n+move_to_original_branch () {\n+\tcase \"$head_name\" in\n+\trefs/*)\n+\t\tmessage=\"rebase finished: $head_name onto $onto\"\n+\t\tgit update-ref -m \"$message\" \\\n+\t\t\t$head_name $(git rev-parse HEAD) $orig_head &&\n+\t\tgit symbolic-ref \\\n+\t\t\t-m \"rebase finished: returning to $head_name\" \\\n+\t\t\tHEAD $head_name ||\n+\t\tdie \"$(eval_gettext \"Could not move back to \\$head_name\")\"\n+\t\t;;\n+\tesac\n+}\n+\n+apply_autostash () {\n+\tif test -f \"$state_dir/autostash\"\n+\tthen\n+\t\tstash_sha1=$(cat \"$state_dir/autostash\")\n+\t\tif git stash apply $stash_sha1 >/dev/null 2>&1\n+\t\tthen\n+\t\t\techo \"$(gettext 'Applied autostash.')\" >&2\n+\t\telse\n+\t\t\tgit stash store -m \"autostash\" -q $stash_sha1 ||\n+\t\t\tdie \"$(eval_gettext \"Cannot store \\$stash_sha1\")\"\n+\t\t\tgettext 'Applying autostash resulted in conflicts.\n+Your changes are safe in the stash.\n+You can run \"git stash pop\" or \"git stash drop\" at any time.\n+' >&2\n+\t\tfi\n+\tfi\n+}\n-- \n2.18.0\n\n"},{"id":"351513","messageId":"20180702091509.15950-4-predatoramigo@gmail.com","threadId":"48795","inReplyTo":"20180702091509.15950-1-predatoramigo@gmail.com","subject":"[PATCH v2 3/4] sequencer: refactor the code to detach HEAD to checkout.c","fromName":"Pratik Karki","fromEmail":"predatoramigo@gmail.com","sentAt":"2018-07-02T09:15:08Z","receivedAt":"2018-07-02T09:16:47Z","isPatch":true,"sender":{"key":"predatoramigo@gmail.com","avatar":"https://avatars.githubusercontent.com/u/12194950?v=4"},"body":"The motivation behind this commit is to extract the core part of\ndo_reset() from sequencer.c and move it to a new detach_head_to()\nfunction in checkout.c.\n\nHere the index only gets locked after performing the first part of\n`do_reset()` rather than before which essentially derives the `oid`\nfrom the specified label/name passed to the `do_reset()` function.\nIt also fixes two bugs: there were two `return error()` statements in\nthe `[new root]` case that would have failed to unlock the index.\n\nThe new function will be used in the next commit by the builtin rebase,\nto perform the initial checkout.\n\nSigned-off-by: Pratik Karki <predatoramigo@gmail.com>\n---\n checkout.c  | 64 +++++++++++++++++++++++++++++++++++++++++++++++++++++\n checkout.h  |  3 +++\n sequencer.c | 58 +++++-------------------------------------------\n 3 files changed, 72 insertions(+), 53 deletions(-)\n\ndiff --git a/checkout.c b/checkout.c\nindex bdefc888b..da68915fd 100644\n--- a/checkout.c\n+++ b/checkout.c\n@@ -2,6 +2,11 @@\n #include \"remote.h\"\n #include \"refspec.h\"\n #include \"checkout.h\"\n+#include \"unpack-trees.h\"\n+#include \"lockfile.h\"\n+#include \"refs.h\"\n+#include \"tree.h\"\n+#include \"cache-tree.h\"\n \n struct tracking_name_data {\n \t/* const */ char *src_ref;\n@@ -42,3 +47,62 @@ const char *unique_tracking_name(const char *name, struct object_id *oid)\n \tfree(cb_data.dst_ref);\n \treturn NULL;\n }\n+\n+int detach_head_to(struct object_id *oid, const char *action,\n+\t\t   const char *reflog_message)\n+{\n+\tstruct strbuf ref_name = STRBUF_INIT;\n+\tstruct tree_desc desc;\n+\tstruct lock_file lock = LOCK_INIT;\n+\tstruct unpack_trees_options unpack_tree_opts;\n+\tstruct tree *tree;\n+\tint ret = 0;\n+\n+\tif (hold_locked_index(&lock, LOCK_REPORT_ON_ERROR) < 0)\n+\t\treturn -1;\n+\n+\tmemset(&unpack_tree_opts, 0, sizeof(unpack_tree_opts));\n+\tsetup_unpack_trees_porcelain(&unpack_tree_opts, action);\n+\tunpack_tree_opts.head_idx = 1;\n+\tunpack_tree_opts.src_index = &the_index;\n+\tunpack_tree_opts.dst_index = &the_index;\n+\tunpack_tree_opts.fn = oneway_merge;\n+\tunpack_tree_opts.merge = 1;\n+\tunpack_tree_opts.update = 1;\n+\n+\tif (read_cache_unmerged()) {\n+\t\trollback_lock_file(&lock);\n+\t\tstrbuf_release(&ref_name);\n+\t\treturn error_resolve_conflict(_(action));\n+\t}\n+\n+\tif (!fill_tree_descriptor(&desc, oid)) {\n+\t\terror(_(\"failed to find tree of %s\"), oid_to_hex(oid));\n+\t\trollback_lock_file(&lock);\n+\t\tfree((void *)desc.buffer);\n+\t\tstrbuf_release(&ref_name);\n+\t\treturn -1;\n+\t}\n+\n+\tif (unpack_trees(1, &desc, &unpack_tree_opts)) {\n+\t\trollback_lock_file(&lock);\n+\t\tfree((void *)desc.buffer);\n+\t\tstrbuf_release(&ref_name);\n+\t\treturn -1;\n+\t}\n+\n+\ttree = parse_tree_indirect(oid);\n+\tprime_cache_tree(&the_index, tree);\n+\n+\tif (write_locked_index(&the_index, &lock, COMMIT_LOCK) < 0)\n+\t\tret = error(_(\"could not write index\"));\n+\tfree((void *)desc.buffer);\n+\n+\tif (!ret)\n+\t\tret = update_ref(reflog_message, \"HEAD\", oid,\n+\t\t\t\t NULL, 0, UPDATE_REFS_MSG_ON_ERR);\n+\n+\tstrbuf_release(&ref_name);\n+\treturn ret;\n+\n+}\ndiff --git a/checkout.h b/checkout.h\nindex 998071117..6ce46cf4e 100644\n--- a/checkout.h\n+++ b/checkout.h\n@@ -10,4 +10,7 @@\n  */\n extern const char *unique_tracking_name(const char *name, struct object_id *oid);\n \n+int detach_head_to(struct object_id *oid, const char *action,\n+\t\t   const char *reflog_message);\n+\n #endif /* CHECKOUT_H */\ndiff --git a/sequencer.c b/sequencer.c\nindex 5354d4d51..106d518f4 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -29,6 +29,7 @@\n #include \"oidset.h\"\n #include \"commit-slab.h\"\n #include \"alias.h\"\n+#include \"checkout.h\"\n \n #define GIT_REFLOG_ACTION \"GIT_REFLOG_ACTION\"\n \n@@ -2756,14 +2757,7 @@ static int do_reset(const char *name, int len, struct replay_opts *opts)\n {\n \tstruct strbuf ref_name = STRBUF_INIT;\n \tstruct object_id oid;\n-\tstruct lock_file lock = LOCK_INIT;\n-\tstruct tree_desc desc;\n-\tstruct tree *tree;\n-\tstruct unpack_trees_options unpack_tree_opts;\n-\tint ret = 0, i;\n-\n-\tif (hold_locked_index(&lock, LOCK_REPORT_ON_ERROR) < 0)\n-\t\treturn -1;\n+\tint i;\n \n \tif (len == 10 && !strncmp(\"[new root]\", name, len)) {\n \t\tif (!opts->have_squash_onto) {\n@@ -2789,56 +2783,14 @@ static int do_reset(const char *name, int len, struct replay_opts *opts)\n \t\tif (get_oid(ref_name.buf, &oid) &&\n \t\t    get_oid(ref_name.buf + strlen(\"refs/rewritten/\"), &oid)) {\n \t\t\terror(_(\"could not read '%s'\"), ref_name.buf);\n-\t\t\trollback_lock_file(&lock);\n \t\t\tstrbuf_release(&ref_name);\n \t\t\treturn -1;\n \t\t}\n \t}\n \n-\tmemset(&unpack_tree_opts, 0, sizeof(unpack_tree_opts));\n-\tsetup_unpack_trees_porcelain(&unpack_tree_opts, \"reset\");\n-\tunpack_tree_opts.head_idx = 1;\n-\tunpack_tree_opts.src_index = &the_index;\n-\tunpack_tree_opts.dst_index = &the_index;\n-\tunpack_tree_opts.fn = oneway_merge;\n-\tunpack_tree_opts.merge = 1;\n-\tunpack_tree_opts.update = 1;\n-\n-\tif (read_cache_unmerged()) {\n-\t\trollback_lock_file(&lock);\n-\t\tstrbuf_release(&ref_name);\n-\t\treturn error_resolve_conflict(_(action_name(opts)));\n-\t}\n-\n-\tif (!fill_tree_descriptor(&desc, &oid)) {\n-\t\terror(_(\"failed to find tree of %s\"), oid_to_hex(&oid));\n-\t\trollback_lock_file(&lock);\n-\t\tfree((void *)desc.buffer);\n-\t\tstrbuf_release(&ref_name);\n-\t\treturn -1;\n-\t}\n-\n-\tif (unpack_trees(1, &desc, &unpack_tree_opts)) {\n-\t\trollback_lock_file(&lock);\n-\t\tfree((void *)desc.buffer);\n-\t\tstrbuf_release(&ref_name);\n-\t\treturn -1;\n-\t}\n-\n-\ttree = parse_tree_indirect(&oid);\n-\tprime_cache_tree(&the_index, tree);\n-\n-\tif (write_locked_index(&the_index, &lock, COMMIT_LOCK) < 0)\n-\t\tret = error(_(\"could not write index\"));\n-\tfree((void *)desc.buffer);\n-\n-\tif (!ret)\n-\t\tret = update_ref(reflog_message(opts, \"reset\", \"'%.*s'\",\n-\t\t\t\t\t\tlen, name), \"HEAD\", &oid,\n-\t\t\t\t NULL, 0, UPDATE_REFS_MSG_ON_ERR);\n-\n-\tstrbuf_release(&ref_name);\n-\treturn ret;\n+\treturn detach_head_to(&oid, action_name(opts),\n+\t\t\t      reflog_message(opts, \"reset\", \"'%.*s'\",\n+\t\t\t\t\t     len, name));\n }\n \n static int do_merge(struct commit *commit, const char *arg, int arg_len,\n-- \n2.18.0\n\n"},{"id":"351514","messageId":"20180702091509.15950-5-predatoramigo@gmail.com","threadId":"48795","inReplyTo":"20180702091509.15950-1-predatoramigo@gmail.com","subject":"[PATCH v2 4/4] builtin/rebase: support running \"git rebase <upstream>\"","fromName":"Pratik Karki","fromEmail":"predatoramigo@gmail.com","sentAt":"2018-07-02T09:15:09Z","receivedAt":"2018-07-02T09:16:51Z","isPatch":true,"sender":{"key":"predatoramigo@gmail.com","avatar":"https://avatars.githubusercontent.com/u/12194950?v=4"},"body":"This patch gives life to the skeleton added in the previous patch.\nThis patch makes real operation happen i.e. by using\n`git -c rebase.usebuiltin=true rebase <upstream>`.\nWith this patch, the basic operation of rebase can be done.\n\nThe current version of the builtin rebase does not, however, make full\nuse of the internals but instead chooses to spawn a couple of Git\nprocesses, still, to make for an easier conversion. There remains a lot\nof room for improvement, left later.\n\nThese backends use Unix shell functions defined both by git-sh-setup.sh\nand git-rebase.sh (we move the latter's into git-rebase--common.sh to\naccommodate for that), so we not only have to source the backend file\nbefore calling the respective Unix shell script function, but we have\nto source git-sh-setup and git-rebase--common before that.\nAnd since this is all done in a Unix shell script snippet, all of this\nis in argv[0]. There will be NULL argv[1] i.e. there are no further\narguments.\n\nThis patch does the *bare* minimum to get `git rebase <upstream>` to\nwork: there is still no option parsing, and only the bare minimum set\nof environment variables are set (in particular, the current revision\nwould be susceptible to bugs where e.g. `rebase_root` could be set by\nmistake before running `git rebase` and the `git-rebase--am` backend\nwould pick up that variable and use it).\n\nIt still calls original `git-legacy-rebase.sh` unless the config\nsetting rebase.useBuiltin is set to true. This patch uses the\ndetach_head_to() function from checkout.c introduced by a previous\ncommit to perform initial checkout.\n\nSigned-off-by: Pratik Karki <predatoramigo@gmail.com>\n---\n builtin/rebase.c | 229 ++++++++++++++++++++++++++++++++++++++++++++++-\n 1 file changed, 228 insertions(+), 1 deletion(-)\n\ndiff --git a/builtin/rebase.c b/builtin/rebase.c\nindex c0c9d6cd2..dc6816e34 100644\n--- a/builtin/rebase.c\n+++ b/builtin/rebase.c\n@@ -9,6 +9,19 @@\n #include \"exec-cmd.h\"\n #include \"argv-array.h\"\n #include \"dir.h\"\n+#include \"packfile.h\"\n+#include \"checkout.h\"\n+#include \"refs.h\"\n+\n+static GIT_PATH_FUNC(apply_dir, \"rebase-apply\");\n+static GIT_PATH_FUNC(merge_dir, \"rebase-merge\");\n+\n+enum rebase_type {\n+\tREBASE_AM,\n+\tREBASE_MERGE,\n+\tREBASE_INTERACTIVE,\n+\tREBASE_PRESERVE_MERGES\n+};\n \n static int use_builtin_rebase(void)\n {\n@@ -28,8 +41,129 @@ static int use_builtin_rebase(void)\n \treturn ret;\n }\n \n+static int apply_autostash(void)\n+{\n+\twarning(\"TODO\");\n+\treturn 0;\n+}\n+\n+struct rebase_options {\n+\tenum rebase_type type;\n+\tconst char *state_dir;\n+\tstruct commit *upstream;\n+\tconst char *upstream_name;\n+\tchar *head_name;\n+\tstruct object_id orig_head;\n+\tstruct commit *onto;\n+\tconst char *onto_name;\n+\tconst char *revisions;\n+\tconst char *root;\n+};\n+\n+static int finish_rebase(struct rebase_options *opts)\n+{\n+\tstruct strbuf dir = STRBUF_INIT;\n+\tconst char *argv_gc_auto[] = { \"gc\", \"--auto\", NULL };\n+\n+\tdelete_ref(NULL, \"REBASE_HEAD\", NULL, REF_NO_DEREF);\n+\tapply_autostash();\n+\tclose_all_packs(the_repository->objects);\n+\t/*\n+\t * We ignore errors in 'gc --auto', since the\n+\t * user should see them.\n+\t */\n+\trun_command_v_opt(argv_gc_auto, RUN_GIT_CMD);\n+\tstrbuf_addstr(&dir, opts->state_dir);\n+\tremove_dir_recursively(&dir, 0);\n+\tstrbuf_release(&dir);\n+\n+\treturn 0;\n+}\n+\n+static struct commit *peel_committish(const char *name)\n+{\n+\tstruct object *obj;\n+\tstruct object_id oid;\n+\tif (get_oid(name, &oid))\n+\t\treturn NULL;\n+\tobj = parse_object(&oid);\n+\treturn (struct commit *)peel_to_type(name, 0, obj, OBJ_COMMIT);\n+}\n+\n+static int run_specific_rebase(struct rebase_options *opts)\n+{\n+\tconst char *argv[] = { NULL, NULL };\n+\tstruct strbuf script_snippet = STRBUF_INIT;\n+\tstruct argv_array env = ARGV_ARRAY_INIT;\n+\tint status;\n+\tconst char *backend, *backend_func;\n+\n+\targv_array_pushf(&env, \"upstream_name=%s\", opts->upstream_name);\n+\targv_array_pushf(&env, \"GIT_DIR=%s\", absolute_path(get_git_dir()));\n+\targv_array_pushf(&env, \"upstream=%s\",\n+\t\t\t\toid_to_hex(&opts->upstream->object.oid));\n+\targv_array_pushf(&env, \"orig_head=%s\", oid_to_hex(&opts->orig_head));\n+\targv_array_pushf(&env, \"onto=%s\",\n+\t\t\t\toid_to_hex(&opts->onto->object.oid));\n+\targv_array_pushf(&env, \"onto_name=%s\", opts->onto_name);\n+\targv_array_pushf(&env, \"revisions=%s\", opts->revisions);\n+\n+\tswitch (opts->type) {\n+\t\tcase REBASE_AM:\n+\t\t\tbackend = \"git-rebase--am\";\n+\t\t\tbackend_func = \"git_rebase__am\";\n+\t\t\tbreak;\n+\t\tcase REBASE_INTERACTIVE:\n+\t\t\tbackend = \"git-rebase--interactive\";\n+\t\t\tbackend_func = \"git_rebase__interactive\";\n+\t\t\tbreak;\n+\t\tcase REBASE_MERGE:\n+\t\t\tbackend = \"git-rebase--merge\";\n+\t\t\tbackend_func = \"git_rebase__merge\";\n+\t\t\tbreak;\n+\t\tcase REBASE_PRESERVE_MERGES:\n+\t\t\tbackend = \"git-rebase--preserve-merges\";\n+\t\t\tbackend_func = \"git_rebase__preserve_merges\";\n+\t\t\tbreak;\n+\t\tdefault:\n+\t\t\tBUG(\"Unhandled rebase type %d\", opts->type);\n+\t\t\tbreak;\n+\t}\n+\n+\tstrbuf_addf(&script_snippet,\n+\t\t    \". git-rebase--common && . %s && %s\",\n+\t\t    backend, backend_func);\n+\targv[0] = script_snippet.buf;\n+\n+\tstatus = run_command_v_opt_cd_env(argv, RUN_USING_SHELL, NULL,\n+\t\t\t\t\t  env.argv);\n+\tif (status == 0)\n+\t\tfinish_rebase(opts);\n+\telse if (status == 2) {\n+\t\tstruct strbuf dir = STRBUF_INIT;\n+\n+\t\tapply_autostash();\n+\t\tstrbuf_addstr(&dir, opts->state_dir);\n+\t\tremove_dir_recursively(&dir, 0);\n+\t\tstrbuf_release(&dir);\n+\t\tdie(\"Nothing to do\");\n+\t}\n+\n+\tstrbuf_release(&script_snippet);\n+\targv_array_clear(&env);\n+\n+\treturn status ? -1 : 0;\n+}\n+\n int cmd_rebase(int argc, const char **argv, const char *prefix)\n {\n+\tstruct rebase_options options = { -1 };\n+\tconst char *branch_name;\n+\tint ret, flags, quiet = 0;\n+\tstruct strbuf msg = STRBUF_INIT;\n+\tstruct strbuf revisions = STRBUF_INIT;\n+\tconst char *restrict_revision = NULL;\n+\n \t/*\n \t* NEEDSWORK: Once the builtin rebase has been tested enough\n \t* and git-legacy-rebase.sh is retired to contrib/, this preamble\n@@ -51,5 +185,98 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \ttrace_repo_setup(prefix);\n \tsetup_work_tree();\n \n-\tdie(\"TODO\");\n+\toptions.type = REBASE_AM;\n+\n+\tswitch (options.type) {\n+\tcase REBASE_AM:\n+\t\toptions.state_dir = apply_dir();\n+\t\tbreak;\n+\tcase REBASE_MERGE:\n+\tcase REBASE_INTERACTIVE:\n+\tcase REBASE_PRESERVE_MERGES:\n+\t\toptions.state_dir = merge_dir();\n+\t\tbreak;\n+\t}\n+\tif (!options.root) {\n+\t\tif (argc != 2)\n+\t\t\tdie(\"TODO: handle @{upstream}\");\n+\t\telse {\n+\t\t\toptions.upstream_name = argv[1];\n+\t\t\targc--;\n+\t\t\targv++;\n+\t\t\tif (!strcmp(options.upstream_name, \"-\"))\n+\t\t\t\toptions.upstream_name = \"@{-1}\";\n+\t\t}\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} else\n+\t\tdie(\"TODO: upstream for --root\");\n+\n+\t/* Make sure the branch to rebase onto is valid. */\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} else {\n+\t\toptions.onto = peel_committish(options.onto_name);\n+\t\tif (!options.onto)\n+\t\t\tdie(_(\"Does not point to a valid commit '%s'\"),\n+\t\t\t\toptions.onto_name);\n+\t}\n+\n+\t/*\n+\t* If the branch to rebase is given, that is the branch we will rebase\n+\t* branch_name -- branch/commit being rebased, or 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*/\n+\tif (argc > 1)\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+\t\toptions.head_name =\n+\t\t\txstrdup_or_null(resolve_ref_unsafe(\"HEAD\", 0, NULL,\n+\t\t\t\t\t &flags));\n+\t\tif (!options.head_name)\n+\t\t\tdie(_(\"No such ref: %s\"), \"HEAD\");\n+\t\tif (flags & REF_ISSYMREF) {\n+\t\t\tif (!skip_prefix(options.head_name,\n+\t\t\t\t\t \"refs/heads/\", &branch_name))\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\tbranch_name = \"HEAD\";\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+\n+\t/* Detach HEAD and reset the tree */\n+\tif (!quiet)\n+\t\tprintf(\"First, rewinding head to replay your work on top of it...\");\n+\n+\tstrbuf_addf(&msg, \"rebase: checkout %s\", options.onto_name);\n+\tif (detach_head_to(&options.onto->object.oid, \"checkout\", msg.buf))\n+\t\tdie(_(\"Could not detach HEAD\"));\n+\tstrbuf_release(&msg);\n+\tif (update_ref(\"rebase\", \"ORIG_HEAD\", &options.orig_head, NULL, 0,\n+\t\t       UPDATE_REFS_MSG_ON_ERR) < 0)\n+\t\tdie(_(\"Could not update ORIG_HEAD to '%s'\"),\n+\t\t    oid_to_hex(&options.orig_head));\n+\n+\tstrbuf_addf(&revisions, \"%s..%s\",\n+\t\t!options.root ? oid_to_hex(&options.onto->object.oid) :\n+\t\t    (restrict_revision ? restrict_revision :\n+\t\t\t    oid_to_hex(&options.upstream->object.oid)),\n+\t\t\t    oid_to_hex(&options.orig_head));\n+\n+\toptions.revisions = revisions.buf;\n+\n+\tret = !!run_specific_rebase(&options);\n+\n+\tstrbuf_release(&revisions);\n+\tfree(options.head_name);\n+\treturn ret;\n }\n-- \n2.18.0\n\n"},{"id":"351655","messageId":"xmqqva9wni1f.fsf@gitster-ct.c.googlers.com","threadId":"48795","inReplyTo":"20180702091509.15950-2-predatoramigo@gmail.com","subject":"Re: [PATCH v2 1/4] rebase: start implementing it as a builtin","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2018-07-03T21:09:00Z","receivedAt":"2018-07-03T21:09:07Z","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 imitates the strategy that was used to convert the\n> difftool to a builtin, see be8a90e (difftool: add a skeleton for the\n> upcoming builtin, 2017-01-17) for details: This commit renames the\n> shell script `git-rebase.sh` to `git-legacy-rebase.sh` and hands off to\n> it by default.\n\nI'd appreciate it if mentors can teach a bit more log message\nwriting to students, thanks.\n\n> diff --git a/builtin/rebase.c b/builtin/rebase.c\n> new file mode 100644\n> index 000000000..c0c9d6cd2\n> --- /dev/null\n> +++ b/builtin/rebase.c\n> @@ -0,0 +1,55 @@\n> +/*\n> + * \"git rebase\" builtin command\n\nNice ;-)\n\n> + * Copyright (c) 2018 Pratik Karki\n> + */\n> +\n> +#include \"builtin.h\"\n> +#include \"run-command.h\"\n> +#include \"exec-cmd.h\"\n> +#include \"argv-array.h\"\n> +#include \"dir.h\"\n> +\n> +static int use_builtin_rebase(void)\n> +{\n> +\tstruct child_process cp = CHILD_PROCESS_INIT;\n> +\tstruct strbuf out = STRBUF_INIT;\n> +\tint ret;\n> +\n> +\targv_array_pushl(&cp.args,\n> +\t\t\t \"config\", \"--bool\", \"rebase.usebuiltin\", NULL);\n> +\tcp.git_cmd = 1;\n> +\tif (capture_command(&cp, &out, 6))\n> +\t\treturn 0;\n> +\n> +\tstrbuf_trim(&out);\n> +\tret = !strcmp(\"true\", out.buf);\n> +\tstrbuf_release(&out);\n> +\treturn ret;\n> +}\n\nOK.  As we give \"--bool\", it is perfectly OK to check with \"true\"\nand no other forms of positive setting.\n\n> +int cmd_rebase(int argc, const char **argv, const char *prefix)\n> +{\n> +\t/*\n> +\t* NEEDSWORK: Once the builtin rebase has been tested enough\n> +\t* and git-legacy-rebase.sh is retired to contrib/, this preamble\n\nAlign these asterisks, i.e.\n\n\t/*\n\t * NEEDSWORK: ...\n\t */\n\n> +\tif (!use_builtin_rebase()) {\n> +\t\tconst char *path = mkpath(\"%s/git-legacy-rebase\",\n> +\t\t\t\t\t  git_exec_path());\n> +\n> +\t\tif (sane_execvp(path, (char **)argv) < 0)\n> +\t\t\tdie_errno(\"could not exec %s\", path);\n> +\n> +\t\treturn 0;\n\nHmph, I know this was inherited from the old commit you modelled\nthis patch after, but can sane_execvp() ever give us control back\nwith non-negative value returned?  IOW I am wondering if this should\nbe more like\n\n\tif (sane_execvp(...) < 0)\n\t\tdie_errno(...);\n\telse\n\t\tdie(\"sane_execvp() returned???\");\n\nNot worth a reroll, but something to think about.\n\n> diff --git a/git-rebase.sh b/git-legacy-rebase.sh\n> similarity index 100%\n> rename from git-rebase.sh\n> rename to git-legacy-rebase.sh\n> diff --git a/git.c b/git.c\n> index 9dbe6ffaa..bacfefb2d 100644\n> --- a/git.c\n> +++ b/git.c\n> @@ -518,6 +518,12 @@ static struct cmd_struct commands[] = {\n>  \t{ \"pull\", cmd_pull, RUN_SETUP | NEED_WORK_TREE },\n>  \t{ \"push\", cmd_push, RUN_SETUP },\n>  \t{ \"read-tree\", cmd_read_tree, RUN_SETUP | SUPPORT_SUPER_PREFIX},\n> +\t/*\n> +\t *NEEDSWORK: Until the rebase is independent and needs no redirection\n> +\t to rebase shell script this is kept as is, then should be changed to\n> +\t RUN_SETUP | NEED_WORK_TREE\n> +\t*/\n\nLikewise.\n\n> +\t{ \"rebase\", cmd_rebase },\n>  \t{ \"rebase--helper\", cmd_rebase__helper, RUN_SETUP | NEED_WORK_TREE },\n>  \t{ \"receive-pack\", cmd_receive_pack },\n>  \t{ \"reflog\", cmd_reflog, RUN_SETUP },\n"},{"id":"351656","messageId":"xmqqr2kknhuj.fsf@gitster-ct.c.googlers.com","threadId":"48795","inReplyTo":"20180702091509.15950-3-predatoramigo@gmail.com","subject":"Re: [PATCH v2 2/4] rebase: refactor common shell functions into their own file","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2018-07-03T21:13:08Z","receivedAt":"2018-07-03T21:13:13Z","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 function present in `git-legacy-rebase.sh` are used by backends\n> so, this refactor tries to extract the functions out so that, the\n> `git-legacy-rebase.sh` can be retired easily as the\n> `git-rebase--common.sh` will provide the functions for now.\n\nMakes sense.\n"},{"id":"351657","messageId":"xmqqmuv8nh7v.fsf@gitster-ct.c.googlers.com","threadId":"48795","inReplyTo":"20180702091509.15950-4-predatoramigo@gmail.com","subject":"Re: [PATCH v2 3/4] sequencer: refactor the code to detach HEAD to checkout.c","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2018-07-03T21:26:44Z","receivedAt":"2018-07-03T21:26:50Z","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 motivation behind this commit is to extract the core part of\n> do_reset() from sequencer.c and move it to a new detach_head_to()\n> function in checkout.c.\n>\n> Here the index only gets locked after performing the first part of\n> `do_reset()` rather than before which essentially derives the `oid`\n> from the specified label/name passed to the `do_reset()` function.\n> It also fixes two bugs: there were two `return error()` statements in\n> the `[new root]` case that would have failed to unlock the index.\n>\n> The new function will be used in the next commit by the builtin rebase,\n> to perform the initial checkout.\n\nI like the split of do_reset() into this \"detach-to\" part that is\nless specific to replaying an existing commit and the rest, which\nas you said incidentally corrects the locking issue.\n\nIt is not clear to me why checkout.[ch] is a better place to house\nthis function, though.\n"},{"id":"351660","messageId":"xmqqfu10nghi.fsf@gitster-ct.c.googlers.com","threadId":"48795","inReplyTo":"20180702091509.15950-5-predatoramigo@gmail.com","subject":"Re: [PATCH v2 4/4] builtin/rebase: support running \"git rebase <upstream>\"","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2018-07-03T21:42:33Z","receivedAt":"2018-07-03T21:42:38Z","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> +static struct commit *peel_committish(const char *name)\n> +{\n> +\tstruct object *obj;\n> +\tstruct object_id oid;\n\nIt by itself is not a big enough deal to warrant a reroll, but\nplease make it a habit to leave a blank line between the\ndeclarations and the first statement (i.e. here), to help readers.\n\n> +\tif (get_oid(name, &oid))\n> +\t\treturn NULL;\n> +\tobj = parse_object(&oid);\n> +\treturn (struct commit *)peel_to_type(name, 0, obj, OBJ_COMMIT);\n> +}\n> +\n\n> +{\n> +\tconst char *argv[] = { NULL, NULL };\n> +\tstruct strbuf script_snippet = STRBUF_INIT;\n> +\tstruct argv_array env = ARGV_ARRAY_INIT;\n> +\tint status;\n> +\tconst char *backend, *backend_func;\n> +\n> +\targv_array_pushf(&env, \"upstream_name=%s\", opts->upstream_name);\n> +\targv_array_pushf(&env, \"GIT_DIR=%s\", absolute_path(get_git_dir()));\n> +\targv_array_pushf(&env, \"upstream=%s\",\n> +\t\t\t\toid_to_hex(&opts->upstream->object.oid));\n> +\targv_array_pushf(&env, \"orig_head=%s\", oid_to_hex(&opts->orig_head));\n> +\targv_array_pushf(&env, \"onto=%s\",\n> +\t\t\t\toid_to_hex(&opts->onto->object.oid));\n> +\targv_array_pushf(&env, \"onto_name=%s\", opts->onto_name);\n> +\targv_array_pushf(&env, \"revisions=%s\", opts->revisions);\n> +\n> +\tswitch (opts->type) {\n> +\t\tcase REBASE_AM:\n> +\t\t\tbackend = \"git-rebase--am\";\n> +\t\t\tbackend_func = \"git_rebase__am\";\n> +\t\t\tbreak;\n> +\t\tcase REBASE_INTERACTIVE:\n> +\t\t\tbackend = \"git-rebase--interactive\";\n> +\t\t\tbackend_func = \"git_rebase__interactive\";\n> +\t\t\tbreak;\n> +\t\tcase REBASE_MERGE:\n> +\t\t\tbackend = \"git-rebase--merge\";\n> +\t\t\tbackend_func = \"git_rebase__merge\";\n> +\t\t\tbreak;\n> +\t\tcase REBASE_PRESERVE_MERGES:\n> +\t\t\tbackend = \"git-rebase--preserve-merges\";\n> +\t\t\tbackend_func = \"git_rebase__preserve_merges\";\n> +\t\t\tbreak;\n> +\t\tdefault:\n> +\t\t\tBUG(\"Unhandled rebase type %d\", opts->type);\n> +\t\t\tbreak;\n\nDe-dent these lines so that case/default and switch all sit on the\nsame column, and the body of each case arm is indented one level\ndeeper than the case labels.\n\n> +\t}\n> +\n> +\tstrbuf_addf(&script_snippet,\n> +\t\t    \". git-rebase--common && . %s && %s\",\n> +\t\t    backend, backend_func);\n> +\targv[0] = script_snippet.buf;\n> +\n> +\tstatus = run_command_v_opt_cd_env(argv, RUN_USING_SHELL, NULL,\n> +\t\t\t\t\t  env.argv);\n\nHmph.  These shell variables that tell rebase backend scriptlets\nwhat rebase frontend figured out about the request and current state\nused to be just plain shell variables that are not exported.  Now\nthey are exported and visible even to subprocesses these scriptlets\nspawn.  That does not sound safe at all, especially GIT_DIR being\namong these variables (git-sh-setup sets GIT_DIR but does not export\nit and that has been very much deliberate).\n\nYou should actually be able to avoid exporthing them by building\nthese variable assignment into script_snippet (you need to quote the\nvalues properly, using quote.c::sq_quote_buf() etc.), I think, and\nthat would be a more faithful-to-the-original safe covnersion.\n\nThanks for a pleasant read.  This step smells more like WIP, but I\ncan see it is already moving in the right direction.  The previous\nones (except for the issues I noticed and sent responses separately)\nlooked more-or-less good, too.\n\n\n"},{"id":"351769","messageId":"20180706120815.17851-1-predatoramigo@gmail.com","threadId":"48795","inReplyTo":"20180628074655.5756-1-predatoramigo@gmail.com","subject":"[GSoC] [PATCH v3 0/4] rebase: rewrite rebase in C","fromName":"Pratik Karki","fromEmail":"predatoramigo@gmail.com","sentAt":"2018-07-06T12:08:11Z","receivedAt":"2018-07-06T12:08:48Z","isPatch":true,"sender":{"key":"predatoramigo@gmail.com","avatar":"https://avatars.githubusercontent.com/u/12194950?v=4"},"body":"As a GSoC project, I have been working on the builtin rebase.\n\nThe motivation behind the rewrite of rebase i.e. from shell script to C\nare for following reasons:\n\n1.  Writing shell scripts and getting it to production is much faster\n    than doing the equivalent in C but lacks in performance and extra\n    workarounds are needed for non-POSIX platforms.\n\n2.  Git for Windows is at loss as the installer size increases due to\n    addition of extra dependencies for the shell scripts which are usually\n    available in POSIX compliant platforms.\n\nThis series of patches serves to demonstrate a minimal builtin rebase\nwhich supports running `git rebase <upstream>` and also serves to ask for\nreviews.\n\nChanges since v2:\n\n  -  Fix commit messages of patches.\n\n  -  Acknowledge Junio's reviews.\n\n  -  Demonstrate an alternative approach to setting of environment variables\n     via `run_command_v_opt_cd_env()` which would be visible by spawned\n     process from rebase backends as this is not safe.\n\nPratik Karki (4):\n  rebase: start implementing it as a builtin\n  rebase: refactor common shell functions into their own file\n  sequencer: refactor the code to detach HEAD to checkout.c\n  builtin/rebase: support running \"git rebase <upstream>\"\n\n .gitignore                            |   2 +\n Makefile                              |   4 +-\n builtin.h                             |   1 +\n builtin/rebase.c                      | 291 ++++++++++++++++++++++++++\n checkout.c                            |  64 ++++++\n checkout.h                            |   3 +\n git-rebase.sh => git-legacy-rebase.sh |  62 +-----\n git-rebase--common.sh                 |  61 ++++++\n git.c                                 |   6 +\n sequencer.c                           |  58 +----\n 10 files changed, 437 insertions(+), 115 deletions(-)\n create mode 100644 builtin/rebase.c\n rename git-rebase.sh => git-legacy-rebase.sh (91%)\n create mode 100644 git-rebase--common.sh\n\n-- \n2.18.0\n\n"},{"id":"351770","messageId":"20180706120815.17851-2-predatoramigo@gmail.com","threadId":"48795","inReplyTo":"20180706120815.17851-1-predatoramigo@gmail.com","subject":"[PATCH v3 1/4] rebase: start implementing it as a builtin","fromName":"Pratik Karki","fromEmail":"predatoramigo@gmail.com","sentAt":"2018-07-06T12:08:12Z","receivedAt":"2018-07-06T12:08:53Z","isPatch":true,"sender":{"key":"predatoramigo@gmail.com","avatar":"https://avatars.githubusercontent.com/u/12194950?v=4"},"body":"This commit imitates the strategy that was used to convert the\ndifftool to a builtin. We start by renaming the shell script\n`git-rebase.sh` to `git-legacy-rebase.sh` and introduce a\n`builtin/rebase.c` that simply executes the shell script version,\nunless the config setting `rebase.useBuiltin` is set to `true`.\n\nThe motivation behind this is to rewrite all the functionality of the\nshell script version in the aforementioned `rebase.c`, one by one and\nbe able to conveniently test new features by configuring\n`rebase.useBuiltin`.\n\nWe intentionally avoid reading the config directly to avoid\nmessing up the GIT_* environment variables when we need to fall back to\nexec()ing the shell script. The test of builtin rebase can be done by\n`git -c rebase.useBuiltin=true rebase ...`\n\nSigned-off-by: Pratik Karki <predatoramigo@gmail.com>\n---\n .gitignore                            |  1 +\n Makefile                              |  3 +-\n builtin.h                             |  1 +\n builtin/rebase.c                      | 56 +++++++++++++++++++++++++++\n git-rebase.sh => git-legacy-rebase.sh |  0\n git.c                                 |  6 +++\n 6 files changed, 66 insertions(+), 1 deletion(-)\n create mode 100644 builtin/rebase.c\n rename git-rebase.sh => git-legacy-rebase.sh (100%)\n\ndiff --git a/.gitignore b/.gitignore\nindex 3284a1e9b1..ec23959014 100644\n--- a/.gitignore\n+++ b/.gitignore\n@@ -78,6 +78,7 @@\n /git-init-db\n /git-interpret-trailers\n /git-instaweb\n+/git-legacy-rebase\n /git-log\n /git-ls-files\n /git-ls-remote\ndiff --git a/Makefile b/Makefile\nindex 0cb6590f24..e88fe2e5fb 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -609,7 +609,7 @@ SCRIPT_SH += git-merge-one-file.sh\n SCRIPT_SH += git-merge-resolve.sh\n SCRIPT_SH += git-mergetool.sh\n SCRIPT_SH += git-quiltimport.sh\n-SCRIPT_SH += git-rebase.sh\n+SCRIPT_SH += git-legacy-rebase.sh\n SCRIPT_SH += git-remote-testgit.sh\n SCRIPT_SH += git-request-pull.sh\n SCRIPT_SH += git-stash.sh\n@@ -1059,6 +1059,7 @@ BUILTIN_OBJS += builtin/prune.o\n BUILTIN_OBJS += builtin/pull.o\n BUILTIN_OBJS += builtin/push.o\n BUILTIN_OBJS += builtin/read-tree.o\n+BUILTIN_OBJS += builtin/rebase.o\n BUILTIN_OBJS += builtin/rebase--helper.o\n BUILTIN_OBJS += builtin/receive-pack.o\n BUILTIN_OBJS += builtin/reflog.o\ndiff --git a/builtin.h b/builtin.h\nindex 0362f1ce25..44651a447f 100644\n--- a/builtin.h\n+++ b/builtin.h\n@@ -202,6 +202,7 @@ extern int cmd_prune_packed(int argc, const char **argv, const char *prefix);\n extern int cmd_pull(int argc, const char **argv, const char *prefix);\n extern int cmd_push(int argc, const char **argv, const char *prefix);\n extern int cmd_read_tree(int argc, const char **argv, const char *prefix);\n+extern int cmd_rebase(int argc, const char **argv, const char *prefix);\n extern int cmd_rebase__helper(int argc, const char **argv, const char *prefix);\n extern int cmd_receive_pack(int argc, const char **argv, const char *prefix);\n extern int cmd_reflog(int argc, const char **argv, const char *prefix);\ndiff --git a/builtin/rebase.c b/builtin/rebase.c\nnew file mode 100644\nindex 0000000000..fab7fca37e\n--- /dev/null\n+++ b/builtin/rebase.c\n@@ -0,0 +1,56 @@\n+/*\n+ * \"git rebase\" builtin command\n+ *\n+ * Copyright (c) 2018 Pratik Karki\n+ */\n+\n+#include \"builtin.h\"\n+#include \"run-command.h\"\n+#include \"exec-cmd.h\"\n+#include \"argv-array.h\"\n+#include \"dir.h\"\n+\n+static int use_builtin_rebase(void)\n+{\n+\tstruct child_process cp = CHILD_PROCESS_INIT;\n+\tstruct strbuf out = STRBUF_INIT;\n+\tint ret;\n+\n+\targv_array_pushl(&cp.args,\n+\t\t\t \"config\", \"--bool\", \"rebase.usebuiltin\", NULL);\n+\tcp.git_cmd = 1;\n+\tif (capture_command(&cp, &out, 6))\n+\t\treturn 0;\n+\n+\tstrbuf_trim(&out);\n+\tret = !strcmp(\"true\", out.buf);\n+\tstrbuf_release(&out);\n+\treturn ret;\n+}\n+\n+int cmd_rebase(int argc, const char **argv, const char *prefix)\n+{\n+\t/*\n+\t * NEEDSWORK: Once the builtin rebase has been tested enough\n+\t * and git-legacy-rebase.sh is retired to contrib/, this preamble\n+\t * can be removed.\n+\t */\n+\n+\tif (!use_builtin_rebase()) {\n+\t\tconst char *path = mkpath(\"%s/git-legacy-rebase\",\n+\t\t\t\t\t  git_exec_path());\n+\n+\t\tif (sane_execvp(path, (char **)argv) < 0)\n+\t\t\tdie_errno(\"could not exec %s\", path);\n+\t\telse\n+\t\t\tdie(\"sane_execvp() returned???\");\n+\t}\n+\n+\tif (argc != 2)\n+\t\tdie(\"Usage: %s <base>\", argv[0]);\n+\tprefix = setup_git_directory();\n+\ttrace_repo_setup(prefix);\n+\tsetup_work_tree();\n+\n+\tdie(\"TODO\");\n+}\ndiff --git a/git-rebase.sh b/git-legacy-rebase.sh\nsimilarity index 100%\nrename from git-rebase.sh\nrename to git-legacy-rebase.sh\ndiff --git a/git.c b/git.c\nindex 9dbe6ffaa7..0e35632464 100644\n--- a/git.c\n+++ b/git.c\n@@ -518,6 +518,12 @@ static struct cmd_struct commands[] = {\n \t{ \"pull\", cmd_pull, RUN_SETUP | NEED_WORK_TREE },\n \t{ \"push\", cmd_push, RUN_SETUP },\n \t{ \"read-tree\", cmd_read_tree, RUN_SETUP | SUPPORT_SUPER_PREFIX},\n+\t/*\n+\t * NEEDSWORK: Until the rebase is independent and needs no redirection\n+\t * to rebase shell script this is kept as is, then should be changed to\n+\t * RUN_SETUP | NEED_WORK_TREE\n+\t */\n+\t{ \"rebase\", cmd_rebase },\n \t{ \"rebase--helper\", cmd_rebase__helper, RUN_SETUP | NEED_WORK_TREE },\n \t{ \"receive-pack\", cmd_receive_pack },\n \t{ \"reflog\", cmd_reflog, RUN_SETUP },\n-- \n2.18.0\n\n"},{"id":"351771","messageId":"20180706120815.17851-3-predatoramigo@gmail.com","threadId":"48795","inReplyTo":"20180706120815.17851-1-predatoramigo@gmail.com","subject":"[PATCH v3 2/4] rebase: refactor common shell functions into their own file","fromName":"Pratik Karki","fromEmail":"predatoramigo@gmail.com","sentAt":"2018-07-06T12:08:13Z","receivedAt":"2018-07-06T12:08:58Z","isPatch":true,"sender":{"key":"predatoramigo@gmail.com","avatar":"https://avatars.githubusercontent.com/u/12194950?v=4"},"body":"The functions present in `git-legacy-rebase.sh` are used by the rebase\nbackends as they are implemented as shell script functions in the\n`git-rebase--<backend>` files.\n\nTo make the `builtin/rebase.c` work, we have to provide support via\na Unix shell script snippet that uses these functions and so, we\nwant to use the rebase backends *directly* from the builtin rebase\nwithout going through `git-legacy-rebase.sh`.\n\nThis commit extracts the functions to a separate file,\n`git-rebase--common`, that will be read by `git-legacy-rebase.sh` and\nby the shell script snippets which will be used extensively in the\nfollowing commits.\n\nSigned-off-by: Pratik Karki <predatoramigo@gmail.com>\n---\n .gitignore            |  1 +\n Makefile              |  1 +\n git-legacy-rebase.sh  | 62 +------------------------------------------\n git-rebase--common.sh | 61 ++++++++++++++++++++++++++++++++++++++++++\n 4 files changed, 64 insertions(+), 61 deletions(-)\n create mode 100644 git-rebase--common.sh\n\ndiff --git a/.gitignore b/.gitignore\nindex ec23959014..824141cba1 100644\n--- a/.gitignore\n+++ b/.gitignore\n@@ -117,6 +117,7 @@\n /git-read-tree\n /git-rebase\n /git-rebase--am\n+/git-rebase--common\n /git-rebase--helper\n /git-rebase--interactive\n /git-rebase--merge\ndiff --git a/Makefile b/Makefile\nindex e88fe2e5fb..163e52ad1a 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -619,6 +619,7 @@ SCRIPT_SH += git-web--browse.sh\n SCRIPT_LIB += git-mergetool--lib\n SCRIPT_LIB += git-parse-remote\n SCRIPT_LIB += git-rebase--am\n+SCRIPT_LIB += git-rebase--common\n SCRIPT_LIB += git-rebase--interactive\n SCRIPT_LIB += git-rebase--preserve-merges\n SCRIPT_LIB += git-rebase--merge\ndiff --git a/git-legacy-rebase.sh b/git-legacy-rebase.sh\nindex 19bdebb480..240aac507c 100755\n--- a/git-legacy-rebase.sh\n+++ b/git-legacy-rebase.sh\n@@ -102,6 +102,7 @@ case \"$(git config --bool commit.gpgsign)\" in\n true)\tgpg_sign_opt=-S ;;\n *)\tgpg_sign_opt= ;;\n esac\n+. git-rebase--common\n \n read_basic_state () {\n \ttest -f \"$state_dir/head-name\" &&\n@@ -132,67 +133,6 @@ read_basic_state () {\n \t}\n }\n \n-write_basic_state () {\n-\techo \"$head_name\" > \"$state_dir\"/head-name &&\n-\techo \"$onto\" > \"$state_dir\"/onto &&\n-\techo \"$orig_head\" > \"$state_dir\"/orig-head &&\n-\techo \"$GIT_QUIET\" > \"$state_dir\"/quiet &&\n-\ttest t = \"$verbose\" && : > \"$state_dir\"/verbose\n-\ttest -n \"$strategy\" && echo \"$strategy\" > \"$state_dir\"/strategy\n-\ttest -n \"$strategy_opts\" && echo \"$strategy_opts\" > \\\n-\t\t\"$state_dir\"/strategy_opts\n-\ttest -n \"$allow_rerere_autoupdate\" && echo \"$allow_rerere_autoupdate\" > \\\n-\t\t\"$state_dir\"/allow_rerere_autoupdate\n-\ttest -n \"$gpg_sign_opt\" && echo \"$gpg_sign_opt\" > \"$state_dir\"/gpg_sign_opt\n-\ttest -n \"$signoff\" && echo \"$signoff\" >\"$state_dir\"/signoff\n-}\n-\n-output () {\n-\tcase \"$verbose\" in\n-\t'')\n-\t\toutput=$(\"$@\" 2>&1 )\n-\t\tstatus=$?\n-\t\ttest $status != 0 && printf \"%s\\n\" \"$output\"\n-\t\treturn $status\n-\t\t;;\n-\t*)\n-\t\t\"$@\"\n-\t\t;;\n-\tesac\n-}\n-\n-move_to_original_branch () {\n-\tcase \"$head_name\" in\n-\trefs/*)\n-\t\tmessage=\"rebase finished: $head_name onto $onto\"\n-\t\tgit update-ref -m \"$message\" \\\n-\t\t\t$head_name $(git rev-parse HEAD) $orig_head &&\n-\t\tgit symbolic-ref \\\n-\t\t\t-m \"rebase finished: returning to $head_name\" \\\n-\t\t\tHEAD $head_name ||\n-\t\tdie \"$(eval_gettext \"Could not move back to \\$head_name\")\"\n-\t\t;;\n-\tesac\n-}\n-\n-apply_autostash () {\n-\tif test -f \"$state_dir/autostash\"\n-\tthen\n-\t\tstash_sha1=$(cat \"$state_dir/autostash\")\n-\t\tif git stash apply $stash_sha1 >/dev/null 2>&1\n-\t\tthen\n-\t\t\techo \"$(gettext 'Applied autostash.')\" >&2\n-\t\telse\n-\t\t\tgit stash store -m \"autostash\" -q $stash_sha1 ||\n-\t\t\tdie \"$(eval_gettext \"Cannot store \\$stash_sha1\")\"\n-\t\t\tgettext 'Applying autostash resulted in conflicts.\n-Your changes are safe in the stash.\n-You can run \"git stash pop\" or \"git stash drop\" at any time.\n-' >&2\n-\t\tfi\n-\tfi\n-}\n-\n finish_rebase () {\n \trm -f \"$(git rev-parse --git-path REBASE_HEAD)\"\n \tapply_autostash &&\ndiff --git a/git-rebase--common.sh b/git-rebase--common.sh\nnew file mode 100644\nindex 0000000000..5ba0603924\n--- /dev/null\n+++ b/git-rebase--common.sh\n@@ -0,0 +1,61 @@\n+\n+write_basic_state () {\n+\techo \"$head_name\" > \"$state_dir\"/head-name &&\n+\techo \"$onto\" > \"$state_dir\"/onto &&\n+\techo \"$orig_head\" > \"$state_dir\"/orig-head &&\n+\techo \"$GIT_QUIET\" > \"$state_dir\"/quiet &&\n+\ttest t = \"$verbose\" && : > \"$state_dir\"/verbose\n+\ttest -n \"$strategy\" && echo \"$strategy\" > \"$state_dir\"/strategy\n+\ttest -n \"$strategy_opts\" && echo \"$strategy_opts\" > \\\n+\t\t\"$state_dir\"/strategy_opts\n+\ttest -n \"$allow_rerere_autoupdate\" && echo \"$allow_rerere_autoupdate\" > \\\n+\t\t\"$state_dir\"/allow_rerere_autoupdate\n+\ttest -n \"$gpg_sign_opt\" && echo \"$gpg_sign_opt\" > \"$state_dir\"/gpg_sign_opt\n+\ttest -n \"$signoff\" && echo \"$signoff\" >\"$state_dir\"/signoff\n+}\n+\n+apply_autostash () {\n+\tif test -f \"$state_dir/autostash\"\n+\tthen\n+\t\tstash_sha1=$(cat \"$state_dir/autostash\")\n+\t\tif git stash apply $stash_sha1 >/dev/null 2>&1\n+\t\tthen\n+\t\t\techo \"$(gettext 'Applied autostash.')\" >&2\n+\t\telse\n+\t\t\tgit stash store -m \"autostash\" -q $stash_sha1 ||\n+\t\t\tdie \"$(eval_gettext \"Cannot store \\$stash_sha1\")\"\n+\t\t\tgettext 'Applying autostash resulted in conflicts.\n+Your changes are safe in the stash.\n+You can run \"git stash pop\" or \"git stash drop\" at any time.\n+' >&2\n+\t\tfi\n+\tfi\n+}\n+\n+move_to_original_branch () {\n+\tcase \"$head_name\" in\n+\trefs/*)\n+\t\tmessage=\"rebase finished: $head_name onto $onto\"\n+\t\tgit update-ref -m \"$message\" \\\n+\t\t\t$head_name $(git rev-parse HEAD) $orig_head &&\n+\t\tgit symbolic-ref \\\n+\t\t\t-m \"rebase finished: returning to $head_name\" \\\n+\t\t\tHEAD $head_name ||\n+\t\tdie \"$(eval_gettext \"Could not move back to \\$head_name\")\"\n+\t\t;;\n+\tesac\n+}\n+\n+output () {\n+\tcase \"$verbose\" in\n+\t'')\n+\t\toutput=$(\"$@\" 2>&1 )\n+\t\tstatus=$?\n+\t\ttest $status != 0 && printf \"%s\\n\" \"$output\"\n+\t\treturn $status\n+\t\t;;\n+\t*)\n+\t\t\"$@\"\n+\t\t;;\n+\tesac\n+}\n-- \n2.18.0\n\n"},{"id":"351772","messageId":"20180706120815.17851-4-predatoramigo@gmail.com","threadId":"48795","inReplyTo":"20180706120815.17851-1-predatoramigo@gmail.com","subject":"[PATCH v3 3/4] sequencer: refactor the code to detach HEAD to checkout.c","fromName":"Pratik Karki","fromEmail":"predatoramigo@gmail.com","sentAt":"2018-07-06T12:08:14Z","receivedAt":"2018-07-06T12:09:02Z","isPatch":true,"sender":{"key":"predatoramigo@gmail.com","avatar":"https://avatars.githubusercontent.com/u/12194950?v=4"},"body":"In the upcoming builtin rebase, we will have to start by detaching\nthe HEAD, just like shell script version does. Essentially, we have\nto do the same thing as `git checkout -q <revision>^0 --`, in pure C.\n\nThe aforementioned functionality was already present in `sequencer.c`\nin `do_reset()` function. But `do_reset()` performs more than detaching\nthe HEAD, and performs action specific to `sequencer.c`.\n\nSo this commit refactors out that part from `do_reset()`, and moves it\nto a new function called `detach_head_to()`. As this function has\nnothing to do with the sequencer, and everything to do with what `git\ncheckout -q <revision>^0 --` does, we move that function to checkout.c.\n\nThis refactoring actually introduces a slight change in behavior:\npreviously, the index was locked before parsing the argument to the\ntodo command `reset`, while it now gets locked *after* that, in the\n`detach_head_to()` function.\n\nIt does not make a huge difference, and the upside is that this closes\na few (unlikely) code paths where the index would not be unlocked upon\nerror.\n\nSigned-off-by: Pratik Karki <predatoramigo@gmail.com>\n---\n checkout.c  | 64 +++++++++++++++++++++++++++++++++++++++++++++++++++++\n checkout.h  |  3 +++\n sequencer.c | 58 +++++-------------------------------------------\n 3 files changed, 72 insertions(+), 53 deletions(-)\n\ndiff --git a/checkout.c b/checkout.c\nindex bdefc888ba..da68915fd7 100644\n--- a/checkout.c\n+++ b/checkout.c\n@@ -2,6 +2,11 @@\n #include \"remote.h\"\n #include \"refspec.h\"\n #include \"checkout.h\"\n+#include \"unpack-trees.h\"\n+#include \"lockfile.h\"\n+#include \"refs.h\"\n+#include \"tree.h\"\n+#include \"cache-tree.h\"\n \n struct tracking_name_data {\n \t/* const */ char *src_ref;\n@@ -42,3 +47,62 @@ const char *unique_tracking_name(const char *name, struct object_id *oid)\n \tfree(cb_data.dst_ref);\n \treturn NULL;\n }\n+\n+int detach_head_to(struct object_id *oid, const char *action,\n+\t\t   const char *reflog_message)\n+{\n+\tstruct strbuf ref_name = STRBUF_INIT;\n+\tstruct tree_desc desc;\n+\tstruct lock_file lock = LOCK_INIT;\n+\tstruct unpack_trees_options unpack_tree_opts;\n+\tstruct tree *tree;\n+\tint ret = 0;\n+\n+\tif (hold_locked_index(&lock, LOCK_REPORT_ON_ERROR) < 0)\n+\t\treturn -1;\n+\n+\tmemset(&unpack_tree_opts, 0, sizeof(unpack_tree_opts));\n+\tsetup_unpack_trees_porcelain(&unpack_tree_opts, action);\n+\tunpack_tree_opts.head_idx = 1;\n+\tunpack_tree_opts.src_index = &the_index;\n+\tunpack_tree_opts.dst_index = &the_index;\n+\tunpack_tree_opts.fn = oneway_merge;\n+\tunpack_tree_opts.merge = 1;\n+\tunpack_tree_opts.update = 1;\n+\n+\tif (read_cache_unmerged()) {\n+\t\trollback_lock_file(&lock);\n+\t\tstrbuf_release(&ref_name);\n+\t\treturn error_resolve_conflict(_(action));\n+\t}\n+\n+\tif (!fill_tree_descriptor(&desc, oid)) {\n+\t\terror(_(\"failed to find tree of %s\"), oid_to_hex(oid));\n+\t\trollback_lock_file(&lock);\n+\t\tfree((void *)desc.buffer);\n+\t\tstrbuf_release(&ref_name);\n+\t\treturn -1;\n+\t}\n+\n+\tif (unpack_trees(1, &desc, &unpack_tree_opts)) {\n+\t\trollback_lock_file(&lock);\n+\t\tfree((void *)desc.buffer);\n+\t\tstrbuf_release(&ref_name);\n+\t\treturn -1;\n+\t}\n+\n+\ttree = parse_tree_indirect(oid);\n+\tprime_cache_tree(&the_index, tree);\n+\n+\tif (write_locked_index(&the_index, &lock, COMMIT_LOCK) < 0)\n+\t\tret = error(_(\"could not write index\"));\n+\tfree((void *)desc.buffer);\n+\n+\tif (!ret)\n+\t\tret = update_ref(reflog_message, \"HEAD\", oid,\n+\t\t\t\t NULL, 0, UPDATE_REFS_MSG_ON_ERR);\n+\n+\tstrbuf_release(&ref_name);\n+\treturn ret;\n+\n+}\ndiff --git a/checkout.h b/checkout.h\nindex 9980711179..6ce46cf4e8 100644\n--- a/checkout.h\n+++ b/checkout.h\n@@ -10,4 +10,7 @@\n  */\n extern const char *unique_tracking_name(const char *name, struct object_id *oid);\n \n+int detach_head_to(struct object_id *oid, const char *action,\n+\t\t   const char *reflog_message);\n+\n #endif /* CHECKOUT_H */\ndiff --git a/sequencer.c b/sequencer.c\nindex 5354d4d51e..106d518f4d 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -29,6 +29,7 @@\n #include \"oidset.h\"\n #include \"commit-slab.h\"\n #include \"alias.h\"\n+#include \"checkout.h\"\n \n #define GIT_REFLOG_ACTION \"GIT_REFLOG_ACTION\"\n \n@@ -2756,14 +2757,7 @@ static int do_reset(const char *name, int len, struct replay_opts *opts)\n {\n \tstruct strbuf ref_name = STRBUF_INIT;\n \tstruct object_id oid;\n-\tstruct lock_file lock = LOCK_INIT;\n-\tstruct tree_desc desc;\n-\tstruct tree *tree;\n-\tstruct unpack_trees_options unpack_tree_opts;\n-\tint ret = 0, i;\n-\n-\tif (hold_locked_index(&lock, LOCK_REPORT_ON_ERROR) < 0)\n-\t\treturn -1;\n+\tint i;\n \n \tif (len == 10 && !strncmp(\"[new root]\", name, len)) {\n \t\tif (!opts->have_squash_onto) {\n@@ -2789,56 +2783,14 @@ static int do_reset(const char *name, int len, struct replay_opts *opts)\n \t\tif (get_oid(ref_name.buf, &oid) &&\n \t\t    get_oid(ref_name.buf + strlen(\"refs/rewritten/\"), &oid)) {\n \t\t\terror(_(\"could not read '%s'\"), ref_name.buf);\n-\t\t\trollback_lock_file(&lock);\n \t\t\tstrbuf_release(&ref_name);\n \t\t\treturn -1;\n \t\t}\n \t}\n \n-\tmemset(&unpack_tree_opts, 0, sizeof(unpack_tree_opts));\n-\tsetup_unpack_trees_porcelain(&unpack_tree_opts, \"reset\");\n-\tunpack_tree_opts.head_idx = 1;\n-\tunpack_tree_opts.src_index = &the_index;\n-\tunpack_tree_opts.dst_index = &the_index;\n-\tunpack_tree_opts.fn = oneway_merge;\n-\tunpack_tree_opts.merge = 1;\n-\tunpack_tree_opts.update = 1;\n-\n-\tif (read_cache_unmerged()) {\n-\t\trollback_lock_file(&lock);\n-\t\tstrbuf_release(&ref_name);\n-\t\treturn error_resolve_conflict(_(action_name(opts)));\n-\t}\n-\n-\tif (!fill_tree_descriptor(&desc, &oid)) {\n-\t\terror(_(\"failed to find tree of %s\"), oid_to_hex(&oid));\n-\t\trollback_lock_file(&lock);\n-\t\tfree((void *)desc.buffer);\n-\t\tstrbuf_release(&ref_name);\n-\t\treturn -1;\n-\t}\n-\n-\tif (unpack_trees(1, &desc, &unpack_tree_opts)) {\n-\t\trollback_lock_file(&lock);\n-\t\tfree((void *)desc.buffer);\n-\t\tstrbuf_release(&ref_name);\n-\t\treturn -1;\n-\t}\n-\n-\ttree = parse_tree_indirect(&oid);\n-\tprime_cache_tree(&the_index, tree);\n-\n-\tif (write_locked_index(&the_index, &lock, COMMIT_LOCK) < 0)\n-\t\tret = error(_(\"could not write index\"));\n-\tfree((void *)desc.buffer);\n-\n-\tif (!ret)\n-\t\tret = update_ref(reflog_message(opts, \"reset\", \"'%.*s'\",\n-\t\t\t\t\t\tlen, name), \"HEAD\", &oid,\n-\t\t\t\t NULL, 0, UPDATE_REFS_MSG_ON_ERR);\n-\n-\tstrbuf_release(&ref_name);\n-\treturn ret;\n+\treturn detach_head_to(&oid, action_name(opts),\n+\t\t\t      reflog_message(opts, \"reset\", \"'%.*s'\",\n+\t\t\t\t\t     len, name));\n }\n \n static int do_merge(struct commit *commit, const char *arg, int arg_len,\n-- \n2.18.0\n\n"},{"id":"351773","messageId":"20180706120815.17851-5-predatoramigo@gmail.com","threadId":"48795","inReplyTo":"20180706120815.17851-1-predatoramigo@gmail.com","subject":"[PATCH v3 4/4] builtin/rebase: support running \"git rebase <upstream>\"","fromName":"Pratik Karki","fromEmail":"predatoramigo@gmail.com","sentAt":"2018-07-06T12:08:15Z","receivedAt":"2018-07-06T12:09:06Z","isPatch":true,"sender":{"key":"predatoramigo@gmail.com","avatar":"https://avatars.githubusercontent.com/u/12194950?v=4"},"body":"This patch gives life to the skeleton added in the previous patches:\nWith this change, we can perform a elementary rebase (without any\noptions).\n\nIt can be tested thusly by:\n\ngit -c rebase.usebuiltin=true rebase HEAD~2\n\nThe rebase backends (i.e. the shell script functions defined in\n`git-rebase--<backend>`) are still at work here and the \"builtin\nrebase\"'s purpose is simply to parse the options and set\neverything up so that those rebase backends can do their work.\n\nNote: We take an alternative approach here which is *not* to set the\nenvironment variables via `run_command_v_opt_cd_env()` because those\nvariables would then be visible by processes spawned from the rebase\nbackends. Instead, we work hard to set them in the shell script snippet.\n\nThe next commits will handle and support all the wonderful rebase\noptions.\n\nSigned-off-by: Pratik Karki <predatoramigo@gmail.com>\n---\n builtin/rebase.c | 237 ++++++++++++++++++++++++++++++++++++++++++++++-\n 1 file changed, 236 insertions(+), 1 deletion(-)\n\ndiff --git a/builtin/rebase.c b/builtin/rebase.c\nindex fab7fca37e..71f06f0789 100644\n--- a/builtin/rebase.c\n+++ b/builtin/rebase.c\n@@ -9,6 +9,20 @@\n #include \"exec-cmd.h\"\n #include \"argv-array.h\"\n #include \"dir.h\"\n+#include \"packfile.h\"\n+#include \"checkout.h\"\n+#include \"refs.h\"\n+#include \"quote.h\"\n+\n+static GIT_PATH_FUNC(apply_dir, \"rebase-apply\");\n+static GIT_PATH_FUNC(merge_dir, \"rebase-merge\");\n+\n+enum rebase_type {\n+\tREBASE_AM,\n+\tREBASE_MERGE,\n+\tREBASE_INTERACTIVE,\n+\tREBASE_PRESERVE_MERGES\n+};\n \n static int use_builtin_rebase(void)\n {\n@@ -28,8 +42,136 @@ static int use_builtin_rebase(void)\n \treturn ret;\n }\n \n+static int apply_autostash(void)\n+{\n+\twarning(\"TODO\");\n+\treturn 0;\n+}\n+\n+struct rebase_options {\n+\tenum rebase_type type;\n+\tconst char *state_dir;\n+\tstruct commit *upstream;\n+\tconst char *upstream_name;\n+\tchar *head_name;\n+\tstruct object_id orig_head;\n+\tstruct commit *onto;\n+\tconst char *onto_name;\n+\tconst char *revisions;\n+\tconst char *root;\n+};\n+\n+static int finish_rebase(struct rebase_options *opts)\n+{\n+\tstruct strbuf dir = STRBUF_INIT;\n+\tconst char *argv_gc_auto[] = { \"gc\", \"--auto\", NULL };\n+\n+\tdelete_ref(NULL, \"REBASE_HEAD\", NULL, REF_NO_DEREF);\n+\tapply_autostash();\n+\tclose_all_packs(the_repository->objects);\n+\t/*\n+\t * We ignore errors in 'gc --auto', since the\n+\t * user should see them.\n+\t */\n+\trun_command_v_opt(argv_gc_auto, RUN_GIT_CMD);\n+\tstrbuf_addstr(&dir, opts->state_dir);\n+\tremove_dir_recursively(&dir, 0);\n+\tstrbuf_release(&dir);\n+\n+\treturn 0;\n+}\n+\n+static struct commit *peel_committish(const char *name)\n+{\n+\tstruct object *obj;\n+\tstruct object_id oid;\n+\n+\tif (get_oid(name, &oid))\n+\t\treturn NULL;\n+\tobj = parse_object(&oid);\n+\treturn (struct commit *)peel_to_type(name, 0, obj, OBJ_COMMIT);\n+}\n+\n+static void add_var(struct strbuf *buf, const char *name, const char *value)\n+{\n+\tstrbuf_addstr(buf, name);\n+\tstrbuf_addstr(buf, \"=\");\n+\tsq_quote_buf(buf, value);\n+\tstrbuf_addstr(buf, \"; \");\n+}\n+\n+static int run_specific_rebase(struct rebase_options *opts)\n+{\n+\tconst char *argv[] = { NULL, NULL };\n+\tstruct strbuf script_snippet = STRBUF_INIT;\n+\tint status;\n+\tconst char *backend, *backend_func;\n+\n+\tadd_var(&script_snippet, \"GIT_DIR\", absolute_path(get_git_dir()));\n+\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, \"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+\tadd_var(&script_snippet, \"revisions\", opts->revisions);\n+\n+\tswitch (opts->type) {\n+\tcase REBASE_AM:\n+\t\tbackend = \"git-rebase--am\";\n+\t\tbackend_func = \"git_rebase__am\";\n+\t\tbreak;\n+\tcase REBASE_INTERACTIVE:\n+\t\tbackend = \"git-rebase--interactive\";\n+\t\tbackend_func = \"git_rebase__interactive\";\n+\t\tbreak;\n+\tcase REBASE_MERGE:\n+\t\tbackend = \"git-rebase--merge\";\n+\t\tbackend_func = \"git_rebase__merge\";\n+\t\tbreak;\n+\tcase REBASE_PRESERVE_MERGES:\n+\t\tbackend = \"git-rebase--preserve-merges\";\n+\t\tbackend_func = \"git_rebase__preserve_merges\";\n+\t\tbreak;\n+\tdefault:\n+\t\tBUG(\"Unhandled rebase type %d\", opts->type);\n+\t\tbreak;\n+\t}\n+\n+\tstrbuf_addf(&script_snippet,\n+\t\t    \". git-rebase--common && . %s && %s\",\n+\t\t    backend, backend_func);\n+\targv[0] = script_snippet.buf;\n+\n+\tstatus = run_command_v_opt(argv, RUN_USING_SHELL);\n+\tif (status == 0)\n+\t\tfinish_rebase(opts);\n+\telse if (status == 2) {\n+\t\tstruct strbuf dir = STRBUF_INIT;\n+\n+\t\tapply_autostash();\n+\t\tstrbuf_addstr(&dir, opts->state_dir);\n+\t\tremove_dir_recursively(&dir, 0);\n+\t\tstrbuf_release(&dir);\n+\t\tdie(\"Nothing to do\");\n+\t}\n+\n+\tstrbuf_release(&script_snippet);\n+\n+\treturn status ? -1 : 0;\n+}\n+\n int cmd_rebase(int argc, const char **argv, const char *prefix)\n {\n+\tstruct rebase_options options = { -1 };\n+\tconst char *branch_name;\n+\tint ret, flags, quiet = 0;\n+\tstruct strbuf msg = STRBUF_INIT;\n+\tstruct strbuf revisions = STRBUF_INIT;\n+\tconst char *restrict_revision = NULL;\n+\n \t/*\n \t * NEEDSWORK: Once the builtin rebase has been tested enough\n \t * and git-legacy-rebase.sh is retired to contrib/, this preamble\n@@ -52,5 +194,98 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \ttrace_repo_setup(prefix);\n \tsetup_work_tree();\n \n-\tdie(\"TODO\");\n+\toptions.type = REBASE_AM;\n+\n+\tswitch (options.type) {\n+\tcase REBASE_AM:\n+\t\toptions.state_dir = apply_dir();\n+\t\tbreak;\n+\tcase REBASE_MERGE:\n+\tcase REBASE_INTERACTIVE:\n+\tcase REBASE_PRESERVE_MERGES:\n+\t\toptions.state_dir = merge_dir();\n+\t\tbreak;\n+\t}\n+\tif (!options.root) {\n+\t\tif (argc != 2)\n+\t\t\tdie(\"TODO: handle @{upstream}\");\n+\t\telse {\n+\t\t\toptions.upstream_name = argv[1];\n+\t\t\targc--;\n+\t\t\targv++;\n+\t\t\tif (!strcmp(options.upstream_name, \"-\"))\n+\t\t\t\toptions.upstream_name = \"@{-1}\";\n+\t\t}\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} else\n+\t\tdie(\"TODO: upstream for --root\");\n+\n+\t/* Make sure the branch to rebase onto is valid. */\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} else {\n+\t\toptions.onto = peel_committish(options.onto_name);\n+\t\tif (!options.onto)\n+\t\t\tdie(_(\"Does not point to a valid commit '%s'\"),\n+\t\t\t\toptions.onto_name);\n+\t}\n+\n+\t/*\n+\t* If the branch to rebase is given, that is the branch we will rebase\n+\t* branch_name -- branch/commit being rebased, or 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*/\n+\tif (argc > 1)\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+\t\toptions.head_name =\n+\t\t\txstrdup_or_null(resolve_ref_unsafe(\"HEAD\", 0, NULL,\n+\t\t\t\t\t &flags));\n+\t\tif (!options.head_name)\n+\t\t\tdie(_(\"No such ref: %s\"), \"HEAD\");\n+\t\tif (flags & REF_ISSYMREF) {\n+\t\t\tif (!skip_prefix(options.head_name,\n+\t\t\t\t\t \"refs/heads/\", &branch_name))\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\tbranch_name = \"HEAD\";\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+\n+\t/* Detach HEAD and reset the tree */\n+\tif (!quiet)\n+\t\tprintf(\"First, rewinding head to replay your work on top of it...\");\n+\n+\tstrbuf_addf(&msg, \"rebase: checkout %s\", options.onto_name);\n+\tif (detach_head_to(&options.onto->object.oid, \"checkout\", msg.buf))\n+\t\tdie(_(\"Could not detach HEAD\"));\n+\tstrbuf_release(&msg);\n+\tif (update_ref(\"rebase\", \"ORIG_HEAD\", &options.orig_head, NULL, 0,\n+\t\t       UPDATE_REFS_MSG_ON_ERR) < 0)\n+\t\tdie(_(\"Could not update ORIG_HEAD to '%s'\"),\n+\t\t    oid_to_hex(&options.orig_head));\n+\n+\tstrbuf_addf(&revisions, \"%s..%s\",\n+\t\t!options.root ? oid_to_hex(&options.onto->object.oid) :\n+\t\t    (restrict_revision ? restrict_revision :\n+\t\t\t    oid_to_hex(&options.upstream->object.oid)),\n+\t\t\t    oid_to_hex(&options.orig_head));\n+\n+\toptions.revisions = revisions.buf;\n+\n+\tret = !!run_specific_rebase(&options);\n+\n+\tstrbuf_release(&revisions);\n+\tfree(options.head_name);\n+\treturn ret;\n }\n-- \n2.18.0\n\n"},{"id":"351776","messageId":"nycvar.QRO.7.76.6.1807061432100.75@tvgsbejvaqbjf.bet","threadId":"48795","inReplyTo":"20180706120815.17851-3-predatoramigo@gmail.com","subject":"Re: [PATCH v3 2/4] rebase: refactor common shell functions into their own file","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2018-07-06T12:36:10Z","receivedAt":"2018-07-06T12:36:36Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Pratik,\n\nOn Fri, 6 Jul 2018, Pratik Karki wrote:\n\n> The functions present in `git-legacy-rebase.sh` are used by the rebase\n> backends as they are implemented as shell script functions in the\n> `git-rebase--<backend>` files.\n> \n> To make the `builtin/rebase.c` work, we have to provide support via\n> a Unix shell script snippet that uses these functions and so, we\n> want to use the rebase backends *directly* from the builtin rebase\n> without going through `git-legacy-rebase.sh`.\n> \n> This commit extracts the functions to a separate file,\n> `git-rebase--common`, that will be read by `git-legacy-rebase.sh` and\n> by the shell script snippets which will be used extensively in the\n> following commits.\n\nGood.\n\nWhile this seems to catch all the functions required by the backends, I am\nfairly certain that the `resolvemsg` variable is used exclusively by the\nbackends, and it should therefore also moved into `git-rebase--common`.\nSee my comments on your https://github.com/git/git/pull/505 for more\ndetails.\n\nCiao,\nDscho\n"},{"id":"351813","messageId":"xmqq36wwjcl2.fsf@gitster-ct.c.googlers.com","threadId":"48795","inReplyTo":"20180706120815.17851-2-predatoramigo@gmail.com","subject":"Re: [PATCH v3 1/4] rebase: start implementing it as a builtin","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2018-07-06T21:09:29Z","receivedAt":"2018-07-06T21:09:34Z","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> +static int use_builtin_rebase(void)\n> +{\n> +\tstruct child_process cp = CHILD_PROCESS_INIT;\n> +\tstruct strbuf out = STRBUF_INIT;\n> +\tint ret;\n> +\n> +\targv_array_pushl(&cp.args,\n> +\t\t\t \"config\", \"--bool\", \"rebase.usebuiltin\", NULL);\n> +\tcp.git_cmd = 1;\n> +\tif (capture_command(&cp, &out, 6))\n> +\t\treturn 0;\n> +\n> +\tstrbuf_trim(&out);\n> +\tret = !strcmp(\"true\", out.buf);\n> +\tstrbuf_release(&out);\n> +\treturn ret;\n> +}\n> +\n> +int cmd_rebase(int argc, const char **argv, const char *prefix)\n> +{\n> +\t/*\n> +\t * NEEDSWORK: Once the builtin rebase has been tested enough\n> +\t * and git-legacy-rebase.sh is retired to contrib/, this preamble\n> +\t * can be removed.\n> +\t */\n> +\n> +\tif (!use_builtin_rebase()) {\n> +\t\tconst char *path = mkpath(\"%s/git-legacy-rebase\",\n> +\t\t\t\t\t  git_exec_path());\n> +\n> +\t\tif (sane_execvp(path, (char **)argv) < 0)\n> +\t\t\tdie_errno(\"could not exec %s\", path);\n> +\t\telse\n> +\t\t\tdie(\"sane_execvp() returned???\");\n\nThis part got changed from returning 0 since the previous round,\nwhich makes sense, but if we are making this change relative to the\noriginal in be8a90e, just because we mention explicitly that we\nimitate that old commit, we must mention how and why we \"improved\"\non it, in the log message.\n\n\tIn the old original used while converting difftool, if\n\tsane_execvp() that attempts to run the legacy scripted\n\tversion returned with non-negative status, the command\n\tsilently exited without doing anything with success, but\n\tsane_execvp() should not retun with non-negative status in\n\tthe first place, so make sure we die() to notice such an\n\tabnormal case.\n\nor something like that, perhaps (but you should be able to shorten\nit further).\n\nBetween die() and BUG(), I am not sure which is more appropriate.\nIt certainly is not _our_ bug if platform execvp() returns success,\nso BUG() would not help our developers all that much.  But end-users\nwon't be helped by being told that sane_execvp() returned, so die()\nis not all that useful, either.  I guess it does not matter that\nmuch bewteen the two, as this is something that is not supposed to\nhappen anyway ;-)\n\nIn any case, this one looks good.  Will queue.\n\nThanks.\n"},{"id":"351819","messageId":"xmqqsh4whx21.fsf@gitster-ct.c.googlers.com","threadId":"48795","inReplyTo":"20180706120815.17851-5-predatoramigo@gmail.com","subject":"Re: [PATCH v3 4/4] builtin/rebase: support running \"git rebase <upstream>\"","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2018-07-06T21:30:14Z","receivedAt":"2018-07-06T21:30:38Z","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> +static void add_var(struct strbuf *buf, const char *name, const char *value)\n> +{\n> +\tstrbuf_addstr(buf, name);\n> +\tstrbuf_addstr(buf, \"=\");\n> +\tsq_quote_buf(buf, value);\n> +\tstrbuf_addstr(buf, \"; \");\n> +}\n> +\n> +static int run_specific_rebase(struct rebase_options *opts)\n> +{\n> +\tconst char *argv[] = { NULL, NULL };\n> +\tstruct strbuf script_snippet = STRBUF_INIT;\n> +\tint status;\n> +\tconst char *backend, *backend_func;\n> +\n> +\tadd_var(&script_snippet, \"GIT_DIR\", absolute_path(get_git_dir()));\n> +\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, \"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> +\tadd_var(&script_snippet, \"revisions\", opts->revisions);\n\nLooks alright.\n\n> +\tswitch (opts->type) {\n> +\tcase REBASE_AM:\n> +...\n> +\tdefault:\n> +\t\tBUG(\"Unhandled rebase type %d\", opts->type);\n> +\t\tbreak;\n> +\t}\n\nBetter.\n\n> +\tstrbuf_addf(&script_snippet,\n> +\t\t    \". git-rebase--common && . %s && %s\",\n> +\t\t    backend, backend_func);\n> +\targv[0] = script_snippet.buf;\n> +\n> +\tstatus = run_command_v_opt(argv, RUN_USING_SHELL);\n\nThis used to use run_command_v_opt_cd_env() to pass extra\nenvironment but now we can do a simpler one.  As cmd_rebase()\nhas called setup_git_directory() to chdir to the top level of\nthe working tree, we just want to .-source the backend within\nthe current working directory, so loss of cd is also good ;-)\n\n> +\tif (status == 0)\n> +\t\tfinish_rebase(opts);\n> +\telse if (status == 2) {\n> +\t\tstruct strbuf dir = STRBUF_INIT;\n> +\n> +\t\tapply_autostash();\n> +\t\tstrbuf_addstr(&dir, opts->state_dir);\n> +\t\tremove_dir_recursively(&dir, 0);\n> +\t\tstrbuf_release(&dir);\n> +\t\tdie(\"Nothing to do\");\n> +\t}\n> +\n> +\tstrbuf_release(&script_snippet);\n> +\n> +\treturn status ? -1 : 0;\n> +}\n> +\n>  int cmd_rebase(int argc, const char **argv, const char *prefix)\n>  {\n> +\tstruct rebase_options options = { -1 };\n\nThe first field of this struct is \"enum rebase_type\" defined without\n\"REBASE_TYPE_UNSPECIFIED = -1\" in it.  It probably makes sense to\nadd that constant there so that you can spell this value out.\n\n> @@ -52,5 +194,98 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n>  \ttrace_repo_setup(prefix);\n>  \tsetup_work_tree();\n>  \n> -\tdie(\"TODO\");\n> +\toptions.type = REBASE_AM;\n> +\n> +\tswitch (options.type) {\n> +\tcase REBASE_AM:\n> +\t\toptions.state_dir = apply_dir();\n> +\t\tbreak;\n> +\tcase REBASE_MERGE:\n> +\tcase REBASE_INTERACTIVE:\n> +\tcase REBASE_PRESERVE_MERGES:\n> +\t\toptions.state_dir = merge_dir();\n> +\t\tbreak;\n\nHave \"default:\" here that barfs with BUG() to help future\nintroduction of bugs as the code to set options.type grows\ncomplexity over time.\n\n> +\t}\n> +\tif (!options.root) {\n> +\t\tif (argc != 2)\n> +\t\t\tdie(\"TODO: handle @{upstream}\");\n> +\t\telse {\n> +\t\t\toptions.upstream_name = argv[1];\n> +\t\t\targc--;\n> +\t\t\targv++;\n> +\t\t\tif (!strcmp(options.upstream_name, \"-\"))\n> +\t\t\t\toptions.upstream_name = \"@{-1}\";\n> +\t\t}\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} else\n> +\t\tdie(\"TODO: upstream for --root\");\n> +\n> +\t/* Make sure the branch to rebase onto is valid. */\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} else {\n> +\t\toptions.onto = peel_committish(options.onto_name);\n> +\t\tif (!options.onto)\n> +\t\t\tdie(_(\"Does not point to a valid commit '%s'\"),\n> +\t\t\t\toptions.onto_name);\n> +\t}\n> +\n> +\t/*\n> +\t* If the branch to rebase is given, that is the branch we will rebase\n\nStyle: align asterisks.\n\n> +\t* branch_name -- branch/commit being rebased, or 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*/\n> +\tif (argc > 1)\n> +\t\t die (\"TODO: handle switch_to\");\n\nStyle: no SP between \"die\" and \"(\"\n\n"},{"id":"351838","messageId":"CAP8UFD3_+0EDSzcrx9f70HBpWKvr94re5ZimuXDhfTZzJpfCvQ@mail.gmail.com","threadId":"48795","inReplyTo":"20180706120815.17851-5-predatoramigo@gmail.com","subject":"Re: [PATCH v3 4/4] builtin/rebase: support running \"git rebase <upstream>\"","fromName":"Christian Couder","fromEmail":"christian.couder@gmail.com","sentAt":"2018-07-07T06:45:03Z","receivedAt":"2018-07-07T06:45:08Z","isPatch":true,"sender":{"key":"christian.couder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/208954?v=4"},"body":"On Fri, Jul 6, 2018 at 2:08 PM, Pratik Karki <predatoramigo@gmail.com> wrote:\n\n> +       switch (opts->type) {\n> +       case REBASE_AM:\n> +               backend = \"git-rebase--am\";\n> +               backend_func = \"git_rebase__am\";\n> +               break;\n> +       case REBASE_INTERACTIVE:\n> +               backend = \"git-rebase--interactive\";\n> +               backend_func = \"git_rebase__interactive\";\n> +               break;\n> +       case REBASE_MERGE:\n> +               backend = \"git-rebase--merge\";\n> +               backend_func = \"git_rebase__merge\";\n> +               break;\n> +       case REBASE_PRESERVE_MERGES:\n> +               backend = \"git-rebase--preserve-merges\";\n> +               backend_func = \"git_rebase__preserve_merges\";\n> +               break;\n> +       default:\n> +               BUG(\"Unhandled rebase type %d\", opts->type);\n> +               break;\n\nNit: I think the \"break;\" line could be removed as the BUG() should always exit.\n\nA quick grep shows that there are other places where there is a\n\"break;\" line after a BUG() though. Maybe one of the #leftoverbits\ncould be about removing those \"break;\" lines.\n\n> +       }\n"},{"id":"351843","messageId":"nycvar.QRO.7.76.6.1807071356520.75@tvgsbejvaqbjf.bet","threadId":"48795","inReplyTo":"CAP8UFD3_+0EDSzcrx9f70HBpWKvr94re5ZimuXDhfTZzJpfCvQ@mail.gmail.com","subject":"Re: [PATCH v3 4/4] builtin/rebase: support running \"git rebase <upstream>\"","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2018-07-07T11:59:40Z","receivedAt":"2018-07-07T12:00:06Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Christian,\n\nOn Sat, 7 Jul 2018, Christian Couder wrote:\n\n> On Fri, Jul 6, 2018 at 2:08 PM, Pratik Karki <predatoramigo@gmail.com> wrote:\n> \n> > +       switch (opts->type) {\n> > +       case REBASE_AM:\n> > +               backend = \"git-rebase--am\";\n> > +               backend_func = \"git_rebase__am\";\n> > +               break;\n> > +       case REBASE_INTERACTIVE:\n> > +               backend = \"git-rebase--interactive\";\n> > +               backend_func = \"git_rebase__interactive\";\n> > +               break;\n> > +       case REBASE_MERGE:\n> > +               backend = \"git-rebase--merge\";\n> > +               backend_func = \"git_rebase__merge\";\n> > +               break;\n> > +       case REBASE_PRESERVE_MERGES:\n> > +               backend = \"git-rebase--preserve-merges\";\n> > +               backend_func = \"git_rebase__preserve_merges\";\n> > +               break;\n> > +       default:\n> > +               BUG(\"Unhandled rebase type %d\", opts->type);\n> > +               break;\n> \n> Nit: I think the \"break;\" line could be removed as the BUG() should always exit.\n> \n> A quick grep shows that there are other places where there is a\n> \"break;\" line after a BUG() though. Maybe one of the #leftoverbits\n> could be about removing those \"break;\" lines.\n\nBut what if there is a bug in the BUG() function? Shouldn't we then not\ncall `die()` directly after the `BUG()`?\n\nOkay, sorry, I let myself loose a little, as I think that we are still\nsafely in the territory where the code needs to be made correct. We can\nnitpick when there are no \"biggies\" left to comment about. Maybe focus a\nlittle more on whether the code does what it should do, rather than\nwhether some stylistic guidelines are violated?\n\nI mean, we can argue back and forth about white-space, indentation,\nsuperfluous break statements, etc. But that way, we won't get anywhere\nwith the builtin rebase.\n\nLet's help Pratik instead to complete his project, okay?\n\nCiao,\nDscho\n"},{"id":"351847","messageId":"xmqqbmbjggka.fsf@gitster-ct.c.googlers.com","threadId":"48795","inReplyTo":"CAP8UFD3_+0EDSzcrx9f70HBpWKvr94re5ZimuXDhfTZzJpfCvQ@mail.gmail.com","subject":"Re: [PATCH v3 4/4] builtin/rebase: support running \"git rebase <upstream>\"","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2018-07-07T16:24:05Z","receivedAt":"2018-07-07T16:24:13Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Christian Couder <christian.couder@gmail.com> writes:\n\n>> +       default:\n>> +               BUG(\"Unhandled rebase type %d\", opts->type);\n>> +               break;\n>\n> Nit: I think the \"break;\" line could be removed as the BUG() should always exit.\n>\n> A quick grep shows that there are other places where there is a\n> \"break;\" line after a BUG() though. Maybe one of the #leftoverbits\n> could be about removing those \"break;\" lines.\n\nI do not see the above as nit, though.  \"could\" is often quite a\ndifferent thing from \"should\", and in this case (and all the other\ncases you incorrectly mark with %leftoverbits) removal of these\nlines does not improve readability.  In fact, if there were another\ncase arm after this one, having \"break\" there would help those who\nscan the code, as the person who wants to ensure what that next case\narm does is correct is given a strong hint by \"break;\" immediately\nbefore it that nothing in the previous case arm matters and does not\nhave to even be looked at.  By removing it you force such a reader\nto notice BUG() and reason that it does not matter because it does\nnot return control to us (hence no fallthru).\n\n"},{"id":"351874","messageId":"20180708180104.17921-1-predatoramigo@gmail.com","threadId":"48795","inReplyTo":"20180628074655.5756-1-predatoramigo@gmail.com","subject":"[GSoC] [PATCH v4 0/4] rebase: rewrite rebase in C","fromName":"Pratik Karki","fromEmail":"predatoramigo@gmail.com","sentAt":"2018-07-08T18:01:00Z","receivedAt":"2018-07-08T18:01:28Z","isPatch":true,"sender":{"key":"predatoramigo@gmail.com","avatar":"https://avatars.githubusercontent.com/u/12194950?v=4"},"body":"As a GSoC project, I have been working on the builtin rebase.\n\nThe motivation behind the rewrite of rebase i.e. from shell script to C\nare for following reasons:\n\n1.  Writing shell scripts and getting it to production is much faster\n    than doing the equivalent in C but lacks in performance and extra\n    workarounds are needed for non-POSIX platforms.\n\n2.  Git for Windows is at loss as the installer size increases due to\n    addition of extra dependencies for the shell scripts which are usually\n    available in POSIX compliant platforms.\n\nThis series of patches serves to demonstrate a minimal builtin rebase\nwhich supports running `git rebase <upstream>` and also serves to ask for\nreviews.\n\nChanges since v3:\n\n  -  Fix commit message of `rebase: start implementing it as a builtin`.\n\n  -  Acknowledge Junio's style reviews.\n\n  -  Acknowledge Johannes Schindelin's review.\n\nPratik Karki (4):\n  rebase: start implementing it as a builtin\n  rebase: refactor common shell functions into their own file\n  sequencer: refactor the code to detach HEAD to checkout.c\n  builtin/rebase: support running \"git rebase <upstream>\"\n\n .gitignore                            |   2 +\n Makefile                              |   4 +-\n builtin.h                             |   1 +\n builtin/rebase.c                      | 292 ++++++++++++++++++++++++++\n checkout.c                            |  64 ++++++\n checkout.h                            |   3 +\n git-rebase.sh => git-legacy-rebase.sh |  69 +-----\n git-rebase--common.sh                 |  68 ++++++\n git.c                                 |   6 +\n sequencer.c                           |  58 +----\n 10 files changed, 446 insertions(+), 121 deletions(-)\n create mode 100644 builtin/rebase.c\n rename git-rebase.sh => git-legacy-rebase.sh (89%)\n create mode 100644 git-rebase--common.sh\n\n-- \n2.18.0\n\n"},{"id":"351875","messageId":"20180708180104.17921-2-predatoramigo@gmail.com","threadId":"48795","inReplyTo":"20180708180104.17921-1-predatoramigo@gmail.com","subject":"[PATCH v4 1/4] rebase: start implementing it as a builtin","fromName":"Pratik Karki","fromEmail":"predatoramigo@gmail.com","sentAt":"2018-07-08T18:01:01Z","receivedAt":"2018-07-08T18:01:36Z","isPatch":true,"sender":{"key":"predatoramigo@gmail.com","avatar":"https://avatars.githubusercontent.com/u/12194950?v=4"},"body":"This commit imitates the strategy that was used to convert the\ndifftool to a builtin. We start by renaming the shell script\n`git-rebase.sh` to `git-legacy-rebase.sh` and introduce a\n`builtin/rebase.c` that simply executes the shell script version,\nunless the config setting `rebase.useBuiltin` is set to `true`.\n\nThe motivation behind this is to rewrite all the functionality of the\nshell script version in the aforementioned `rebase.c`, one by one and\nbe able to conveniently test new features by configuring\n`rebase.useBuiltin`.\n\nIn the original difftool conversion, if sane_execvp() that attempts to\nrun the legacy scripted version returned with non-negative status, the\ncommand silently exited without doing anything with success, but\nsane_execvp() should not retun with non-negative status in the first\nplace, so we use die() to notice such an abnormal case.\n\nWe intentionally avoid reading the config directly to avoid\nmessing up the GIT_* environment variables when we need to fall back to\nexec()ing the shell script. The test of builtin rebase can be done by\n`git -c rebase.useBuiltin=true rebase ...`\n\nSigned-off-by: Pratik Karki <predatoramigo@gmail.com>\n---\n .gitignore                            |  1 +\n Makefile                              |  3 +-\n builtin.h                             |  1 +\n builtin/rebase.c                      | 56 +++++++++++++++++++++++++++\n git-rebase.sh => git-legacy-rebase.sh |  0\n git.c                                 |  6 +++\n 6 files changed, 66 insertions(+), 1 deletion(-)\n create mode 100644 builtin/rebase.c\n rename git-rebase.sh => git-legacy-rebase.sh (100%)\n\ndiff --git a/.gitignore b/.gitignore\nindex 3284a1e9b1..ec23959014 100644\n--- a/.gitignore\n+++ b/.gitignore\n@@ -78,6 +78,7 @@\n /git-init-db\n /git-interpret-trailers\n /git-instaweb\n+/git-legacy-rebase\n /git-log\n /git-ls-files\n /git-ls-remote\ndiff --git a/Makefile b/Makefile\nindex 0cb6590f24..e88fe2e5fb 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -609,7 +609,7 @@ SCRIPT_SH += git-merge-one-file.sh\n SCRIPT_SH += git-merge-resolve.sh\n SCRIPT_SH += git-mergetool.sh\n SCRIPT_SH += git-quiltimport.sh\n-SCRIPT_SH += git-rebase.sh\n+SCRIPT_SH += git-legacy-rebase.sh\n SCRIPT_SH += git-remote-testgit.sh\n SCRIPT_SH += git-request-pull.sh\n SCRIPT_SH += git-stash.sh\n@@ -1059,6 +1059,7 @@ BUILTIN_OBJS += builtin/prune.o\n BUILTIN_OBJS += builtin/pull.o\n BUILTIN_OBJS += builtin/push.o\n BUILTIN_OBJS += builtin/read-tree.o\n+BUILTIN_OBJS += builtin/rebase.o\n BUILTIN_OBJS += builtin/rebase--helper.o\n BUILTIN_OBJS += builtin/receive-pack.o\n BUILTIN_OBJS += builtin/reflog.o\ndiff --git a/builtin.h b/builtin.h\nindex 0362f1ce25..44651a447f 100644\n--- a/builtin.h\n+++ b/builtin.h\n@@ -202,6 +202,7 @@ extern int cmd_prune_packed(int argc, const char **argv, const char *prefix);\n extern int cmd_pull(int argc, const char **argv, const char *prefix);\n extern int cmd_push(int argc, const char **argv, const char *prefix);\n extern int cmd_read_tree(int argc, const char **argv, const char *prefix);\n+extern int cmd_rebase(int argc, const char **argv, const char *prefix);\n extern int cmd_rebase__helper(int argc, const char **argv, const char *prefix);\n extern int cmd_receive_pack(int argc, const char **argv, const char *prefix);\n extern int cmd_reflog(int argc, const char **argv, const char *prefix);\ndiff --git a/builtin/rebase.c b/builtin/rebase.c\nnew file mode 100644\nindex 0000000000..fab7fca37e\n--- /dev/null\n+++ b/builtin/rebase.c\n@@ -0,0 +1,56 @@\n+/*\n+ * \"git rebase\" builtin command\n+ *\n+ * Copyright (c) 2018 Pratik Karki\n+ */\n+\n+#include \"builtin.h\"\n+#include \"run-command.h\"\n+#include \"exec-cmd.h\"\n+#include \"argv-array.h\"\n+#include \"dir.h\"\n+\n+static int use_builtin_rebase(void)\n+{\n+\tstruct child_process cp = CHILD_PROCESS_INIT;\n+\tstruct strbuf out = STRBUF_INIT;\n+\tint ret;\n+\n+\targv_array_pushl(&cp.args,\n+\t\t\t \"config\", \"--bool\", \"rebase.usebuiltin\", NULL);\n+\tcp.git_cmd = 1;\n+\tif (capture_command(&cp, &out, 6))\n+\t\treturn 0;\n+\n+\tstrbuf_trim(&out);\n+\tret = !strcmp(\"true\", out.buf);\n+\tstrbuf_release(&out);\n+\treturn ret;\n+}\n+\n+int cmd_rebase(int argc, const char **argv, const char *prefix)\n+{\n+\t/*\n+\t * NEEDSWORK: Once the builtin rebase has been tested enough\n+\t * and git-legacy-rebase.sh is retired to contrib/, this preamble\n+\t * can be removed.\n+\t */\n+\n+\tif (!use_builtin_rebase()) {\n+\t\tconst char *path = mkpath(\"%s/git-legacy-rebase\",\n+\t\t\t\t\t  git_exec_path());\n+\n+\t\tif (sane_execvp(path, (char **)argv) < 0)\n+\t\t\tdie_errno(\"could not exec %s\", path);\n+\t\telse\n+\t\t\tdie(\"sane_execvp() returned???\");\n+\t}\n+\n+\tif (argc != 2)\n+\t\tdie(\"Usage: %s <base>\", argv[0]);\n+\tprefix = setup_git_directory();\n+\ttrace_repo_setup(prefix);\n+\tsetup_work_tree();\n+\n+\tdie(\"TODO\");\n+}\ndiff --git a/git-rebase.sh b/git-legacy-rebase.sh\nsimilarity index 100%\nrename from git-rebase.sh\nrename to git-legacy-rebase.sh\ndiff --git a/git.c b/git.c\nindex 9dbe6ffaa7..0e35632464 100644\n--- a/git.c\n+++ b/git.c\n@@ -518,6 +518,12 @@ static struct cmd_struct commands[] = {\n \t{ \"pull\", cmd_pull, RUN_SETUP | NEED_WORK_TREE },\n \t{ \"push\", cmd_push, RUN_SETUP },\n \t{ \"read-tree\", cmd_read_tree, RUN_SETUP | SUPPORT_SUPER_PREFIX},\n+\t/*\n+\t * NEEDSWORK: Until the rebase is independent and needs no redirection\n+\t * to rebase shell script this is kept as is, then should be changed to\n+\t * RUN_SETUP | NEED_WORK_TREE\n+\t */\n+\t{ \"rebase\", cmd_rebase },\n \t{ \"rebase--helper\", cmd_rebase__helper, RUN_SETUP | NEED_WORK_TREE },\n \t{ \"receive-pack\", cmd_receive_pack },\n \t{ \"reflog\", cmd_reflog, RUN_SETUP },\n-- \n2.18.0\n\n"},{"id":"351876","messageId":"20180708180104.17921-3-predatoramigo@gmail.com","threadId":"48795","inReplyTo":"20180708180104.17921-1-predatoramigo@gmail.com","subject":"[PATCH v4 2/4] rebase: refactor common shell functions into their own file","fromName":"Pratik Karki","fromEmail":"predatoramigo@gmail.com","sentAt":"2018-07-08T18:01:02Z","receivedAt":"2018-07-08T18:01:40Z","isPatch":true,"sender":{"key":"predatoramigo@gmail.com","avatar":"https://avatars.githubusercontent.com/u/12194950?v=4"},"body":"The functions present in `git-legacy-rebase.sh` are used by the rebase\nbackends as they are implemented as shell script functions in the\n`git-rebase--<backend>` files.\n\nTo make the `builtin/rebase.c` work, we have to provide support via\na Unix shell script snippet that uses these functions and so, we\nwant to use the rebase backends *directly* from the builtin rebase\nwithout going through `git-legacy-rebase.sh`.\n\nThis commit extracts the functions to a separate file,\n`git-rebase--common`, that will be read by `git-legacy-rebase.sh` and\nby the shell script snippets which will be used extensively in the\nfollowing commits.\n\nSigned-off-by: Pratik Karki <predatoramigo@gmail.com>\n---\n .gitignore            |  1 +\n Makefile              |  1 +\n git-legacy-rebase.sh  | 69 ++-----------------------------------------\n git-rebase--common.sh | 68 ++++++++++++++++++++++++++++++++++++++++++\n 4 files changed, 72 insertions(+), 67 deletions(-)\n create mode 100644 git-rebase--common.sh\n\ndiff --git a/.gitignore b/.gitignore\nindex ec23959014..824141cba1 100644\n--- a/.gitignore\n+++ b/.gitignore\n@@ -117,6 +117,7 @@\n /git-read-tree\n /git-rebase\n /git-rebase--am\n+/git-rebase--common\n /git-rebase--helper\n /git-rebase--interactive\n /git-rebase--merge\ndiff --git a/Makefile b/Makefile\nindex e88fe2e5fb..163e52ad1a 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -619,6 +619,7 @@ SCRIPT_SH += git-web--browse.sh\n SCRIPT_LIB += git-mergetool--lib\n SCRIPT_LIB += git-parse-remote\n SCRIPT_LIB += git-rebase--am\n+SCRIPT_LIB += git-rebase--common\n SCRIPT_LIB += git-rebase--interactive\n SCRIPT_LIB += git-rebase--preserve-merges\n SCRIPT_LIB += git-rebase--merge\ndiff --git a/git-legacy-rebase.sh b/git-legacy-rebase.sh\nindex 19bdebb480..fbaf16420d 100755\n--- a/git-legacy-rebase.sh\n+++ b/git-legacy-rebase.sh\n@@ -57,12 +57,7 @@ cd_to_toplevel\n LF='\n '\n ok_to_skip_pre_rebase=\n-resolvemsg=\"\n-$(gettext 'Resolve all conflicts manually, mark them as resolved with\n-\"git add/rm <conflicted_files>\", then run \"git rebase --continue\".\n-You can instead skip this commit: run \"git rebase --skip\".\n-To abort and get back to the state before \"git rebase\", run \"git rebase --abort\".')\n-\"\n+\n squash_onto=\n unset onto\n unset restrict_revision\n@@ -102,6 +97,7 @@ case \"$(git config --bool commit.gpgsign)\" in\n true)\tgpg_sign_opt=-S ;;\n *)\tgpg_sign_opt= ;;\n esac\n+. git-rebase--common\n \n read_basic_state () {\n \ttest -f \"$state_dir/head-name\" &&\n@@ -132,67 +128,6 @@ read_basic_state () {\n \t}\n }\n \n-write_basic_state () {\n-\techo \"$head_name\" > \"$state_dir\"/head-name &&\n-\techo \"$onto\" > \"$state_dir\"/onto &&\n-\techo \"$orig_head\" > \"$state_dir\"/orig-head &&\n-\techo \"$GIT_QUIET\" > \"$state_dir\"/quiet &&\n-\ttest t = \"$verbose\" && : > \"$state_dir\"/verbose\n-\ttest -n \"$strategy\" && echo \"$strategy\" > \"$state_dir\"/strategy\n-\ttest -n \"$strategy_opts\" && echo \"$strategy_opts\" > \\\n-\t\t\"$state_dir\"/strategy_opts\n-\ttest -n \"$allow_rerere_autoupdate\" && echo \"$allow_rerere_autoupdate\" > \\\n-\t\t\"$state_dir\"/allow_rerere_autoupdate\n-\ttest -n \"$gpg_sign_opt\" && echo \"$gpg_sign_opt\" > \"$state_dir\"/gpg_sign_opt\n-\ttest -n \"$signoff\" && echo \"$signoff\" >\"$state_dir\"/signoff\n-}\n-\n-output () {\n-\tcase \"$verbose\" in\n-\t'')\n-\t\toutput=$(\"$@\" 2>&1 )\n-\t\tstatus=$?\n-\t\ttest $status != 0 && printf \"%s\\n\" \"$output\"\n-\t\treturn $status\n-\t\t;;\n-\t*)\n-\t\t\"$@\"\n-\t\t;;\n-\tesac\n-}\n-\n-move_to_original_branch () {\n-\tcase \"$head_name\" in\n-\trefs/*)\n-\t\tmessage=\"rebase finished: $head_name onto $onto\"\n-\t\tgit update-ref -m \"$message\" \\\n-\t\t\t$head_name $(git rev-parse HEAD) $orig_head &&\n-\t\tgit symbolic-ref \\\n-\t\t\t-m \"rebase finished: returning to $head_name\" \\\n-\t\t\tHEAD $head_name ||\n-\t\tdie \"$(eval_gettext \"Could not move back to \\$head_name\")\"\n-\t\t;;\n-\tesac\n-}\n-\n-apply_autostash () {\n-\tif test -f \"$state_dir/autostash\"\n-\tthen\n-\t\tstash_sha1=$(cat \"$state_dir/autostash\")\n-\t\tif git stash apply $stash_sha1 >/dev/null 2>&1\n-\t\tthen\n-\t\t\techo \"$(gettext 'Applied autostash.')\" >&2\n-\t\telse\n-\t\t\tgit stash store -m \"autostash\" -q $stash_sha1 ||\n-\t\t\tdie \"$(eval_gettext \"Cannot store \\$stash_sha1\")\"\n-\t\t\tgettext 'Applying autostash resulted in conflicts.\n-Your changes are safe in the stash.\n-You can run \"git stash pop\" or \"git stash drop\" at any time.\n-' >&2\n-\t\tfi\n-\tfi\n-}\n-\n finish_rebase () {\n \trm -f \"$(git rev-parse --git-path REBASE_HEAD)\"\n \tapply_autostash &&\ndiff --git a/git-rebase--common.sh b/git-rebase--common.sh\nnew file mode 100644\nindex 0000000000..7e39d22871\n--- /dev/null\n+++ b/git-rebase--common.sh\n@@ -0,0 +1,68 @@\n+\n+resolvemsg=\"\n+$(gettext 'Resolve all conflicts manually, mark them as resolved with\n+\"git add/rm <conflicted_files>\", then run \"git rebase --continue\".\n+You can instead skip this commit: run \"git rebase --skip\".\n+To abort and get back to the state before \"git rebase\", run \"git rebase --abort\".')\n+\"\n+\n+write_basic_state () {\n+\techo \"$head_name\" > \"$state_dir\"/head-name &&\n+\techo \"$onto\" > \"$state_dir\"/onto &&\n+\techo \"$orig_head\" > \"$state_dir\"/orig-head &&\n+\techo \"$GIT_QUIET\" > \"$state_dir\"/quiet &&\n+\ttest t = \"$verbose\" && : > \"$state_dir\"/verbose\n+\ttest -n \"$strategy\" && echo \"$strategy\" > \"$state_dir\"/strategy\n+\ttest -n \"$strategy_opts\" && echo \"$strategy_opts\" > \\\n+\t\t\"$state_dir\"/strategy_opts\n+\ttest -n \"$allow_rerere_autoupdate\" && echo \"$allow_rerere_autoupdate\" > \\\n+\t\t\"$state_dir\"/allow_rerere_autoupdate\n+\ttest -n \"$gpg_sign_opt\" && echo \"$gpg_sign_opt\" > \"$state_dir\"/gpg_sign_opt\n+\ttest -n \"$signoff\" && echo \"$signoff\" >\"$state_dir\"/signoff\n+}\n+\n+apply_autostash () {\n+\tif test -f \"$state_dir/autostash\"\n+\tthen\n+\t\tstash_sha1=$(cat \"$state_dir/autostash\")\n+\t\tif git stash apply $stash_sha1 >/dev/null 2>&1\n+\t\tthen\n+\t\t\techo \"$(gettext 'Applied autostash.')\" >&2\n+\t\telse\n+\t\t\tgit stash store -m \"autostash\" -q $stash_sha1 ||\n+\t\t\tdie \"$(eval_gettext \"Cannot store \\$stash_sha1\")\"\n+\t\t\tgettext 'Applying autostash resulted in conflicts.\n+Your changes are safe in the stash.\n+You can run \"git stash pop\" or \"git stash drop\" at any time.\n+' >&2\n+\t\tfi\n+\tfi\n+}\n+\n+move_to_original_branch () {\n+\tcase \"$head_name\" in\n+\trefs/*)\n+\t\tmessage=\"rebase finished: $head_name onto $onto\"\n+\t\tgit update-ref -m \"$message\" \\\n+\t\t\t$head_name $(git rev-parse HEAD) $orig_head &&\n+\t\tgit symbolic-ref \\\n+\t\t\t-m \"rebase finished: returning to $head_name\" \\\n+\t\t\tHEAD $head_name ||\n+\t\tdie \"$(eval_gettext \"Could not move back to \\$head_name\")\"\n+\t\t;;\n+\tesac\n+}\n+\n+output () {\n+\tcase \"$verbose\" in\n+\t'')\n+\t\toutput=$(\"$@\" 2>&1 )\n+\t\tstatus=$?\n+\t\ttest $status != 0 && printf \"%s\\n\" \"$output\"\n+\t\treturn $status\n+\t\t;;\n+\t*)\n+\t\t\"$@\"\n+\t\t;;\n+\tesac\n+}\n-- \n2.18.0\n\n"},{"id":"351877","messageId":"20180708180104.17921-4-predatoramigo@gmail.com","threadId":"48795","inReplyTo":"20180708180104.17921-1-predatoramigo@gmail.com","subject":"[PATCH v4 3/4] sequencer: refactor the code to detach HEAD to checkout.c","fromName":"Pratik Karki","fromEmail":"predatoramigo@gmail.com","sentAt":"2018-07-08T18:01:03Z","receivedAt":"2018-07-08T18:01:45Z","isPatch":true,"sender":{"key":"predatoramigo@gmail.com","avatar":"https://avatars.githubusercontent.com/u/12194950?v=4"},"body":"In the upcoming builtin rebase, we will have to start by detaching\nthe HEAD, just like shell script version does. Essentially, we have\nto do the same thing as `git checkout -q <revision>^0 --`, in pure C.\n\nThe aforementioned functionality was already present in `sequencer.c`\nin `do_reset()` function. But `do_reset()` performs more than detaching\nthe HEAD, and performs action specific to `sequencer.c`.\n\nSo this commit refactors out that part from `do_reset()`, and moves it\nto a new function called `detach_head_to()`. As this function has\nnothing to do with the sequencer, and everything to do with what `git\ncheckout -q <revision>^0 --` does, we move that function to checkout.c.\n\nThis refactoring actually introduces a slight change in behavior:\npreviously, the index was locked before parsing the argument to the\ntodo command `reset`, while it now gets locked *after* that, in the\n`detach_head_to()` function.\n\nIt does not make a huge difference, and the upside is that this closes\na few (unlikely) code paths where the index would not be unlocked upon\nerror.\n\nSigned-off-by: Pratik Karki <predatoramigo@gmail.com>\n---\n checkout.c  | 64 +++++++++++++++++++++++++++++++++++++++++++++++++++++\n checkout.h  |  3 +++\n sequencer.c | 58 +++++-------------------------------------------\n 3 files changed, 72 insertions(+), 53 deletions(-)\n\ndiff --git a/checkout.c b/checkout.c\nindex bdefc888ba..da68915fd7 100644\n--- a/checkout.c\n+++ b/checkout.c\n@@ -2,6 +2,11 @@\n #include \"remote.h\"\n #include \"refspec.h\"\n #include \"checkout.h\"\n+#include \"unpack-trees.h\"\n+#include \"lockfile.h\"\n+#include \"refs.h\"\n+#include \"tree.h\"\n+#include \"cache-tree.h\"\n \n struct tracking_name_data {\n \t/* const */ char *src_ref;\n@@ -42,3 +47,62 @@ const char *unique_tracking_name(const char *name, struct object_id *oid)\n \tfree(cb_data.dst_ref);\n \treturn NULL;\n }\n+\n+int detach_head_to(struct object_id *oid, const char *action,\n+\t\t   const char *reflog_message)\n+{\n+\tstruct strbuf ref_name = STRBUF_INIT;\n+\tstruct tree_desc desc;\n+\tstruct lock_file lock = LOCK_INIT;\n+\tstruct unpack_trees_options unpack_tree_opts;\n+\tstruct tree *tree;\n+\tint ret = 0;\n+\n+\tif (hold_locked_index(&lock, LOCK_REPORT_ON_ERROR) < 0)\n+\t\treturn -1;\n+\n+\tmemset(&unpack_tree_opts, 0, sizeof(unpack_tree_opts));\n+\tsetup_unpack_trees_porcelain(&unpack_tree_opts, action);\n+\tunpack_tree_opts.head_idx = 1;\n+\tunpack_tree_opts.src_index = &the_index;\n+\tunpack_tree_opts.dst_index = &the_index;\n+\tunpack_tree_opts.fn = oneway_merge;\n+\tunpack_tree_opts.merge = 1;\n+\tunpack_tree_opts.update = 1;\n+\n+\tif (read_cache_unmerged()) {\n+\t\trollback_lock_file(&lock);\n+\t\tstrbuf_release(&ref_name);\n+\t\treturn error_resolve_conflict(_(action));\n+\t}\n+\n+\tif (!fill_tree_descriptor(&desc, oid)) {\n+\t\terror(_(\"failed to find tree of %s\"), oid_to_hex(oid));\n+\t\trollback_lock_file(&lock);\n+\t\tfree((void *)desc.buffer);\n+\t\tstrbuf_release(&ref_name);\n+\t\treturn -1;\n+\t}\n+\n+\tif (unpack_trees(1, &desc, &unpack_tree_opts)) {\n+\t\trollback_lock_file(&lock);\n+\t\tfree((void *)desc.buffer);\n+\t\tstrbuf_release(&ref_name);\n+\t\treturn -1;\n+\t}\n+\n+\ttree = parse_tree_indirect(oid);\n+\tprime_cache_tree(&the_index, tree);\n+\n+\tif (write_locked_index(&the_index, &lock, COMMIT_LOCK) < 0)\n+\t\tret = error(_(\"could not write index\"));\n+\tfree((void *)desc.buffer);\n+\n+\tif (!ret)\n+\t\tret = update_ref(reflog_message, \"HEAD\", oid,\n+\t\t\t\t NULL, 0, UPDATE_REFS_MSG_ON_ERR);\n+\n+\tstrbuf_release(&ref_name);\n+\treturn ret;\n+\n+}\ndiff --git a/checkout.h b/checkout.h\nindex 9980711179..6ce46cf4e8 100644\n--- a/checkout.h\n+++ b/checkout.h\n@@ -10,4 +10,7 @@\n  */\n extern const char *unique_tracking_name(const char *name, struct object_id *oid);\n \n+int detach_head_to(struct object_id *oid, const char *action,\n+\t\t   const char *reflog_message);\n+\n #endif /* CHECKOUT_H */\ndiff --git a/sequencer.c b/sequencer.c\nindex 5354d4d51e..106d518f4d 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -29,6 +29,7 @@\n #include \"oidset.h\"\n #include \"commit-slab.h\"\n #include \"alias.h\"\n+#include \"checkout.h\"\n \n #define GIT_REFLOG_ACTION \"GIT_REFLOG_ACTION\"\n \n@@ -2756,14 +2757,7 @@ static int do_reset(const char *name, int len, struct replay_opts *opts)\n {\n \tstruct strbuf ref_name = STRBUF_INIT;\n \tstruct object_id oid;\n-\tstruct lock_file lock = LOCK_INIT;\n-\tstruct tree_desc desc;\n-\tstruct tree *tree;\n-\tstruct unpack_trees_options unpack_tree_opts;\n-\tint ret = 0, i;\n-\n-\tif (hold_locked_index(&lock, LOCK_REPORT_ON_ERROR) < 0)\n-\t\treturn -1;\n+\tint i;\n \n \tif (len == 10 && !strncmp(\"[new root]\", name, len)) {\n \t\tif (!opts->have_squash_onto) {\n@@ -2789,56 +2783,14 @@ static int do_reset(const char *name, int len, struct replay_opts *opts)\n \t\tif (get_oid(ref_name.buf, &oid) &&\n \t\t    get_oid(ref_name.buf + strlen(\"refs/rewritten/\"), &oid)) {\n \t\t\terror(_(\"could not read '%s'\"), ref_name.buf);\n-\t\t\trollback_lock_file(&lock);\n \t\t\tstrbuf_release(&ref_name);\n \t\t\treturn -1;\n \t\t}\n \t}\n \n-\tmemset(&unpack_tree_opts, 0, sizeof(unpack_tree_opts));\n-\tsetup_unpack_trees_porcelain(&unpack_tree_opts, \"reset\");\n-\tunpack_tree_opts.head_idx = 1;\n-\tunpack_tree_opts.src_index = &the_index;\n-\tunpack_tree_opts.dst_index = &the_index;\n-\tunpack_tree_opts.fn = oneway_merge;\n-\tunpack_tree_opts.merge = 1;\n-\tunpack_tree_opts.update = 1;\n-\n-\tif (read_cache_unmerged()) {\n-\t\trollback_lock_file(&lock);\n-\t\tstrbuf_release(&ref_name);\n-\t\treturn error_resolve_conflict(_(action_name(opts)));\n-\t}\n-\n-\tif (!fill_tree_descriptor(&desc, &oid)) {\n-\t\terror(_(\"failed to find tree of %s\"), oid_to_hex(&oid));\n-\t\trollback_lock_file(&lock);\n-\t\tfree((void *)desc.buffer);\n-\t\tstrbuf_release(&ref_name);\n-\t\treturn -1;\n-\t}\n-\n-\tif (unpack_trees(1, &desc, &unpack_tree_opts)) {\n-\t\trollback_lock_file(&lock);\n-\t\tfree((void *)desc.buffer);\n-\t\tstrbuf_release(&ref_name);\n-\t\treturn -1;\n-\t}\n-\n-\ttree = parse_tree_indirect(&oid);\n-\tprime_cache_tree(&the_index, tree);\n-\n-\tif (write_locked_index(&the_index, &lock, COMMIT_LOCK) < 0)\n-\t\tret = error(_(\"could not write index\"));\n-\tfree((void *)desc.buffer);\n-\n-\tif (!ret)\n-\t\tret = update_ref(reflog_message(opts, \"reset\", \"'%.*s'\",\n-\t\t\t\t\t\tlen, name), \"HEAD\", &oid,\n-\t\t\t\t NULL, 0, UPDATE_REFS_MSG_ON_ERR);\n-\n-\tstrbuf_release(&ref_name);\n-\treturn ret;\n+\treturn detach_head_to(&oid, action_name(opts),\n+\t\t\t      reflog_message(opts, \"reset\", \"'%.*s'\",\n+\t\t\t\t\t     len, name));\n }\n \n static int do_merge(struct commit *commit, const char *arg, int arg_len,\n-- \n2.18.0\n\n"},{"id":"351878","messageId":"20180708180104.17921-5-predatoramigo@gmail.com","threadId":"48795","inReplyTo":"20180708180104.17921-1-predatoramigo@gmail.com","subject":"[PATCH v4 4/4] builtin/rebase: support running \"git rebase <upstream>\"","fromName":"Pratik Karki","fromEmail":"predatoramigo@gmail.com","sentAt":"2018-07-08T18:01:04Z","receivedAt":"2018-07-08T18:01:46Z","isPatch":true,"sender":{"key":"predatoramigo@gmail.com","avatar":"https://avatars.githubusercontent.com/u/12194950?v=4"},"body":"This patch gives life to the skeleton added in the previous patches:\nWith this change, we can perform a elementary rebase (without any\noptions).\n\nIt can be tested thusly by:\n\ngit -c rebase.usebuiltin=true rebase HEAD~2\n\nThe rebase backends (i.e. the shell script functions defined in\n`git-rebase--<backend>`) are still at work here and the \"builtin\nrebase\"'s purpose is simply to parse the options and set\neverything up so that those rebase backends can do their work.\n\nNote: We take an alternative approach here which is *not* to set the\nenvironment variables via `run_command_v_opt_cd_env()` because those\nvariables would then be visible by processes spawned from the rebase\nbackends. Instead, we work hard to set them in the shell script snippet.\n\nThe next commits will handle and support all the wonderful rebase\noptions.\n\nSigned-off-by: Pratik Karki <predatoramigo@gmail.com>\n---\n builtin/rebase.c | 238 ++++++++++++++++++++++++++++++++++++++++++++++-\n 1 file changed, 237 insertions(+), 1 deletion(-)\n\ndiff --git a/builtin/rebase.c b/builtin/rebase.c\nindex fab7fca37e..e38ea80874 100644\n--- a/builtin/rebase.c\n+++ b/builtin/rebase.c\n@@ -9,6 +9,20 @@\n #include \"exec-cmd.h\"\n #include \"argv-array.h\"\n #include \"dir.h\"\n+#include \"packfile.h\"\n+#include \"checkout.h\"\n+#include \"refs.h\"\n+#include \"quote.h\"\n+\n+static GIT_PATH_FUNC(apply_dir, \"rebase-apply\");\n+static GIT_PATH_FUNC(merge_dir, \"rebase-merge\");\n+\n+enum rebase_type {\n+\tREBASE_AM,\n+\tREBASE_MERGE,\n+\tREBASE_INTERACTIVE,\n+\tREBASE_PRESERVE_MERGES\n+};\n \n static int use_builtin_rebase(void)\n {\n@@ -28,8 +42,136 @@ static int use_builtin_rebase(void)\n \treturn ret;\n }\n \n+static int apply_autostash(void)\n+{\n+\twarning(\"TODO\");\n+\treturn 0;\n+}\n+\n+struct rebase_options {\n+\tenum rebase_type type;\n+\tconst char *state_dir;\n+\tstruct commit *upstream;\n+\tconst char *upstream_name;\n+\tchar *head_name;\n+\tstruct object_id orig_head;\n+\tstruct commit *onto;\n+\tconst char *onto_name;\n+\tconst char *revisions;\n+\tconst char *root;\n+};\n+\n+static int finish_rebase(struct rebase_options *opts)\n+{\n+\tstruct strbuf dir = STRBUF_INIT;\n+\tconst char *argv_gc_auto[] = { \"gc\", \"--auto\", NULL };\n+\n+\tdelete_ref(NULL, \"REBASE_HEAD\", NULL, REF_NO_DEREF);\n+\tapply_autostash();\n+\tclose_all_packs(the_repository->objects);\n+\t/*\n+\t * We ignore errors in 'gc --auto', since the\n+\t * user should see them.\n+\t */\n+\trun_command_v_opt(argv_gc_auto, RUN_GIT_CMD);\n+\tstrbuf_addstr(&dir, opts->state_dir);\n+\tremove_dir_recursively(&dir, 0);\n+\tstrbuf_release(&dir);\n+\n+\treturn 0;\n+}\n+\n+static struct commit *peel_committish(const char *name)\n+{\n+\tstruct object *obj;\n+\tstruct object_id oid;\n+\n+\tif (get_oid(name, &oid))\n+\t\treturn NULL;\n+\tobj = parse_object(&oid);\n+\treturn (struct commit *)peel_to_type(name, 0, obj, OBJ_COMMIT);\n+}\n+\n+static void add_var(struct strbuf *buf, const char *name, const char *value)\n+{\n+\tstrbuf_addstr(buf, name);\n+\tstrbuf_addstr(buf, \"=\");\n+\tsq_quote_buf(buf, value);\n+\tstrbuf_addstr(buf, \"; \");\n+}\n+\n+static int run_specific_rebase(struct rebase_options *opts)\n+{\n+\tconst char *argv[] = { NULL, NULL };\n+\tstruct strbuf script_snippet = STRBUF_INIT;\n+\tint status;\n+\tconst char *backend, *backend_func;\n+\n+\tadd_var(&script_snippet, \"GIT_DIR\", absolute_path(get_git_dir()));\n+\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, \"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+\tadd_var(&script_snippet, \"revisions\", opts->revisions);\n+\n+\tswitch (opts->type) {\n+\tcase REBASE_AM:\n+\t\tbackend = \"git-rebase--am\";\n+\t\tbackend_func = \"git_rebase__am\";\n+\t\tbreak;\n+\tcase REBASE_INTERACTIVE:\n+\t\tbackend = \"git-rebase--interactive\";\n+\t\tbackend_func = \"git_rebase__interactive\";\n+\t\tbreak;\n+\tcase REBASE_MERGE:\n+\t\tbackend = \"git-rebase--merge\";\n+\t\tbackend_func = \"git_rebase__merge\";\n+\t\tbreak;\n+\tcase REBASE_PRESERVE_MERGES:\n+\t\tbackend = \"git-rebase--preserve-merges\";\n+\t\tbackend_func = \"git_rebase__preserve_merges\";\n+\t\tbreak;\n+\tdefault:\n+\t\tBUG(\"Unhandled rebase type %d\", opts->type);\n+\t\tbreak;\n+\t}\n+\n+\tstrbuf_addf(&script_snippet,\n+\t\t    \". git-rebase--common && . %s && %s\",\n+\t\t    backend, backend_func);\n+\targv[0] = script_snippet.buf;\n+\n+\tstatus = run_command_v_opt(argv, RUN_USING_SHELL);\n+\tif (status == 0)\n+\t\tfinish_rebase(opts);\n+\telse if (status == 2) {\n+\t\tstruct strbuf dir = STRBUF_INIT;\n+\n+\t\tapply_autostash();\n+\t\tstrbuf_addstr(&dir, opts->state_dir);\n+\t\tremove_dir_recursively(&dir, 0);\n+\t\tstrbuf_release(&dir);\n+\t\tdie(\"Nothing to do\");\n+\t}\n+\n+\tstrbuf_release(&script_snippet);\n+\n+\treturn status ? -1 : 0;\n+}\n+\n int cmd_rebase(int argc, const char **argv, const char *prefix)\n {\n+\tstruct rebase_options options = { -1 };\n+\tconst char *branch_name;\n+\tint ret, flags, quiet = 0;\n+\tstruct strbuf msg = STRBUF_INIT;\n+\tstruct strbuf revisions = STRBUF_INIT;\n+\tconst char *restrict_revision = NULL;\n+\n \t/*\n \t * NEEDSWORK: Once the builtin rebase has been tested enough\n \t * and git-legacy-rebase.sh is retired to contrib/, this preamble\n@@ -52,5 +194,99 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \ttrace_repo_setup(prefix);\n \tsetup_work_tree();\n \n-\tdie(\"TODO\");\n+\toptions.type = REBASE_AM;\n+\n+\tswitch (options.type) {\n+\tcase REBASE_AM:\n+\t\toptions.state_dir = apply_dir();\n+\t\tbreak;\n+\tcase REBASE_MERGE:\n+\tcase REBASE_INTERACTIVE:\n+\tcase REBASE_PRESERVE_MERGES:\n+\t\toptions.state_dir = merge_dir();\n+\t\tbreak;\n+\t}\n+\tif (!options.root) {\n+\t\tif (argc != 2)\n+\t\t\tdie(\"TODO: handle @{upstream}\");\n+\t\telse {\n+\t\t\toptions.upstream_name = argv[1];\n+\t\t\targc--;\n+\t\t\targv++;\n+\t\t\tif (!strcmp(options.upstream_name, \"-\"))\n+\t\t\t\toptions.upstream_name = \"@{-1}\";\n+\t\t}\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} else\n+\t\tdie(\"TODO: upstream for --root\");\n+\n+\t/* Make sure the branch to rebase onto is valid. */\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} else {\n+\t\toptions.onto = peel_committish(options.onto_name);\n+\t\tif (!options.onto)\n+\t\t\tdie(_(\"Does not point to a valid commit '%s'\"),\n+\t\t\t\toptions.onto_name);\n+\t}\n+\n+\t/*\n+\t * If the branch to rebase is given, that is the branch we will rebase\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 */\n+\tif (argc > 1)\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+\t\toptions.head_name =\n+\t\t\txstrdup_or_null(resolve_ref_unsafe(\"HEAD\", 0, NULL,\n+\t\t\t\t\t &flags));\n+\t\tif (!options.head_name)\n+\t\t\tdie(_(\"No such ref: %s\"), \"HEAD\");\n+\t\tif (flags & REF_ISSYMREF) {\n+\t\t\tif (!skip_prefix(options.head_name,\n+\t\t\t\t\t \"refs/heads/\", &branch_name))\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\tbranch_name = \"HEAD\";\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+\n+\t/* Detach HEAD and reset the tree */\n+\tif (!quiet)\n+\t\tprintf(\"First, rewinding head to replay your work on top of it...\");\n+\n+\tstrbuf_addf(&msg, \"rebase: checkout %s\", options.onto_name);\n+\tif (detach_head_to(&options.onto->object.oid, \"checkout\", msg.buf))\n+\t\tdie(_(\"Could not detach HEAD\"));\n+\tstrbuf_release(&msg);\n+\tif (update_ref(\"rebase\", \"ORIG_HEAD\", &options.orig_head, NULL, 0,\n+\t\t       UPDATE_REFS_MSG_ON_ERR) < 0)\n+\t\tdie(_(\"Could not update ORIG_HEAD to '%s'\"),\n+\t\t    oid_to_hex(&options.orig_head));\n+\n+\tstrbuf_addf(&revisions, \"%s..%s\",\n+\t\t!options.root ? oid_to_hex(&options.onto->object.oid) :\n+\t\t    (restrict_revision ? restrict_revision :\n+\t\t\t    oid_to_hex(&options.upstream->object.oid)),\n+\t\t\t    oid_to_hex(&options.orig_head));\n+\n+\toptions.revisions = revisions.buf;\n+\n+\tret = !!run_specific_rebase(&options);\n+\n+\tstrbuf_release(&revisions);\n+\tfree(options.head_name);\n+\treturn ret;\n }\n-- \n2.18.0\n\n"},{"id":"351890","messageId":"nycvar.QRO.7.76.6.1807082311540.75@tvgsbejvaqbjf.bet","threadId":"48795","inReplyTo":"20180708180104.17921-1-predatoramigo@gmail.com","subject":"Re: [GSoC] [PATCH v4 0/4] rebase: rewrite rebase in C","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2018-07-08T21:14:58Z","receivedAt":"2018-07-08T21:15:12Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Pratik,\n\nOn Sun, 8 Jul 2018, Pratik Karki wrote:\n\n> As a GSoC project, I have been working on the builtin rebase.\n> \n> The motivation behind the rewrite of rebase i.e. from shell script to C\n> are for following reasons:\n> \n> 1.  Writing shell scripts and getting it to production is much faster\n>     than doing the equivalent in C but lacks in performance and extra\n>     workarounds are needed for non-POSIX platforms.\n> \n> 2.  Git for Windows is at loss as the installer size increases due to\n>     addition of extra dependencies for the shell scripts which are usually\n>     available in POSIX compliant platforms.\n> \n> This series of patches serves to demonstrate a minimal builtin rebase\n> which supports running `git rebase <upstream>` and also serves to ask for\n> reviews.\n> \n> Changes since v3:\n> \n>   -  Fix commit message of `rebase: start implementing it as a builtin`.\n> \n>   -  Acknowledge Junio's style reviews.\n> \n>   -  Acknowledge Johannes Schindelin's review.\n\nThe range-diff looks like this (and makes sense to me; you might want to\nfix the typo s/retun/return/, but that's all for now):\n\n-- snipsnap --\n 1:  7baec70f219 !  1:  42778b20edf rebase: start implementing it as a builtin\n    @@ -13,6 +13,12 @@\n         be able to conveniently test new features by configuring\n         `rebase.useBuiltin`.\n\n    +    In the original difftool conversion, if sane_execvp() that attempts to\n    +    run the legacy scripted version returned with non-negative status, the\n    +    command silently exited without doing anything with success, but\n    +    sane_execvp() should not retun with non-negative status in the first\n    +    place, so we use die() to notice such an abnormal case.\n    +\n         We intentionally avoid reading the config directly to avoid\n         messing up the GIT_* environment variables when we need to fall back to\n         exec()ing the shell script. The test of builtin rebase can be done by\n 2:  f385f42dc56 !  2:  a28be7308e6 rebase: refactor common shell functions into their own file\n    @@ -45,6 +45,20 @@\n     diff --git a/git-legacy-rebase.sh b/git-legacy-rebase.sh\n     --- a/git-legacy-rebase.sh\n     +++ b/git-legacy-rebase.sh\n    +@@\n    + LF='\n    + '\n    + ok_to_skip_pre_rebase=\n    +-resolvemsg=\"\n    +-$(gettext 'Resolve all conflicts manually, mark them as resolved with\n    +-\"git add/rm <conflicted_files>\", then run \"git rebase --continue\".\n    +-You can instead skip this commit: run \"git rebase --skip\".\n    +-To abort and get back to the state before \"git rebase\", run \"git rebase --abort\".')\n    +-\"\n    ++\n    + squash_onto=\n    + unset onto\n    + unset restrict_revision\n     @@\n      true)     gpg_sign_opt=-S ;;\n      *)        gpg_sign_opt= ;;\n    @@ -128,6 +142,13 @@\n     +++ b/git-rebase--common.sh\n     @@\n     +\n    ++resolvemsg=\"\n    ++$(gettext 'Resolve all conflicts manually, mark them as resolved with\n    ++\"git add/rm <conflicted_files>\", then run \"git rebase --continue\".\n    ++You can instead skip this commit: run \"git rebase --skip\".\n    ++To abort and get back to the state before \"git rebase\", run \"git rebase --abort\".')\n    ++\"\n    ++\n     +write_basic_state () {\n     +  echo \"$head_name\" > \"$state_dir\"/head-name &&\n     +  echo \"$onto\" > \"$state_dir\"/onto &&\n 3:  147699bd195 =  3:  7591098c4d1 sequencer: refactor the code to detach HEAD to checkout.c\n 4:  bbaa4264caa !  4:  f8429e950a4 builtin/rebase: support running \"git rebase <upstream>\"\n    @@ -232,13 +232,14 @@\n     +  }\n     +\n     +  /*\n    -+  * If the branch to rebase is given, that is the branch we will rebase\n    -+  * branch_name -- branch/commit being rebased, or HEAD (already detached)\n    -+  * orig_head -- commit object name of tip of the branch before rebasing\n    -+  * head_name -- refs/heads/<that-branch> or \"detached HEAD\"\n    -+  */\n    ++   * If the branch to rebase is given, that is the branch we will rebase\n    ++   * branch_name -- branch/commit being rebased, or\n    ++   *                HEAD (already detached)\n    ++   * orig_head -- commit object name of tip of the branch before rebasing\n    ++   * head_name -- refs/heads/<that-branch> or \"detached HEAD\"\n    ++   */\n     +  if (argc > 1)\n    -+           die (\"TODO: handle switch_to\");\n    ++           die(\"TODO: handle switch_to\");\n     +  else {\n     +          /* Do not need to switch branches, we are already on it.  */\n     +          options.head_name =\n\n"},{"id":"351892","messageId":"nycvar.QRO.7.76.6.1807082315350.75@tvgsbejvaqbjf.bet","threadId":"48795","inReplyTo":"20180708180104.17921-4-predatoramigo@gmail.com","subject":"Re: [PATCH v4 3/4] sequencer: refactor the code to detach HEAD to checkout.c","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2018-07-08T21:31:38Z","receivedAt":"2018-07-08T21:31:48Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Pratik,\n\nOn Sun, 8 Jul 2018, Pratik Karki wrote:\n\n> diff --git a/checkout.c b/checkout.c\n> index bdefc888ba..da68915fd7 100644\n> --- a/checkout.c\n> +++ b/checkout.c\n> @@ -2,6 +2,11 @@\n>  #include \"remote.h\"\n>  #include \"refspec.h\"\n>  #include \"checkout.h\"\n> +#include \"unpack-trees.h\"\n> +#include \"lockfile.h\"\n> +#include \"refs.h\"\n> +#include \"tree.h\"\n> +#include \"cache-tree.h\"\n>  \n>  struct tracking_name_data {\n>  \t/* const */ char *src_ref;\n> @@ -42,3 +47,62 @@ const char *unique_tracking_name(const char *name, struct object_id *oid)\n>  \tfree(cb_data.dst_ref);\n>  \treturn NULL;\n>  }\n> +\n> +int detach_head_to(struct object_id *oid, const char *action,\n> +\t\t   const char *reflog_message)\n> +{\n> +\tstruct strbuf ref_name = STRBUF_INIT;\n> +\tstruct tree_desc desc;\n> +\tstruct lock_file lock = LOCK_INIT;\n> +\tstruct unpack_trees_options unpack_tree_opts;\n> +\tstruct tree *tree;\n> +\tint ret = 0;\n> +\n> +\tif (hold_locked_index(&lock, LOCK_REPORT_ON_ERROR) < 0)\n> +\t\treturn -1;\n> +\n> +\tmemset(&unpack_tree_opts, 0, sizeof(unpack_tree_opts));\n> +\tsetup_unpack_trees_porcelain(&unpack_tree_opts, action);\n> +\tunpack_tree_opts.head_idx = 1;\n> +\tunpack_tree_opts.src_index = &the_index;\n> +\tunpack_tree_opts.dst_index = &the_index;\n> +\tunpack_tree_opts.fn = oneway_merge;\n> +\tunpack_tree_opts.merge = 1;\n> +\tunpack_tree_opts.update = 1;\n> +\n> +\tif (read_cache_unmerged()) {\n> +\t\trollback_lock_file(&lock);\n> +\t\tstrbuf_release(&ref_name);\n> +\t\treturn error_resolve_conflict(_(action));\n> +\t}\n> +\n> +\tif (!fill_tree_descriptor(&desc, oid)) {\n> +\t\terror(_(\"failed to find tree of %s\"), oid_to_hex(oid));\n> +\t\trollback_lock_file(&lock);\n> +\t\tfree((void *)desc.buffer);\n> +\t\tstrbuf_release(&ref_name);\n> +\t\treturn -1;\n> +\t}\n> +\n> +\tif (unpack_trees(1, &desc, &unpack_tree_opts)) {\n> +\t\trollback_lock_file(&lock);\n> +\t\tfree((void *)desc.buffer);\n> +\t\tstrbuf_release(&ref_name);\n> +\t\treturn -1;\n> +\t}\n> +\n> +\ttree = parse_tree_indirect(oid);\n> +\tprime_cache_tree(&the_index, tree);\n> +\n> +\tif (write_locked_index(&the_index, &lock, COMMIT_LOCK) < 0)\n> +\t\tret = error(_(\"could not write index\"));\n> +\tfree((void *)desc.buffer);\n> +\n> +\tif (!ret)\n> +\t\tret = update_ref(reflog_message, \"HEAD\", oid,\n> +\t\t\t\t NULL, 0, UPDATE_REFS_MSG_ON_ERR);\n\nI noticed that this does not actually detach the HEAD. That is my fault,\nof course, as I should have not only suggested refactoring the\n`do_reset()` function from `sequencer.c`, but I should also have\nremembered that that function has the benefit of *always* acting on a\ndetached HEAD (because it runs during an interactive rebase), and\ntherefore does not need to detach it explicitly.\n\nIn light of the `reset_hard()` function that you added in a `wip` (see\nhttps://github.com/git/git/pull/505/files#diff-c7361e406139e8cd3a300b80b8f8cc8dR296),\nI could imagine that it might be better, after all, to leave `do_reset()`\nalone and implement a `reset_hard()` function that also optionally\ndetaches the `HEAD` (I *think* that the flag `REF_NO_DEREF` would do that\nfor you).\n\nAlternatively, just update the code in `do_reset()` to use that flag\nfirst, and only *then* extract the code to `checkout.c`.\n\n(I could not resist, and made this quick change on top of your\n`wip-rebase`, and together with a couple more, obvious fixups, this lets\nt3403 pass. It still needs some things that you have not yet sent to the\nmailing list, such as support for `--skip`.)\n\nCiao,\nDscho\n\n"},{"id":"351893","messageId":"nycvar.QRO.7.76.6.1807082331490.75@tvgsbejvaqbjf.bet","threadId":"48795","inReplyTo":"20180708180104.17921-5-predatoramigo@gmail.com","subject":"Re: [PATCH v4 4/4] builtin/rebase: support running \"git rebase <upstream>\"","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2018-07-08T21:44:08Z","receivedAt":"2018-07-08T21:44:22Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Pratik,\n\nOn Sun, 8 Jul 2018, Pratik Karki wrote:\n\n> +\tstrbuf_addf(&script_snippet,\n> +\t\t    \". git-rebase--common && . %s && %s\",\n> +\t\t    backend, backend_func);\n\nIn my quick test (on top of `wip-rebase`), this line needed this change:\n\n-- snip --\n@@ -269,7 +279,8 @@ static int run_specific_rebase(struct rebase_options *opts)\n        }\n\n        strbuf_addf(&script_snippet,\n-                   \"set -x && . git-rebase--common && . %s && %s\",\n+                   \"set -x && \"\n+                   \". git-sh-setup && . git-rebase--common && . %s && %s\",\n                    backend, backend_func);\n        argv[0] = script_snippet.buf;\n-- snap --\n\nObviously, the `set -x && ` part was not part of the patches you sent to\nthe Git mailing list, so please do not let that distract you from the fact\nthat I had to source also `git-sh-setup` (it implies `git-sh-i18n`, and\nthe `eval_gettext` function is defined there and used in the\n`move_to_original_branch` fnuction).\n\nWith this (and the REF_NO_DEREF change), t3404-rebase-skip.sh passes,\nwhich is pretty cool.\n\nCiao,\nDscho\n"},{"id":"351927","messageId":"857b04d8-37b4-596f-6f3e-45b6e2a59442@gmail.com","threadId":"48795","inReplyTo":"20180708180104.17921-2-predatoramigo@gmail.com","subject":"Re: [PATCH v4 1/4] rebase: start implementing it as a builtin","fromName":"Andrei Rybak","fromEmail":"rybak.a.v@gmail.com","sentAt":"2018-07-09T07:59:31Z","receivedAt":"2018-07-09T07:59:37Z","isPatch":true,"sender":{"key":"rybak.a.v@gmail.com","avatar":"https://avatars.githubusercontent.com/u/624072?v=4"},"body":"On 2018-07-08 20:01, Pratik Karki wrote:\n> +\n> +static int use_builtin_rebase(void)\n> +{\n> +\tstruct child_process cp = CHILD_PROCESS_INIT;\n> +\tstruct strbuf out = STRBUF_INIT;\n> +\tint ret;\n> +\n> +\targv_array_pushl(&cp.args,\n> +\t\t\t \"config\", \"--bool\", \"rebase.usebuiltin\", NULL);\n> +\tcp.git_cmd = 1;\n> +\tif (capture_command(&cp, &out, 6))\n> +\t\treturn 0;\n\nDoes strbuf out leak on return here?\n\n> +\n> +\tstrbuf_trim(&out);\n> +\tret = !strcmp(\"true\", out.buf);\n> +\tstrbuf_release(&out);\n> +\treturn ret;\n> +}\n\n\n"},{"id":"351936","messageId":"CAPig+cQopjftfSoPHPZQAzECTAUUwZ-pXYMeWEV=VJBFm63t9g@mail.gmail.com","threadId":"48795","inReplyTo":"857b04d8-37b4-596f-6f3e-45b6e2a59442@gmail.com","subject":"Re: [PATCH v4 1/4] rebase: start implementing it as a builtin","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2018-07-09T08:36:19Z","receivedAt":"2018-07-09T08:36:33Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"On Mon, Jul 9, 2018 at 3:59 AM Andrei Rybak <rybak.a.v@gmail.com> wrote:\n> On 2018-07-08 20:01, Pratik Karki wrote:\n> > +static int use_builtin_rebase(void)\n> > +{\n> > +     struct child_process cp = CHILD_PROCESS_INIT;\n> > +     struct strbuf out = STRBUF_INIT;\n> > +     int ret;\n> > +\n> > +     argv_array_pushl(&cp.args,\n> > +                      \"config\", \"--bool\", \"rebase.usebuiltin\", NULL);\n> > +     cp.git_cmd = 1;\n> > +     if (capture_command(&cp, &out, 6))\n> > +             return 0;\n>\n> Does strbuf out leak on return here?\n\nGood catch. This _is_ a potential leak. Here is an excerpt from the\ndocumentation of pipe_command(), which is called by capture_command():\n\n    Any output collected in the buffers is kept even if the\n    command returns a non-zero exit.\n\nSo, yes, this needs a strbuf_release() before returning.\n\n> > +     strbuf_trim(&out);\n> > +     ret = !strcmp(\"true\", out.buf);\n> > +     strbuf_release(&out);\n> > +     return ret;\n> > +}\n"},{"id":"351955","messageId":"xmqq8t6kfjic.fsf@gitster-ct.c.googlers.com","threadId":"48795","inReplyTo":"20180708180104.17921-4-predatoramigo@gmail.com","subject":"Re: [PATCH v4 3/4] sequencer: refactor the code to detach HEAD to checkout.c","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2018-07-09T16:42:35Z","receivedAt":"2018-07-09T16:42:43Z","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> In the upcoming builtin rebase, we will have to start by detaching\n> the HEAD, just like shell script version does. Essentially, we have\n> to do the same thing as `git checkout -q <revision>^0 --`, in pure C.\n>\n> The aforementioned functionality was already present in `sequencer.c`\n> in `do_reset()` function. But `do_reset()` performs more than detaching\n> the HEAD, and performs action specific to `sequencer.c`.\n>\n> So this commit refactors out that part from `do_reset()`, and moves it\n> to a new function called `detach_head_to()`. As this function has\n> nothing to do with the sequencer, and everything to do with what `git\n> checkout -q <revision>^0 --` does, we move that function to checkout.c.\n>\n> This refactoring actually introduces a slight change in behavior:\n> previously, the index was locked before parsing the argument to the\n> todo command `reset`, while it now gets locked *after* that, in the\n> `detach_head_to()` function.\n>\n> It does not make a huge difference, and the upside is that this closes\n> a few (unlikely) code paths where the index would not be unlocked upon\n> error.\n>\n> Signed-off-by: Pratik Karki <predatoramigo@gmail.com>\n> ---\n\nHere is a place to say \"unchanged since v3\" for a change like this\none that changes neither the proposed log message above nor the\npatch below to help reviewers who have seen the previous round (they\ncan stop reading here).  Hopefully there are more reviewers than you\nwho write new code, so spending a bit more time to help them spend\nless would be an overall win for the project.\n\nThanks.\n\n>  checkout.c  | 64 +++++++++++++++++++++++++++++++++++++++++++++++++++++\n>  checkout.h  |  3 +++\n>  sequencer.c | 58 +++++-------------------------------------------\n>  3 files changed, 72 insertions(+), 53 deletions(-)\n>\n> diff --git a/checkout.c b/checkout.c\n> index bdefc888ba..da68915fd7 100644\n> --- a/checkout.c\n> +++ b/checkout.c\n> @@ -2,6 +2,11 @@\n>  #include \"remote.h\"\n>  #include \"refspec.h\"\n>  #include \"checkout.h\"\n> +#include \"unpack-trees.h\"\n> +#include \"lockfile.h\"\n> +#include \"refs.h\"\n> +#include \"tree.h\"\n> +#include \"cache-tree.h\"\n>  \n>  struct tracking_name_data {\n>  \t/* const */ char *src_ref;\n> @@ -42,3 +47,62 @@ const char *unique_tracking_name(const char *name, struct object_id *oid)\n>  \tfree(cb_data.dst_ref);\n>  \treturn NULL;\n>  }\n> +\n> +int detach_head_to(struct object_id *oid, const char *action,\n> +\t\t   const char *reflog_message)\n> +{\n> +\tstruct strbuf ref_name = STRBUF_INIT;\n> +\tstruct tree_desc desc;\n> +\tstruct lock_file lock = LOCK_INIT;\n> +\tstruct unpack_trees_options unpack_tree_opts;\n> +\tstruct tree *tree;\n> +\tint ret = 0;\n> +\n> +\tif (hold_locked_index(&lock, LOCK_REPORT_ON_ERROR) < 0)\n> +\t\treturn -1;\n> +\n> +\tmemset(&unpack_tree_opts, 0, sizeof(unpack_tree_opts));\n> +\tsetup_unpack_trees_porcelain(&unpack_tree_opts, action);\n> +\tunpack_tree_opts.head_idx = 1;\n> +\tunpack_tree_opts.src_index = &the_index;\n> +\tunpack_tree_opts.dst_index = &the_index;\n> +\tunpack_tree_opts.fn = oneway_merge;\n> +\tunpack_tree_opts.merge = 1;\n> +\tunpack_tree_opts.update = 1;\n> +\n> +\tif (read_cache_unmerged()) {\n> +\t\trollback_lock_file(&lock);\n> +\t\tstrbuf_release(&ref_name);\n> +\t\treturn error_resolve_conflict(_(action));\n> +\t}\n> +\n> +\tif (!fill_tree_descriptor(&desc, oid)) {\n> +\t\terror(_(\"failed to find tree of %s\"), oid_to_hex(oid));\n> +\t\trollback_lock_file(&lock);\n> +\t\tfree((void *)desc.buffer);\n> +\t\tstrbuf_release(&ref_name);\n> +\t\treturn -1;\n> +\t}\n> +\n> +\tif (unpack_trees(1, &desc, &unpack_tree_opts)) {\n> +\t\trollback_lock_file(&lock);\n> +\t\tfree((void *)desc.buffer);\n> +\t\tstrbuf_release(&ref_name);\n> +\t\treturn -1;\n> +\t}\n> +\n> +\ttree = parse_tree_indirect(oid);\n> +\tprime_cache_tree(&the_index, tree);\n> +\n> +\tif (write_locked_index(&the_index, &lock, COMMIT_LOCK) < 0)\n> +\t\tret = error(_(\"could not write index\"));\n> +\tfree((void *)desc.buffer);\n> +\n> +\tif (!ret)\n> +\t\tret = update_ref(reflog_message, \"HEAD\", oid,\n> +\t\t\t\t NULL, 0, UPDATE_REFS_MSG_ON_ERR);\n> +\n> +\tstrbuf_release(&ref_name);\n> +\treturn ret;\n> +\n> +}\n> diff --git a/checkout.h b/checkout.h\n> index 9980711179..6ce46cf4e8 100644\n> --- a/checkout.h\n> +++ b/checkout.h\n> @@ -10,4 +10,7 @@\n>   */\n>  extern const char *unique_tracking_name(const char *name, struct object_id *oid);\n>  \n> +int detach_head_to(struct object_id *oid, const char *action,\n> +\t\t   const char *reflog_message);\n> +\n>  #endif /* CHECKOUT_H */\n> diff --git a/sequencer.c b/sequencer.c\n> index 5354d4d51e..106d518f4d 100644\n> --- a/sequencer.c\n> +++ b/sequencer.c\n> @@ -29,6 +29,7 @@\n>  #include \"oidset.h\"\n>  #include \"commit-slab.h\"\n>  #include \"alias.h\"\n> +#include \"checkout.h\"\n>  \n>  #define GIT_REFLOG_ACTION \"GIT_REFLOG_ACTION\"\n>  \n> @@ -2756,14 +2757,7 @@ static int do_reset(const char *name, int len, struct replay_opts *opts)\n>  {\n>  \tstruct strbuf ref_name = STRBUF_INIT;\n>  \tstruct object_id oid;\n> -\tstruct lock_file lock = LOCK_INIT;\n> -\tstruct tree_desc desc;\n> -\tstruct tree *tree;\n> -\tstruct unpack_trees_options unpack_tree_opts;\n> -\tint ret = 0, i;\n> -\n> -\tif (hold_locked_index(&lock, LOCK_REPORT_ON_ERROR) < 0)\n> -\t\treturn -1;\n> +\tint i;\n>  \n>  \tif (len == 10 && !strncmp(\"[new root]\", name, len)) {\n>  \t\tif (!opts->have_squash_onto) {\n> @@ -2789,56 +2783,14 @@ static int do_reset(const char *name, int len, struct replay_opts *opts)\n>  \t\tif (get_oid(ref_name.buf, &oid) &&\n>  \t\t    get_oid(ref_name.buf + strlen(\"refs/rewritten/\"), &oid)) {\n>  \t\t\terror(_(\"could not read '%s'\"), ref_name.buf);\n> -\t\t\trollback_lock_file(&lock);\n>  \t\t\tstrbuf_release(&ref_name);\n>  \t\t\treturn -1;\n>  \t\t}\n>  \t}\n>  \n> -\tmemset(&unpack_tree_opts, 0, sizeof(unpack_tree_opts));\n> -\tsetup_unpack_trees_porcelain(&unpack_tree_opts, \"reset\");\n> -\tunpack_tree_opts.head_idx = 1;\n> -\tunpack_tree_opts.src_index = &the_index;\n> -\tunpack_tree_opts.dst_index = &the_index;\n> -\tunpack_tree_opts.fn = oneway_merge;\n> -\tunpack_tree_opts.merge = 1;\n> -\tunpack_tree_opts.update = 1;\n> -\n> -\tif (read_cache_unmerged()) {\n> -\t\trollback_lock_file(&lock);\n> -\t\tstrbuf_release(&ref_name);\n> -\t\treturn error_resolve_conflict(_(action_name(opts)));\n> -\t}\n> -\n> -\tif (!fill_tree_descriptor(&desc, &oid)) {\n> -\t\terror(_(\"failed to find tree of %s\"), oid_to_hex(&oid));\n> -\t\trollback_lock_file(&lock);\n> -\t\tfree((void *)desc.buffer);\n> -\t\tstrbuf_release(&ref_name);\n> -\t\treturn -1;\n> -\t}\n> -\n> -\tif (unpack_trees(1, &desc, &unpack_tree_opts)) {\n> -\t\trollback_lock_file(&lock);\n> -\t\tfree((void *)desc.buffer);\n> -\t\tstrbuf_release(&ref_name);\n> -\t\treturn -1;\n> -\t}\n> -\n> -\ttree = parse_tree_indirect(&oid);\n> -\tprime_cache_tree(&the_index, tree);\n> -\n> -\tif (write_locked_index(&the_index, &lock, COMMIT_LOCK) < 0)\n> -\t\tret = error(_(\"could not write index\"));\n> -\tfree((void *)desc.buffer);\n> -\n> -\tif (!ret)\n> -\t\tret = update_ref(reflog_message(opts, \"reset\", \"'%.*s'\",\n> -\t\t\t\t\t\tlen, name), \"HEAD\", &oid,\n> -\t\t\t\t NULL, 0, UPDATE_REFS_MSG_ON_ERR);\n> -\n> -\tstrbuf_release(&ref_name);\n> -\treturn ret;\n> +\treturn detach_head_to(&oid, action_name(opts),\n> +\t\t\t      reflog_message(opts, \"reset\", \"'%.*s'\",\n> +\t\t\t\t\t     len, name));\n>  }\n>  \n>  static int do_merge(struct commit *commit, const char *arg, int arg_len,\n"},{"id":"351958","messageId":"CAOZc8M8qecSkH_zujcesSSGZy=9fS=phuEGMJPx_Vwit_2s+FA@mail.gmail.com","threadId":"48795","inReplyTo":"CAPig+cQopjftfSoPHPZQAzECTAUUwZ-pXYMeWEV=VJBFm63t9g@mail.gmail.com","subject":"Re: [PATCH v4 1/4] rebase: start implementing it as a builtin","fromName":"Pratik Karki","fromEmail":"predatoramigo@gmail.com","sentAt":"2018-07-09T17:18:07Z","receivedAt":"2018-07-09T17:18:22Z","isPatch":true,"sender":{"key":"predatoramigo@gmail.com","avatar":"https://avatars.githubusercontent.com/u/12194950?v=4"},"body":"Hi,\n\nOn Mon, Jul 9, 2018 at 2:21 PM Eric Sunshine <sunshine@sunshineco.com> wrote:\n>\n> On Mon, Jul 9, 2018 at 3:59 AM Andrei Rybak <rybak.a.v@gmail.com> wrote:\n> > On 2018-07-08 20:01, Pratik Karki wrote:\n> > > +static int use_builtin_rebase(void)\n> > > +{\n> > > +     struct child_process cp = CHILD_PROCESS_INIT;\n> > > +     struct strbuf out = STRBUF_INIT;\n> > > +     int ret;\n> > > +\n> > > +     argv_array_pushl(&cp.args,\n> > > +                      \"config\", \"--bool\", \"rebase.usebuiltin\", NULL);\n> > > +     cp.git_cmd = 1;\n> > > +     if (capture_command(&cp, &out, 6))\n> > > +             return 0;\n> >\n> > Does strbuf out leak on return here?\n>\n> Good catch. This _is_ a potential leak. Here is an excerpt from the\n> documentation of pipe_command(), which is called by capture_command():\n>\n>     Any output collected in the buffers is kept even if the\n>     command returns a non-zero exit.\n>\n> So, yes, this needs a strbuf_release() before returning.\n\nHmm. This seems to be a problem. Thanks for reviewing.\n"},{"id":"351959","messageId":"CAOZc8M9HJ86vJ4Cbz5RhP_bd0Ezgp7x+zu5xqhvrxiCGED+NYA@mail.gmail.com","threadId":"48795","inReplyTo":"xmqq8t6kfjic.fsf@gitster-ct.c.googlers.com","subject":"Re: [PATCH v4 3/4] sequencer: refactor the code to detach HEAD to checkout.c","fromName":"Pratik Karki","fromEmail":"predatoramigo@gmail.com","sentAt":"2018-07-09T17:20:05Z","receivedAt":"2018-07-09T17:20:21Z","isPatch":true,"sender":{"key":"predatoramigo@gmail.com","avatar":"https://avatars.githubusercontent.com/u/12194950?v=4"},"body":"On Mon, Jul 9, 2018 at 10:27 PM Junio C Hamano <gitster@pobox.com> wrote:\n>\n> Pratik Karki <predatoramigo@gmail.com> writes:\n>\n> > In the upcoming builtin rebase, we will have to start by detaching\n> > the HEAD, just like shell script version does. Essentially, we have\n> > to do the same thing as `git checkout -q <revision>^0 --`, in pure C.\n> >\n> > The aforementioned functionality was already present in `sequencer.c`\n> > in `do_reset()` function. But `do_reset()` performs more than detaching\n> > the HEAD, and performs action specific to `sequencer.c`.\n> >\n> > So this commit refactors out that part from `do_reset()`, and moves it\n> > to a new function called `detach_head_to()`. As this function has\n> > nothing to do with the sequencer, and everything to do with what `git\n> > checkout -q <revision>^0 --` does, we move that function to checkout.c.\n> >\n> > This refactoring actually introduces a slight change in behavior:\n> > previously, the index was locked before parsing the argument to the\n> > todo command `reset`, while it now gets locked *after* that, in the\n> > `detach_head_to()` function.\n> >\n> > It does not make a huge difference, and the upside is that this closes\n> > a few (unlikely) code paths where the index would not be unlocked upon\n> > error.\n> >\n> > Signed-off-by: Pratik Karki <predatoramigo@gmail.com>\n> > ---\n>\n> Here is a place to say \"unchanged since v3\" for a change like this\n> one that changes neither the proposed log message above nor the\n> patch below to help reviewers who have seen the previous round (they\n> can stop reading here).  Hopefully there are more reviewers than you\n> who write new code, so spending a bit more time to help them spend\n> less would be an overall win for the project.\n\nThanks for the review. I'll keep this in mind, the next time.\n"},{"id":"351960","messageId":"CAOZc8M8YmLwJOzG-1jyz8ft4W_tJMwNs6kSV8inX1q_zmDW8Sg@mail.gmail.com","threadId":"48795","inReplyTo":"nycvar.QRO.7.76.6.1807082315350.75@tvgsbejvaqbjf.bet","subject":"Re: [PATCH v4 3/4] sequencer: refactor the code to detach HEAD to checkout.c","fromName":"Pratik Karki","fromEmail":"predatoramigo@gmail.com","sentAt":"2018-07-09T17:23:35Z","receivedAt":"2018-07-09T17:23:51Z","isPatch":true,"sender":{"key":"predatoramigo@gmail.com","avatar":"https://avatars.githubusercontent.com/u/12194950?v=4"},"body":"Hi,\nOn Mon, Jul 9, 2018 at 3:16 AM Johannes Schindelin\n<Johannes.Schindelin@gmx.de> wrote:\n>\n> Hi Pratik,\n>\n> On Sun, 8 Jul 2018, Pratik Karki wrote:\n>\n> > diff --git a/checkout.c b/checkout.c\n> > index bdefc888ba..da68915fd7 100644\n> > --- a/checkout.c\n> > +++ b/checkout.c\n> > @@ -2,6 +2,11 @@\n> >  #include \"remote.h\"\n> >  #include \"refspec.h\"\n> >  #include \"checkout.h\"\n> > +#include \"unpack-trees.h\"\n> > +#include \"lockfile.h\"\n> > +#include \"refs.h\"\n> > +#include \"tree.h\"\n> > +#include \"cache-tree.h\"\n> >\n> >  struct tracking_name_data {\n> >       /* const */ char *src_ref;\n> > @@ -42,3 +47,62 @@ const char *unique_tracking_name(const char *name, struct object_id *oid)\n> >       free(cb_data.dst_ref);\n> >       return NULL;\n> >  }\n> > +\n> > +int detach_head_to(struct object_id *oid, const char *action,\n> > +                const char *reflog_message)\n> > +{\n> > +     struct strbuf ref_name = STRBUF_INIT;\n> > +     struct tree_desc desc;\n> > +     struct lock_file lock = LOCK_INIT;\n> > +     struct unpack_trees_options unpack_tree_opts;\n> > +     struct tree *tree;\n> > +     int ret = 0;\n> > +\n> > +     if (hold_locked_index(&lock, LOCK_REPORT_ON_ERROR) < 0)\n> > +             return -1;\n> > +\n> > +     memset(&unpack_tree_opts, 0, sizeof(unpack_tree_opts));\n> > +     setup_unpack_trees_porcelain(&unpack_tree_opts, action);\n> > +     unpack_tree_opts.head_idx = 1;\n> > +     unpack_tree_opts.src_index = &the_index;\n> > +     unpack_tree_opts.dst_index = &the_index;\n> > +     unpack_tree_opts.fn = oneway_merge;\n> > +     unpack_tree_opts.merge = 1;\n> > +     unpack_tree_opts.update = 1;\n> > +\n> > +     if (read_cache_unmerged()) {\n> > +             rollback_lock_file(&lock);\n> > +             strbuf_release(&ref_name);\n> > +             return error_resolve_conflict(_(action));\n> > +     }\n> > +\n> > +     if (!fill_tree_descriptor(&desc, oid)) {\n> > +             error(_(\"failed to find tree of %s\"), oid_to_hex(oid));\n> > +             rollback_lock_file(&lock);\n> > +             free((void *)desc.buffer);\n> > +             strbuf_release(&ref_name);\n> > +             return -1;\n> > +     }\n> > +\n> > +     if (unpack_trees(1, &desc, &unpack_tree_opts)) {\n> > +             rollback_lock_file(&lock);\n> > +             free((void *)desc.buffer);\n> > +             strbuf_release(&ref_name);\n> > +             return -1;\n> > +     }\n> > +\n> > +     tree = parse_tree_indirect(oid);\n> > +     prime_cache_tree(&the_index, tree);\n> > +\n> > +     if (write_locked_index(&the_index, &lock, COMMIT_LOCK) < 0)\n> > +             ret = error(_(\"could not write index\"));\n> > +     free((void *)desc.buffer);\n> > +\n> > +     if (!ret)\n> > +             ret = update_ref(reflog_message, \"HEAD\", oid,\n> > +                              NULL, 0, UPDATE_REFS_MSG_ON_ERR);\n>\n> I noticed that this does not actually detach the HEAD. That is my fault,\n> of course, as I should have not only suggested refactoring the\n> `do_reset()` function from `sequencer.c`, but I should also have\n> remembered that that function has the benefit of *always* acting on a\n> detached HEAD (because it runs during an interactive rebase), and\n> therefore does not need to detach it explicitly.\n>\n> In light of the `reset_hard()` function that you added in a `wip` (see\n> https://github.com/git/git/pull/505/files#diff-c7361e406139e8cd3a300b80b8f8cc8dR296),\n> I could imagine that it might be better, after all, to leave `do_reset()`\n> alone and implement a `reset_hard()` function that also optionally\n> detaches the `HEAD` (I *think* that the flag `REF_NO_DEREF` would do that\n> for you).\n\nYes. I think this will be better. Thanks.\n\n> Alternatively, just update the code in `do_reset()` to use that flag\n> first, and only *then* extract the code to `checkout.c`.\n>\n> (I could not resist, and made this quick change on top of your\n> `wip-rebase`, and together with a couple more, obvious fixups, this lets\n> t3403 pass. It still needs some things that you have not yet sent to the\n> mailing list, such as support for `--skip`.)\n\nThank you for taking the time to review.\n"},{"id":"352837","messageId":"ae561025-3e99-0e4a-569a-c1ff1f2a2e58@drbeat.li","threadId":"48795","inReplyTo":"20180706120815.17851-5-predatoramigo@gmail.com","subject":"Re: [PATCH v3 4/4] builtin/rebase: support running \"git rebase <upstream>\"","fromName":"Beat Bolli","fromEmail":"dev+git@drbeat.li","sentAt":"2018-07-17T21:49:15Z","receivedAt":"2018-07-17T21:49:22Z","isPatch":true,"sender":{"key":"dev+git@drbeat.li","avatar":"https://avatars.githubusercontent.com/u/21444?v=4"},"body":"On 06.07.18 14:08, Pratik Karki wrote:\n> +static GIT_PATH_FUNC(apply_dir, \"rebase-apply\");\n> +static GIT_PATH_FUNC(merge_dir, \"rebase-merge\");\n\nMaybe fix this up with\n\n-static GIT_PATH_FUNC(apply_dir, \"rebase-apply\");\n-static GIT_PATH_FUNC(merge_dir, \"rebase-merge\");\n+static GIT_PATH_FUNC(apply_dir, \"rebase-apply\")\n+static GIT_PATH_FUNC(merge_dir, \"rebase-merge\")\n\n?\n\n(See\nhttps://public-inbox.org/git/20180709192537.18564-5-dev+git@drbeat.li/#t)\n\nCheers, Beat\n"},{"id":"352839","messageId":"edffa564-28e4-a0b1-8be3-865f420a88be@drbeat.li","threadId":"48795","inReplyTo":"ae561025-3e99-0e4a-569a-c1ff1f2a2e58@drbeat.li","subject":"Re: [PATCH v3 4/4] builtin/rebase: support running \"git rebase <upstream>\"","fromName":"Beat Bolli","fromEmail":"dev+git@drbeat.li","sentAt":"2018-07-17T21:55:56Z","receivedAt":"2018-07-17T21:56:02Z","isPatch":true,"sender":{"key":"dev+git@drbeat.li","avatar":"https://avatars.githubusercontent.com/u/21444?v=4"},"body":"On 17.07.18 23:49, Beat Bolli wrote:\n> On 06.07.18 14:08, Pratik Karki wrote:\n>> +static GIT_PATH_FUNC(apply_dir, \"rebase-apply\");\n>> +static GIT_PATH_FUNC(merge_dir, \"rebase-merge\");\n> \n> Maybe fix this up with\n> \n> -static GIT_PATH_FUNC(apply_dir, \"rebase-apply\");\n> -static GIT_PATH_FUNC(merge_dir, \"rebase-merge\");\n> +static GIT_PATH_FUNC(apply_dir, \"rebase-apply\")\n> +static GIT_PATH_FUNC(merge_dir, \"rebase-merge\")\n> \n> ?\n\nSorry, this should have been a reply to [PATCH v4 4/4]. The remark still\napplies, though.\n\n> (See https://public-inbox.org/git/20180709192537.18564-5-dev+git@drbeat.li/#t)\n\nCheers, Beat\n\n"},{"id":"353303","messageId":"CACsJy8D9mX4imSgQUdPgQEuj_CsuPwSUc9zLKjDTp4-q+Jnwkg@mail.gmail.com","threadId":"48795","inReplyTo":"20180708180104.17921-2-predatoramigo@gmail.com","subject":"Re: [PATCH v4 1/4] rebase: start implementing it as a builtin","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2018-07-22T09:14:26Z","receivedAt":"2018-07-22T09:14:54Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Sun, Jul 8, 2018 at 8:03 PM Pratik Karki <predatoramigo@gmail.com> wrote:\n> +int cmd_rebase(int argc, const char **argv, const char *prefix)\n> +{\n> +       /*\n> +        * NEEDSWORK: Once the builtin rebase has been tested enough\n> +        * and git-legacy-rebase.sh is retired to contrib/, this preamble\n> +        * can be removed.\n> +        */\n> +\n> +       if (!use_builtin_rebase()) {\n> +               const char *path = mkpath(\"%s/git-legacy-rebase\",\n> +                                         git_exec_path());\n> +\n> +               if (sane_execvp(path, (char **)argv) < 0)\n> +                       die_errno(\"could not exec %s\", path);\n\nPlease wrap all user visible strings in thi series in _().\n\n> +               else\n> +                       die(\"sane_execvp() returned???\");\n\nor if it's definitely a bug in the code, go with BUG()\n-- \nDuy\n"},{"id":"353908","messageId":"20180730162920.20318-1-predatoramigo@gmail.com","threadId":"48795","inReplyTo":"20180708180104.17921-1-predatoramigo@gmail.com","subject":"[GSoC] [PATCH v5 0/3] rebase: rewrite rebase in C","fromName":"Pratik Karki","fromEmail":"predatoramigo@gmail.com","sentAt":"2018-07-30T16:29:17Z","receivedAt":"2018-07-30T16:29:38Z","isPatch":true,"sender":{"key":"predatoramigo@gmail.com","avatar":"https://avatars.githubusercontent.com/u/12194950?v=4"},"body":"As a GSoC project, I have been working on the builtin rebase.\n\nThe motivation behind the rewrite of rebase i.e. from shell script to C\nare for following reasons:\n\n1.  Writing shell scripts and getting it to production is much faster\n    than doing the equivalent in C but lacks in performance and extra\n    workarounds are needed for non-POSIX platforms.\n\n2.  Git for Windows is at loss as the installer size increases due to\n    addition of extra dependencies for the shell scripts which are usually\n    available in POSIX compliant platforms.\n\nThis series of patches serves to demonstrate a minimal builtin rebase\nwhich supports running `git rebase <upstream>` and also serves to ask for\nreviews.\n\nChanges since v4:\n\n  -  Remove the `do_reset()` refactored function from sequencer.\n     In other words `sequencer: refactor the code to detach HEAD to checkout.c`\n     patch was dropped to introduce a new function `reset_hard()` for `rebase.c`\n     (as suggested by Johannes).\n\n  -  Fix a case of leak in `rebase: start implementing it as a builtin`.\n     (as pointed out by Andrei Rybak and Eric Sunshine).\n\n  -  Wrap the user visible comments in `_()` and used `BUG()` depending on the\n     scenarios (as pointed out by Duy Nguyen).\n\n  -  Fix the macro `GIT_PATH_FUNC` which expands to function definition and\n     doesn't require semicolons (as pointed out by Beat Bolli).\n\nPratik Karki (3):\n  rebase: start implementing it as a builtin\n  rebase: refactor common shell functions into their own file\n  builtin/rebase: support running \"git rebase <upstream>\"\n\n .gitignore                            |   2 +\n Makefile                              |   4 +-\n builtin.h                             |   1 +\n builtin/rebase.c                      | 406 ++++++++++++++++++++++++++\n git-rebase.sh => git-legacy-rebase.sh |  69 +----\n git-rebase--common.sh                 |  68 +++++\n git.c                                 |   6 +\n 7 files changed, 488 insertions(+), 68 deletions(-)\n create mode 100644 builtin/rebase.c\n rename git-rebase.sh => git-legacy-rebase.sh (90%)\n create mode 100644 git-rebase--common.sh\n\n-- \n2.18.0\n\n"},{"id":"353909","messageId":"20180730162920.20318-2-predatoramigo@gmail.com","threadId":"48795","inReplyTo":"20180730162920.20318-1-predatoramigo@gmail.com","subject":"[PATCH v5 1/3] rebase: start implementing it as a builtin","fromName":"Pratik Karki","fromEmail":"predatoramigo@gmail.com","sentAt":"2018-07-30T16:29:18Z","receivedAt":"2018-07-30T16:29:47Z","isPatch":true,"sender":{"key":"predatoramigo@gmail.com","avatar":"https://avatars.githubusercontent.com/u/12194950?v=4"},"body":"This commit imitates the strategy that was used to convert the\ndifftool to a builtin. We start by renaming the shell script\n`git-rebase.sh` to `git-legacy-rebase.sh` and introduce a\n`builtin/rebase.c` that simply executes the shell script version,\nunless the config setting `rebase.useBuiltin` is set to `true`.\n\nThe motivation behind this is to rewrite all the functionality of the\nshell script version in the aforementioned `rebase.c`, one by one and\nbe able to conveniently test new features by configuring\n`rebase.useBuiltin`.\n\nIn the original difftool conversion, if sane_execvp() that attempts to\nrun the legacy scripted version returned with non-negative status, the\ncommand silently exited without doing anything with success, but\nsane_execvp() should not return with non-negative status in the first\nplace, so we use die() to notice such an abnormal case.\n\nWe intentionally avoid reading the config directly to avoid\nmessing up the GIT_* environment variables when we need to fall back to\nexec()ing the shell script. The test of builtin rebase can be done by\n`git -c rebase.useBuiltin=true rebase ...`\n\nSigned-off-by: Pratik Karki <predatoramigo@gmail.com>\n---\n .gitignore                            |  1 +\n Makefile                              |  3 +-\n builtin.h                             |  1 +\n builtin/rebase.c                      | 58 +++++++++++++++++++++++++++\n git-rebase.sh => git-legacy-rebase.sh |  0\n git.c                                 |  6 +++\n 6 files changed, 68 insertions(+), 1 deletion(-)\n create mode 100644 builtin/rebase.c\n rename git-rebase.sh => git-legacy-rebase.sh (100%)\n\ndiff --git a/.gitignore b/.gitignore\nindex 3284a1e9b1..ec23959014 100644\n--- a/.gitignore\n+++ b/.gitignore\n@@ -78,6 +78,7 @@\n /git-init-db\n /git-interpret-trailers\n /git-instaweb\n+/git-legacy-rebase\n /git-log\n /git-ls-files\n /git-ls-remote\ndiff --git a/Makefile b/Makefile\nindex 08e5c54549..a0c410b7d6 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -609,7 +609,7 @@ SCRIPT_SH += git-merge-one-file.sh\n SCRIPT_SH += git-merge-resolve.sh\n SCRIPT_SH += git-mergetool.sh\n SCRIPT_SH += git-quiltimport.sh\n-SCRIPT_SH += git-rebase.sh\n+SCRIPT_SH += git-legacy-rebase.sh\n SCRIPT_SH += git-remote-testgit.sh\n SCRIPT_SH += git-request-pull.sh\n SCRIPT_SH += git-stash.sh\n@@ -1059,6 +1059,7 @@ BUILTIN_OBJS += builtin/prune.o\n BUILTIN_OBJS += builtin/pull.o\n BUILTIN_OBJS += builtin/push.o\n BUILTIN_OBJS += builtin/read-tree.o\n+BUILTIN_OBJS += builtin/rebase.o\n BUILTIN_OBJS += builtin/rebase--helper.o\n BUILTIN_OBJS += builtin/receive-pack.o\n BUILTIN_OBJS += builtin/reflog.o\ndiff --git a/builtin.h b/builtin.h\nindex 0362f1ce25..44651a447f 100644\n--- a/builtin.h\n+++ b/builtin.h\n@@ -202,6 +202,7 @@ extern int cmd_prune_packed(int argc, const char **argv, const char *prefix);\n extern int cmd_pull(int argc, const char **argv, const char *prefix);\n extern int cmd_push(int argc, const char **argv, const char *prefix);\n extern int cmd_read_tree(int argc, const char **argv, const char *prefix);\n+extern int cmd_rebase(int argc, const char **argv, const char *prefix);\n extern int cmd_rebase__helper(int argc, const char **argv, const char *prefix);\n extern int cmd_receive_pack(int argc, const char **argv, const char *prefix);\n extern int cmd_reflog(int argc, const char **argv, const char *prefix);\ndiff --git a/builtin/rebase.c b/builtin/rebase.c\nnew file mode 100644\nindex 0000000000..c44addb2a4\n--- /dev/null\n+++ b/builtin/rebase.c\n@@ -0,0 +1,58 @@\n+/*\n+ * \"git rebase\" builtin command\n+ *\n+ * Copyright (c) 2018 Pratik Karki\n+ */\n+\n+#include \"builtin.h\"\n+#include \"run-command.h\"\n+#include \"exec-cmd.h\"\n+#include \"argv-array.h\"\n+#include \"dir.h\"\n+\n+static int use_builtin_rebase(void)\n+{\n+\tstruct child_process cp = CHILD_PROCESS_INIT;\n+\tstruct strbuf out = STRBUF_INIT;\n+\tint ret;\n+\n+\targv_array_pushl(&cp.args,\n+\t\t\t \"config\", \"--bool\", \"rebase.usebuiltin\", NULL);\n+\tcp.git_cmd = 1;\n+\tif (capture_command(&cp, &out, 6)) {\n+\t\tstrbuf_release(&out);\n+\t\treturn 0;\n+\t}\n+\n+\tstrbuf_trim(&out);\n+\tret = !strcmp(\"true\", out.buf);\n+\tstrbuf_release(&out);\n+\treturn ret;\n+}\n+\n+int cmd_rebase(int argc, const char **argv, const char *prefix)\n+{\n+\t/*\n+\t * NEEDSWORK: Once the builtin rebase has been tested enough\n+\t * and git-legacy-rebase.sh is retired to contrib/, this preamble\n+\t * can be removed.\n+\t */\n+\n+\tif (!use_builtin_rebase()) {\n+\t\tconst char *path = mkpath(\"%s/git-legacy-rebase\",\n+\t\t\t\t\t  git_exec_path());\n+\n+\t\tif (sane_execvp(path, (char **)argv) < 0)\n+\t\t\tdie_errno(_(\"could not exec %s\"), path);\n+\t\telse\n+\t\t\tBUG(\"sane_execvp() returned???\");\n+\t}\n+\n+\tif (argc != 2)\n+\t\tdie(_(\"Usage: %s <base>\"), argv[0]);\n+\tprefix = setup_git_directory();\n+\ttrace_repo_setup(prefix);\n+\tsetup_work_tree();\n+\n+\tdie(\"TODO\");\n+}\ndiff --git a/git-rebase.sh b/git-legacy-rebase.sh\nsimilarity index 100%\nrename from git-rebase.sh\nrename to git-legacy-rebase.sh\ndiff --git a/git.c b/git.c\nindex 3fded74519..d28ad90e31 100644\n--- a/git.c\n+++ b/git.c\n@@ -518,6 +518,12 @@ static struct cmd_struct commands[] = {\n \t{ \"pull\", cmd_pull, RUN_SETUP | NEED_WORK_TREE },\n \t{ \"push\", cmd_push, RUN_SETUP },\n \t{ \"read-tree\", cmd_read_tree, RUN_SETUP | SUPPORT_SUPER_PREFIX},\n+\t/*\n+\t * NEEDSWORK: Until the rebase is independent and needs no redirection\n+\t * to rebase shell script this is kept as is, then should be changed to\n+\t * RUN_SETUP | NEED_WORK_TREE\n+\t */\n+\t{ \"rebase\", cmd_rebase },\n \t{ \"rebase--helper\", cmd_rebase__helper, RUN_SETUP | NEED_WORK_TREE },\n \t{ \"receive-pack\", cmd_receive_pack },\n \t{ \"reflog\", cmd_reflog, RUN_SETUP },\n-- \n2.18.0\n\n"},{"id":"353910","messageId":"20180730162920.20318-3-predatoramigo@gmail.com","threadId":"48795","inReplyTo":"20180730162920.20318-1-predatoramigo@gmail.com","subject":"[PATCH v5 2/3] rebase: refactor common shell functions into their own file","fromName":"Pratik Karki","fromEmail":"predatoramigo@gmail.com","sentAt":"2018-07-30T16:29:19Z","receivedAt":"2018-07-30T16:29:53Z","isPatch":true,"sender":{"key":"predatoramigo@gmail.com","avatar":"https://avatars.githubusercontent.com/u/12194950?v=4"},"body":"The functions present in `git-legacy-rebase.sh` are used by the rebase\nbackends as they are implemented as shell script functions in the\n`git-rebase--<backend>` files.\n\nTo make the `builtin/rebase.c` work, we have to provide support via\na Unix shell script snippet that uses these functions and so, we\nwant to use the rebase backends *directly* from the builtin rebase\nwithout going through `git-legacy-rebase.sh`.\n\nThis commit extracts the functions to a separate file,\n`git-rebase--common`, that will be read by `git-legacy-rebase.sh` and\nby the shell script snippets which will be used extensively in the\nfollowing commits.\n\nSigned-off-by: Pratik Karki <predatoramigo@gmail.com>\n---\nUnchanged since v4.\n\n .gitignore            |  1 +\n Makefile              |  1 +\n git-legacy-rebase.sh  | 69 ++-----------------------------------------\n git-rebase--common.sh | 68 ++++++++++++++++++++++++++++++++++++++++++\n 4 files changed, 72 insertions(+), 67 deletions(-)\n create mode 100644 git-rebase--common.sh\n\ndiff --git a/.gitignore b/.gitignore\nindex ec23959014..824141cba1 100644\n--- a/.gitignore\n+++ b/.gitignore\n@@ -117,6 +117,7 @@\n /git-read-tree\n /git-rebase\n /git-rebase--am\n+/git-rebase--common\n /git-rebase--helper\n /git-rebase--interactive\n /git-rebase--merge\ndiff --git a/Makefile b/Makefile\nindex a0c410b7d6..c59e2f64a1 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -619,6 +619,7 @@ SCRIPT_SH += git-web--browse.sh\n SCRIPT_LIB += git-mergetool--lib\n SCRIPT_LIB += git-parse-remote\n SCRIPT_LIB += git-rebase--am\n+SCRIPT_LIB += git-rebase--common\n SCRIPT_LIB += git-rebase--interactive\n SCRIPT_LIB += git-rebase--preserve-merges\n SCRIPT_LIB += git-rebase--merge\ndiff --git a/git-legacy-rebase.sh b/git-legacy-rebase.sh\nindex 7973447645..af2cdfef03 100755\n--- a/git-legacy-rebase.sh\n+++ b/git-legacy-rebase.sh\n@@ -57,12 +57,7 @@ cd_to_toplevel\n LF='\n '\n ok_to_skip_pre_rebase=\n-resolvemsg=\"\n-$(gettext 'Resolve all conflicts manually, mark them as resolved with\n-\"git add/rm <conflicted_files>\", then run \"git rebase --continue\".\n-You can instead skip this commit: run \"git rebase --skip\".\n-To abort and get back to the state before \"git rebase\", run \"git rebase --abort\".')\n-\"\n+\n squash_onto=\n unset onto\n unset restrict_revision\n@@ -102,6 +97,7 @@ case \"$(git config --bool commit.gpgsign)\" in\n true)\tgpg_sign_opt=-S ;;\n *)\tgpg_sign_opt= ;;\n esac\n+. git-rebase--common\n \n read_basic_state () {\n \ttest -f \"$state_dir/head-name\" &&\n@@ -132,67 +128,6 @@ read_basic_state () {\n \t}\n }\n \n-write_basic_state () {\n-\techo \"$head_name\" > \"$state_dir\"/head-name &&\n-\techo \"$onto\" > \"$state_dir\"/onto &&\n-\techo \"$orig_head\" > \"$state_dir\"/orig-head &&\n-\techo \"$GIT_QUIET\" > \"$state_dir\"/quiet &&\n-\ttest t = \"$verbose\" && : > \"$state_dir\"/verbose\n-\ttest -n \"$strategy\" && echo \"$strategy\" > \"$state_dir\"/strategy\n-\ttest -n \"$strategy_opts\" && echo \"$strategy_opts\" > \\\n-\t\t\"$state_dir\"/strategy_opts\n-\ttest -n \"$allow_rerere_autoupdate\" && echo \"$allow_rerere_autoupdate\" > \\\n-\t\t\"$state_dir\"/allow_rerere_autoupdate\n-\ttest -n \"$gpg_sign_opt\" && echo \"$gpg_sign_opt\" > \"$state_dir\"/gpg_sign_opt\n-\ttest -n \"$signoff\" && echo \"$signoff\" >\"$state_dir\"/signoff\n-}\n-\n-output () {\n-\tcase \"$verbose\" in\n-\t'')\n-\t\toutput=$(\"$@\" 2>&1 )\n-\t\tstatus=$?\n-\t\ttest $status != 0 && printf \"%s\\n\" \"$output\"\n-\t\treturn $status\n-\t\t;;\n-\t*)\n-\t\t\"$@\"\n-\t\t;;\n-\tesac\n-}\n-\n-move_to_original_branch () {\n-\tcase \"$head_name\" in\n-\trefs/*)\n-\t\tmessage=\"rebase finished: $head_name onto $onto\"\n-\t\tgit update-ref -m \"$message\" \\\n-\t\t\t$head_name $(git rev-parse HEAD) $orig_head &&\n-\t\tgit symbolic-ref \\\n-\t\t\t-m \"rebase finished: returning to $head_name\" \\\n-\t\t\tHEAD $head_name ||\n-\t\tdie \"$(eval_gettext \"Could not move back to \\$head_name\")\"\n-\t\t;;\n-\tesac\n-}\n-\n-apply_autostash () {\n-\tif test -f \"$state_dir/autostash\"\n-\tthen\n-\t\tstash_sha1=$(cat \"$state_dir/autostash\")\n-\t\tif git stash apply $stash_sha1 >/dev/null 2>&1\n-\t\tthen\n-\t\t\techo \"$(gettext 'Applied autostash.')\" >&2\n-\t\telse\n-\t\t\tgit stash store -m \"autostash\" -q $stash_sha1 ||\n-\t\t\tdie \"$(eval_gettext \"Cannot store \\$stash_sha1\")\"\n-\t\t\tgettext 'Applying autostash resulted in conflicts.\n-Your changes are safe in the stash.\n-You can run \"git stash pop\" or \"git stash drop\" at any time.\n-' >&2\n-\t\tfi\n-\tfi\n-}\n-\n finish_rebase () {\n \trm -f \"$(git rev-parse --git-path REBASE_HEAD)\"\n \tapply_autostash &&\ndiff --git a/git-rebase--common.sh b/git-rebase--common.sh\nnew file mode 100644\nindex 0000000000..7e39d22871\n--- /dev/null\n+++ b/git-rebase--common.sh\n@@ -0,0 +1,68 @@\n+\n+resolvemsg=\"\n+$(gettext 'Resolve all conflicts manually, mark them as resolved with\n+\"git add/rm <conflicted_files>\", then run \"git rebase --continue\".\n+You can instead skip this commit: run \"git rebase --skip\".\n+To abort and get back to the state before \"git rebase\", run \"git rebase --abort\".')\n+\"\n+\n+write_basic_state () {\n+\techo \"$head_name\" > \"$state_dir\"/head-name &&\n+\techo \"$onto\" > \"$state_dir\"/onto &&\n+\techo \"$orig_head\" > \"$state_dir\"/orig-head &&\n+\techo \"$GIT_QUIET\" > \"$state_dir\"/quiet &&\n+\ttest t = \"$verbose\" && : > \"$state_dir\"/verbose\n+\ttest -n \"$strategy\" && echo \"$strategy\" > \"$state_dir\"/strategy\n+\ttest -n \"$strategy_opts\" && echo \"$strategy_opts\" > \\\n+\t\t\"$state_dir\"/strategy_opts\n+\ttest -n \"$allow_rerere_autoupdate\" && echo \"$allow_rerere_autoupdate\" > \\\n+\t\t\"$state_dir\"/allow_rerere_autoupdate\n+\ttest -n \"$gpg_sign_opt\" && echo \"$gpg_sign_opt\" > \"$state_dir\"/gpg_sign_opt\n+\ttest -n \"$signoff\" && echo \"$signoff\" >\"$state_dir\"/signoff\n+}\n+\n+apply_autostash () {\n+\tif test -f \"$state_dir/autostash\"\n+\tthen\n+\t\tstash_sha1=$(cat \"$state_dir/autostash\")\n+\t\tif git stash apply $stash_sha1 >/dev/null 2>&1\n+\t\tthen\n+\t\t\techo \"$(gettext 'Applied autostash.')\" >&2\n+\t\telse\n+\t\t\tgit stash store -m \"autostash\" -q $stash_sha1 ||\n+\t\t\tdie \"$(eval_gettext \"Cannot store \\$stash_sha1\")\"\n+\t\t\tgettext 'Applying autostash resulted in conflicts.\n+Your changes are safe in the stash.\n+You can run \"git stash pop\" or \"git stash drop\" at any time.\n+' >&2\n+\t\tfi\n+\tfi\n+}\n+\n+move_to_original_branch () {\n+\tcase \"$head_name\" in\n+\trefs/*)\n+\t\tmessage=\"rebase finished: $head_name onto $onto\"\n+\t\tgit update-ref -m \"$message\" \\\n+\t\t\t$head_name $(git rev-parse HEAD) $orig_head &&\n+\t\tgit symbolic-ref \\\n+\t\t\t-m \"rebase finished: returning to $head_name\" \\\n+\t\t\tHEAD $head_name ||\n+\t\tdie \"$(eval_gettext \"Could not move back to \\$head_name\")\"\n+\t\t;;\n+\tesac\n+}\n+\n+output () {\n+\tcase \"$verbose\" in\n+\t'')\n+\t\toutput=$(\"$@\" 2>&1 )\n+\t\tstatus=$?\n+\t\ttest $status != 0 && printf \"%s\\n\" \"$output\"\n+\t\treturn $status\n+\t\t;;\n+\t*)\n+\t\t\"$@\"\n+\t\t;;\n+\tesac\n+}\n-- \n2.18.0\n\n"},{"id":"353911","messageId":"20180730162920.20318-4-predatoramigo@gmail.com","threadId":"48795","inReplyTo":"20180730162920.20318-1-predatoramigo@gmail.com","subject":"[PATCH v5 3/3] builtin/rebase: support running \"git rebase <upstream>\"","fromName":"Pratik Karki","fromEmail":"predatoramigo@gmail.com","sentAt":"2018-07-30T16:29:20Z","receivedAt":"2018-07-30T16:30:01Z","isPatch":true,"sender":{"key":"predatoramigo@gmail.com","avatar":"https://avatars.githubusercontent.com/u/12194950?v=4"},"body":"This patch gives life to the skeleton added in the previous patches:\nWith this change, we can perform a elementary rebase (without any\noptions).\n\nIt can be tested thusly by:\n\ngit -c rebase.usebuiltin=true rebase HEAD~2\n\nThe rebase backends (i.e. the shell script functions defined in\n`git-rebase--<backend>`) are still at work here and the \"builtin\nrebase\"'s purpose is simply to parse the options and set\neverything up so that those rebase backends can do their work.\n\nNote: We take an alternative approach here which is *not* to set the\nenvironment variables via `run_command_v_opt_cd_env()` because those\nvariables would then be visible by processes spawned from the rebase\nbackends. Instead, we work hard to set them in the shell script snippet.\nOn Windows, some of the tests fail merely due to core.fileMode not\nbeing heeded that's why the core.*config variables is parsed here.\n\nThe next commits will handle and support all the wonderful rebase\noptions.\n\nSigned-off-by: Pratik Karki <predatoramigo@gmail.com>\n---\n builtin/rebase.c | 350 ++++++++++++++++++++++++++++++++++++++++++++++-\n 1 file changed, 349 insertions(+), 1 deletion(-)\n\ndiff --git a/builtin/rebase.c b/builtin/rebase.c\nindex c44addb2a4..5863139204 100644\n--- a/builtin/rebase.c\n+++ b/builtin/rebase.c\n@@ -9,6 +9,24 @@\n #include \"exec-cmd.h\"\n #include \"argv-array.h\"\n #include \"dir.h\"\n+#include \"packfile.h\"\n+#include \"refs.h\"\n+#include \"quote.h\"\n+#include \"config.h\"\n+#include \"cache-tree.h\"\n+#include \"unpack-trees.h\"\n+#include \"lockfile.h\"\n+\n+static GIT_PATH_FUNC(apply_dir, \"rebase-apply\")\n+static GIT_PATH_FUNC(merge_dir, \"rebase-merge\")\n+\n+enum rebase_type {\n+\tREBASE_UNSPECIFIED = -1,\n+\tREBASE_AM,\n+\tREBASE_MERGE,\n+\tREBASE_INTERACTIVE,\n+\tREBASE_PRESERVE_MERGES\n+};\n \n static int use_builtin_rebase(void)\n {\n@@ -30,8 +48,243 @@ static int use_builtin_rebase(void)\n \treturn ret;\n }\n \n+static int apply_autostash(void)\n+{\n+\twarning(\"TODO\");\n+\treturn 0;\n+}\n+\n+struct rebase_options {\n+\tenum rebase_type type;\n+\tconst char *state_dir;\n+\tstruct commit *upstream;\n+\tconst char *upstream_name;\n+\tchar *head_name;\n+\tstruct object_id orig_head;\n+\tstruct commit *onto;\n+\tconst char *onto_name;\n+\tconst char *revisions;\n+\tconst char *root;\n+\tconst char *restrict_revision;\n+};\n+\n+static int finish_rebase(struct rebase_options *opts)\n+{\n+\tstruct strbuf dir = STRBUF_INIT;\n+\tconst char *argv_gc_auto[] = { \"gc\", \"--auto\", NULL };\n+\n+\tdelete_ref(NULL, \"REBASE_HEAD\", NULL, REF_NO_DEREF);\n+\tapply_autostash();\n+\tclose_all_packs(the_repository->objects);\n+\t/*\n+\t * We ignore errors in 'gc --auto', since the\n+\t * user should see them.\n+\t */\n+\trun_command_v_opt(argv_gc_auto, RUN_GIT_CMD);\n+\tstrbuf_addstr(&dir, opts->state_dir);\n+\tremove_dir_recursively(&dir, 0);\n+\tstrbuf_release(&dir);\n+\n+\treturn 0;\n+}\n+\n+static struct commit *peel_committish(const char *name)\n+{\n+\tstruct object *obj;\n+\tstruct object_id oid;\n+\n+\tif (get_oid(name, &oid))\n+\t\treturn NULL;\n+\tobj = parse_object(&oid);\n+\treturn (struct commit *)peel_to_type(name, 0, obj, OBJ_COMMIT);\n+}\n+\n+static void add_var(struct strbuf *buf, const char *name, const char *value)\n+{\n+\tstrbuf_addstr(buf, name);\n+\tif (value) {\n+\t\tstrbuf_addstr(buf, \"=\");\n+\t\tsq_quote_buf(buf, value);\n+\t}\n+\tstrbuf_addstr(buf, \"; \");\n+}\n+\n+static int run_specific_rebase(struct rebase_options *opts)\n+{\n+\tconst char *argv[] = { NULL, NULL };\n+\tstruct strbuf script_snippet = STRBUF_INIT;\n+\tint status;\n+\tconst char *backend, *backend_func;\n+\n+\tadd_var(&script_snippet, \"GIT_DIR\", absolute_path(get_git_dir()));\n+\tadd_var(&script_snippet, \"state_dir\", opts->state_dir);\n+\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, \"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+\tadd_var(&script_snippet, \"revisions\", opts->revisions);\n+\tif (opts->restrict_revision == NULL)\n+\t\tadd_var(&script_snippet, \"restrict_revision\", \"\");\n+\telse\n+\t\tadd_var(&script_snippet, \"restrict_revision\",\n+\t\t\topts->restrict_revision);\n+\n+\tswitch (opts->type) {\n+\tcase REBASE_AM:\n+\t\tbackend = \"git-rebase--am\";\n+\t\tbackend_func = \"git_rebase__am\";\n+\t\tbreak;\n+\tcase REBASE_INTERACTIVE:\n+\t\tbackend = \"git-rebase--interactive\";\n+\t\tbackend_func = \"git_rebase__interactive\";\n+\t\tbreak;\n+\tcase REBASE_MERGE:\n+\t\tbackend = \"git-rebase--merge\";\n+\t\tbackend_func = \"git_rebase__merge\";\n+\t\tbreak;\n+\tcase REBASE_PRESERVE_MERGES:\n+\t\tbackend = \"git-rebase--preserve-merges\";\n+\t\tbackend_func = \"git_rebase__preserve_merges\";\n+\t\tbreak;\n+\tdefault:\n+\t\tBUG(\"Unhandled rebase type %d\", opts->type);\n+\t\tbreak;\n+\t}\n+\n+\tstrbuf_addf(&script_snippet,\n+\t\t    \". git-sh-setup && . git-rebase--common && . %s && %s\",\n+\t\t    backend, backend_func);\n+\targv[0] = script_snippet.buf;\n+\n+\tstatus = run_command_v_opt(argv, RUN_USING_SHELL);\n+\tif (status == 0)\n+\t\tfinish_rebase(opts);\n+\telse if (status == 2) {\n+\t\tstruct strbuf dir = STRBUF_INIT;\n+\n+\t\tapply_autostash();\n+\t\tstrbuf_addstr(&dir, opts->state_dir);\n+\t\tremove_dir_recursively(&dir, 0);\n+\t\tstrbuf_release(&dir);\n+\t\tdie(\"Nothing to do\");\n+\t}\n+\n+\tstrbuf_release(&script_snippet);\n+\n+\treturn status ? -1 : 0;\n+}\n+\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+{\n+\tstruct object_id head_oid;\n+\tstruct tree_desc desc;\n+\tstruct lock_file lock = LOCK_INIT;\n+\tstruct unpack_trees_options unpack_tree_opts;\n+\tstruct tree *tree;\n+\tconst char *reflog_action;\n+\tstruct strbuf msg = STRBUF_INIT;\n+\tsize_t prefix_len;\n+\tstruct object_id *orig = NULL, oid_orig,\n+\t\t*old_orig = NULL, oid_old_orig;\n+\tint ret = 0;\n+\n+\tif (hold_locked_index(&lock, LOCK_REPORT_ON_ERROR) < 0)\n+\t\treturn -1;\n+\n+\tif (!oid) {\n+\t\tif (get_oid(\"HEAD\", &head_oid)) {\n+\t\t\trollback_lock_file(&lock);\n+\t\t\treturn error(_(\"could not determine HEAD revision\"));\n+\t\t}\n+\t\toid = &head_oid;\n+\t}\n+\n+\tmemset(&unpack_tree_opts, 0, sizeof(unpack_tree_opts));\n+\tsetup_unpack_trees_porcelain(&unpack_tree_opts, action);\n+\tunpack_tree_opts.head_idx = 1;\n+\tunpack_tree_opts.src_index = the_repository->index;\n+\tunpack_tree_opts.dst_index = the_repository->index;\n+\tunpack_tree_opts.fn = oneway_merge;\n+\tunpack_tree_opts.update = 1;\n+\tif (!detach_head)\n+\t\tunpack_tree_opts.reset = 1;\n+\telse\n+\t\tunpack_tree_opts.merge = 1;\n+\n+\tif (read_index(the_repository->index) < 0) {\n+\t\trollback_lock_file(&lock);\n+\t\treturn error(_(\"could not read index\"));\n+\t}\n+\n+\tif (!fill_tree_descriptor(&desc, oid)) {\n+\t\terror(_(\"failed to find tree of %s\"), oid_to_hex(oid));\n+\t\trollback_lock_file(&lock);\n+\t\tfree((void *)desc.buffer);\n+\t\treturn -1;\n+\t}\n+\n+\tif (unpack_trees(1, &desc, &unpack_tree_opts)) {\n+\t\trollback_lock_file(&lock);\n+\t\tfree((void *)desc.buffer);\n+\t\treturn -1;\n+\t}\n+\n+\ttree = parse_tree_indirect(oid);\n+\tprime_cache_tree(the_repository->index, tree);\n+\n+\tif (write_locked_index(the_repository->index, &lock, COMMIT_LOCK) < 0)\n+\t\tret = error(_(\"could not write index\"));\n+\tfree((void *)desc.buffer);\n+\n+\tif (ret)\n+\t\treturn ret;\n+\n+\treflog_action = getenv(GIT_REFLOG_ACTION_ENVIRONMENT);\n+\tstrbuf_addf(&msg, \"%s: \", reflog_action ? reflog_action : \"rebase\");\n+\tprefix_len = msg.len;\n+\n+\tif (!get_oid(\"ORIG_HEAD\", &oid_old_orig))\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\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 (!switch_to_branch)\n+\t\tret = update_ref(msg.buf, \"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, orig, 0,\n+\t\t\t\t\t UPDATE_REFS_MSG_ON_ERR);\n+\t}\n+\n+\tstrbuf_release(&msg);\n+\treturn ret;\n+}\n+\n int cmd_rebase(int argc, const char **argv, const char *prefix)\n {\n+\tstruct rebase_options options = {\n+\t\t.type = REBASE_UNSPECIFIED,\n+\t};\n+\tconst char *branch_name;\n+\tint ret, flags, quiet = 0;\n+\tstruct strbuf msg = STRBUF_INIT;\n+\tstruct strbuf revisions = STRBUF_INIT;\n+\n \t/*\n \t * NEEDSWORK: Once the builtin rebase has been tested enough\n \t * and git-legacy-rebase.sh is retired to contrib/, this preamble\n@@ -54,5 +307,100 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \ttrace_repo_setup(prefix);\n \tsetup_work_tree();\n \n-\tdie(\"TODO\");\n+\tgit_config(git_default_config, NULL);\n+\n+\tswitch (options.type) {\n+\tcase REBASE_MERGE:\n+\tcase REBASE_INTERACTIVE:\n+\tcase REBASE_PRESERVE_MERGES:\n+\t\toptions.state_dir = merge_dir();\n+\t\tbreak;\n+\tcase REBASE_AM:\n+\t\toptions.state_dir = apply_dir();\n+\t\tbreak;\n+\tdefault:\n+\t\toptions.type = REBASE_AM;\n+\t\toptions.state_dir = apply_dir();\n+\t\tbreak;\n+\t}\n+\n+\tif (!options.root) {\n+\t\tif (argc < 2)\n+\t\t\tdie(\"TODO: handle @{upstream}\");\n+\t\telse {\n+\t\t\toptions.upstream_name = argv[1];\n+\t\t\targc--;\n+\t\t\targv++;\n+\t\t\tif (!strcmp(options.upstream_name, \"-\"))\n+\t\t\t\toptions.upstream_name = \"@{-1}\";\n+\t\t}\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} else\n+\t\tdie(\"TODO: upstream for --root\");\n+\n+\t/* Make sure the branch to rebase onto is valid. */\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} else {\n+\t\toptions.onto = peel_committish(options.onto_name);\n+\t\tif (!options.onto)\n+\t\t\tdie(_(\"Does not point to a valid commit '%s'\"),\n+\t\t\t\toptions.onto_name);\n+\t}\n+\n+\t/*\n+\t * If the branch to rebase is given, that is the branch we will rebase\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 */\n+\tif (argc > 1)\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+\t\toptions.head_name =\n+\t\t\txstrdup_or_null(resolve_ref_unsafe(\"HEAD\", 0, NULL,\n+\t\t\t\t\t &flags));\n+\t\tif (!options.head_name)\n+\t\t\tdie(_(\"No such ref: %s\"), \"HEAD\");\n+\t\tif (flags & REF_ISSYMREF) {\n+\t\t\tif (!skip_prefix(options.head_name,\n+\t\t\t\t\t \"refs/heads/\", &branch_name))\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\tbranch_name = \"HEAD\";\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+\n+\t/* Detach HEAD and reset the tree */\n+\tif (!quiet)\n+\t\tprintf(\"First, rewinding head to replay your work on top of it...\");\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+\tstrbuf_release(&msg);\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 ? options.restrict_revision :\n+\t\t\t    oid_to_hex(&options.upstream->object.oid)),\n+\t\t\t    oid_to_hex(&options.orig_head));\n+\n+\toptions.revisions = revisions.buf;\n+\n+\tret = !!run_specific_rebase(&options);\n+\n+\tstrbuf_release(&revisions);\n+\tfree(options.head_name);\n+\treturn ret;\n }\n-- \n2.18.0\n\n"},{"id":"354138","messageId":"CAOZc8M_FJmMCEB1MkJrBRpLiFjy8OTEg_MxoNQTh5-brHxR-=A@mail.gmail.com","threadId":"48795","inReplyTo":"20180730162920.20318-1-predatoramigo@gmail.com","subject":"Re: [GSoC] [PATCH v5 0/3] rebase: rewrite rebase in C","fromName":"Pratik Karki","fromEmail":"predatoramigo@gmail.com","sentAt":"2018-08-01T00:17:25Z","receivedAt":"2018-08-01T00:17:39Z","isPatch":true,"sender":{"key":"predatoramigo@gmail.com","avatar":"https://avatars.githubusercontent.com/u/12194950?v=4"},"body":"Hi Junio,\n\nDuring recent development, I found out that `v5` has some issues and shouldn't\nbe merged into `next`. I implemented more options and ran a couple of regression\ntests from which I figured out that certain choices I made in those commits\nneed to be reconsidered.\n\nDuring recent development, my working branch `wip-rebase` has passing `t3400`\nand for which I have made some changes to the code already in v5.\n\nCheers,\nPratik\n"},{"id":"354675","messageId":"20180806193111.12229-4-predatoramigo@gmail.com","threadId":"48795","inReplyTo":"20180806193111.12229-1-predatoramigo@gmail.com","subject":"[GSoC] [PATCH v6 3/3] builtin/rebase: support running \"git rebase <upstream>\"","fromName":"Pratik Karki","fromEmail":"predatoramigo@gmail.com","sentAt":"2018-08-06T19:31:11Z","receivedAt":"2018-08-06T19:31:43Z","isPatch":true,"sender":{"key":"predatoramigo@gmail.com","avatar":"https://avatars.githubusercontent.com/u/12194950?v=4"},"body":"This patch gives life to the skeleton added in the previous patches:\nWith this change, we can perform a elementary rebase (without any\noptions).\n\nIt can be tested thusly by:\n\ngit -c rebase.usebuiltin=true rebase HEAD~2\n\nThe rebase backends (i.e. the shell script functions defined in\n`git-rebase--<backend>`) are still at work here and the \"builtin\nrebase\"'s purpose is simply to parse the options and set\neverything up so that those rebase backends can do their work.\n\nNote: We take an alternative approach here which is *not* to set the\nenvironment variables via `run_command_v_opt_cd_env()` because those\nvariables would then be visible by processes spawned from the rebase\nbackends. Instead, we work hard to set them in the shell script snippet.\nOn Windows, some of the tests fail merely due to core.fileMode not\nbeing heeded that's why the core.*config variables is parsed here.\n\nThe `reset_head()` function is currently only used to detach the HEAD\nto onto by way of starting the rebase, but it offers additional\nfunctionality that subsequent patches will need like moving to the\noriginal branch (possibly updating it) and also to do the equivalent of\n`git reset --hard`.\n\nThe next commits will handle and support all the wonderful rebase\noptions.\n\nSigned-off-by: Pratik Karki <predatoramigo@gmail.com>\n---\n builtin/rebase.c | 365 ++++++++++++++++++++++++++++++++++++++++++++++-\n 1 file changed, 364 insertions(+), 1 deletion(-)\n\ndiff --git a/builtin/rebase.c b/builtin/rebase.c\nindex c44addb2a4..e695d8a430 100644\n--- a/builtin/rebase.c\n+++ b/builtin/rebase.c\n@@ -9,6 +9,24 @@\n #include \"exec-cmd.h\"\n #include \"argv-array.h\"\n #include \"dir.h\"\n+#include \"packfile.h\"\n+#include \"refs.h\"\n+#include \"quote.h\"\n+#include \"config.h\"\n+#include \"cache-tree.h\"\n+#include \"unpack-trees.h\"\n+#include \"lockfile.h\"\n+\n+static GIT_PATH_FUNC(apply_dir, \"rebase-apply\")\n+static GIT_PATH_FUNC(merge_dir, \"rebase-merge\")\n+\n+enum rebase_type {\n+\tREBASE_UNSPECIFIED = -1,\n+\tREBASE_AM,\n+\tREBASE_MERGE,\n+\tREBASE_INTERACTIVE,\n+\tREBASE_PRESERVE_MERGES\n+};\n \n static int use_builtin_rebase(void)\n {\n@@ -30,8 +48,260 @@ static int use_builtin_rebase(void)\n \treturn ret;\n }\n \n+static int apply_autostash(void)\n+{\n+\twarning(\"TODO\");\n+\treturn 0;\n+}\n+\n+struct rebase_options {\n+\tenum rebase_type type;\n+\tconst char *state_dir;\n+\tstruct commit *upstream;\n+\tconst char *upstream_name;\n+\tchar *head_name;\n+\tstruct object_id orig_head;\n+\tstruct commit *onto;\n+\tconst char *onto_name;\n+\tconst char *revisions;\n+\tint root;\n+\tstruct commit *restrict_revision;\n+\tint dont_finish_rebase;\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+\tstatic struct strbuf path = STRBUF_INIT;\n+\tstatic size_t prefix_len;\n+\n+\tif (!prefix_len) {\n+\t\tstrbuf_addf(&path, \"%s/\", opts->state_dir);\n+\t\tprefix_len = path.len;\n+\t}\n+\n+\tstrbuf_setlen(&path, prefix_len);\n+\tstrbuf_addstr(&path, filename);\n+\treturn path.buf;\n+}\n+\n+static int finish_rebase(struct rebase_options *opts)\n+{\n+\tstruct strbuf dir = STRBUF_INIT;\n+\tconst char *argv_gc_auto[] = { \"gc\", \"--auto\", NULL };\n+\n+\tdelete_ref(NULL, \"REBASE_HEAD\", NULL, REF_NO_DEREF);\n+\tapply_autostash();\n+\tclose_all_packs(the_repository->objects);\n+\t/*\n+\t * We ignore errors in 'gc --auto', since the\n+\t * user should see them.\n+\t */\n+\trun_command_v_opt(argv_gc_auto, RUN_GIT_CMD);\n+\tstrbuf_addstr(&dir, opts->state_dir);\n+\tremove_dir_recursively(&dir, 0);\n+\tstrbuf_release(&dir);\n+\n+\treturn 0;\n+}\n+\n+static struct commit *peel_committish(const char *name)\n+{\n+\tstruct object *obj;\n+\tstruct object_id oid;\n+\n+\tif (get_oid(name, &oid))\n+\t\treturn NULL;\n+\tobj = parse_object(the_repository, &oid);\n+\treturn (struct commit *)peel_to_type(name, 0, obj, OBJ_COMMIT);\n+}\n+\n+static void add_var(struct strbuf *buf, const char *name, const char *value)\n+{\n+\tif (!value)\n+\t\tstrbuf_addf(buf, \"unset %s; \", name);\n+\telse {\n+\t\tstrbuf_addf(buf, \"%s=\", name);\n+\t\tsq_quote_buf(buf, value);\n+\t\tstrbuf_addstr(buf, \"; \");\n+\t}\n+}\n+\n+static int run_specific_rebase(struct rebase_options *opts)\n+{\n+\tconst char *argv[] = { NULL, NULL };\n+\tstruct strbuf script_snippet = STRBUF_INIT;\n+\tint status;\n+\tconst char *backend, *backend_func;\n+\n+\tadd_var(&script_snippet, \"GIT_DIR\", absolute_path(get_git_dir()));\n+\tadd_var(&script_snippet, \"state_dir\", opts->state_dir);\n+\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, \"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+\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+\n+\tswitch (opts->type) {\n+\tcase REBASE_AM:\n+\t\tbackend = \"git-rebase--am\";\n+\t\tbackend_func = \"git_rebase__am\";\n+\t\tbreak;\n+\tcase REBASE_INTERACTIVE:\n+\t\tbackend = \"git-rebase--interactive\";\n+\t\tbackend_func = \"git_rebase__interactive\";\n+\t\tbreak;\n+\tcase REBASE_MERGE:\n+\t\tbackend = \"git-rebase--merge\";\n+\t\tbackend_func = \"git_rebase__merge\";\n+\t\tbreak;\n+\tcase REBASE_PRESERVE_MERGES:\n+\t\tbackend = \"git-rebase--preserve-merges\";\n+\t\tbackend_func = \"git_rebase__preserve_merges\";\n+\t\tbreak;\n+\tdefault:\n+\t\tBUG(\"Unhandled rebase type %d\", opts->type);\n+\t\tbreak;\n+\t}\n+\n+\tstrbuf_addf(&script_snippet,\n+\t\t    \". git-sh-setup && . git-rebase--common &&\"\n+\t\t    \" . %s && %s\", backend, backend_func);\n+\targv[0] = script_snippet.buf;\n+\n+\tstatus = run_command_v_opt(argv, RUN_USING_SHELL);\n+\tif (opts->dont_finish_rebase)\n+\t\t; /* do nothing */\n+\telse if (status == 0) {\n+\t\tif (!file_exists(state_dir_path(\"stopped-sha\", opts)))\n+\t\t\tfinish_rebase(opts);\n+\t} else if (status == 2) {\n+\t\tstruct strbuf dir = STRBUF_INIT;\n+\n+\t\tapply_autostash();\n+\t\tstrbuf_addstr(&dir, opts->state_dir);\n+\t\tremove_dir_recursively(&dir, 0);\n+\t\tstrbuf_release(&dir);\n+\t\tdie(\"Nothing to do\");\n+\t}\n+\n+\tstrbuf_release(&script_snippet);\n+\n+\treturn status ? -1 : 0;\n+}\n+\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+{\n+\tstruct object_id head_oid;\n+\tstruct tree_desc desc;\n+\tstruct lock_file lock = LOCK_INIT;\n+\tstruct unpack_trees_options unpack_tree_opts;\n+\tstruct tree *tree;\n+\tconst char *reflog_action;\n+\tstruct strbuf msg = STRBUF_INIT;\n+\tsize_t prefix_len;\n+\tstruct object_id *orig = NULL, oid_orig,\n+\t\t*old_orig = NULL, oid_old_orig;\n+\tint ret = 0;\n+\n+\tif (hold_locked_index(&lock, LOCK_REPORT_ON_ERROR) < 0)\n+\t\treturn -1;\n+\n+\tif (!oid) {\n+\t\tif (get_oid(\"HEAD\", &head_oid)) {\n+\t\t\trollback_lock_file(&lock);\n+\t\t\treturn error(_(\"could not determine HEAD revision\"));\n+\t\t}\n+\t\toid = &head_oid;\n+\t}\n+\n+\tmemset(&unpack_tree_opts, 0, sizeof(unpack_tree_opts));\n+\tsetup_unpack_trees_porcelain(&unpack_tree_opts, action);\n+\tunpack_tree_opts.head_idx = 1;\n+\tunpack_tree_opts.src_index = the_repository->index;\n+\tunpack_tree_opts.dst_index = the_repository->index;\n+\tunpack_tree_opts.fn = oneway_merge;\n+\tunpack_tree_opts.update = 1;\n+\tunpack_tree_opts.merge = 1;\n+\tif (!detach_head)\n+\t\tunpack_tree_opts.reset = 1;\n+\n+\tif (read_index_unmerged(the_repository->index) < 0) {\n+\t\trollback_lock_file(&lock);\n+\t\treturn error(_(\"could not read index\"));\n+\t}\n+\n+\tif (!fill_tree_descriptor(&desc, oid)) {\n+\t\terror(_(\"failed to find tree of %s\"), oid_to_hex(oid));\n+\t\trollback_lock_file(&lock);\n+\t\tfree((void *)desc.buffer);\n+\t\treturn -1;\n+\t}\n+\n+\tif (unpack_trees(1, &desc, &unpack_tree_opts)) {\n+\t\trollback_lock_file(&lock);\n+\t\tfree((void *)desc.buffer);\n+\t\treturn -1;\n+\t}\n+\n+\ttree = parse_tree_indirect(oid);\n+\tprime_cache_tree(the_repository->index, tree);\n+\n+\tif (write_locked_index(the_repository->index, &lock, COMMIT_LOCK) < 0)\n+\t\tret = error(_(\"could not write index\"));\n+\tfree((void *)desc.buffer);\n+\n+\tif (ret)\n+\t\treturn ret;\n+\n+\treflog_action = getenv(GIT_REFLOG_ACTION_ENVIRONMENT);\n+\tstrbuf_addf(&msg, \"%s: \", reflog_action ? reflog_action : \"rebase\");\n+\tprefix_len = msg.len;\n+\n+\tif (!get_oid(\"ORIG_HEAD\", &oid_old_orig))\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\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 (!switch_to_branch)\n+\t\tret = update_ref(msg.buf, \"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\t\t\t UPDATE_REFS_MSG_ON_ERR);\n+\t}\n+\n+\tstrbuf_release(&msg);\n+\treturn ret;\n+}\n+\n int cmd_rebase(int argc, const char **argv, const char *prefix)\n {\n+\tstruct rebase_options options = {\n+\t\t.type = REBASE_UNSPECIFIED,\n+\t};\n+\tconst char *branch_name;\n+\tint ret, flags;\n+\tstruct strbuf msg = STRBUF_INIT;\n+\tstruct strbuf revisions = STRBUF_INIT;\n+\n \t/*\n \t * NEEDSWORK: Once the builtin rebase has been tested enough\n \t * and git-legacy-rebase.sh is retired to contrib/, this preamble\n@@ -54,5 +324,98 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)\n \ttrace_repo_setup(prefix);\n \tsetup_work_tree();\n \n-\tdie(\"TODO\");\n+\tgit_config(git_default_config, NULL);\n+\n+\tswitch (options.type) {\n+\tcase REBASE_MERGE:\n+\tcase REBASE_INTERACTIVE:\n+\tcase REBASE_PRESERVE_MERGES:\n+\t\toptions.state_dir = merge_dir();\n+\t\tbreak;\n+\tcase REBASE_AM:\n+\t\toptions.state_dir = apply_dir();\n+\t\tbreak;\n+\tdefault:\n+\t\t/* the default rebase backend is `--am` */\n+\t\toptions.type = REBASE_AM;\n+\t\toptions.state_dir = apply_dir();\n+\t\tbreak;\n+\t}\n+\n+\tif (!options.root) {\n+\t\tif (argc < 2)\n+\t\t\tdie(\"TODO: handle @{upstream}\");\n+\t\telse {\n+\t\t\toptions.upstream_name = argv[1];\n+\t\t\targc--;\n+\t\t\targv++;\n+\t\t\tif (!strcmp(options.upstream_name, \"-\"))\n+\t\t\t\toptions.upstream_name = \"@{-1}\";\n+\t\t}\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} else\n+\t\tdie(\"TODO: upstream for --root\");\n+\n+\t/* Make sure the branch to rebase onto is valid. */\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} else {\n+\t\toptions.onto = peel_committish(options.onto_name);\n+\t\tif (!options.onto)\n+\t\t\tdie(_(\"Does not point to a valid commit '%s'\"),\n+\t\t\t\toptions.onto_name);\n+\t}\n+\n+\t/*\n+\t * If the branch to rebase is given, that is the branch we will rebase\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 */\n+\tif (argc > 1)\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+\t\toptions.head_name =\n+\t\t\txstrdup_or_null(resolve_ref_unsafe(\"HEAD\", 0, NULL,\n+\t\t\t\t\t &flags));\n+\t\tif (!options.head_name)\n+\t\t\tdie(_(\"No such ref: %s\"), \"HEAD\");\n+\t\tif (flags & REF_ISSYMREF) {\n+\t\t\tif (!skip_prefix(options.head_name,\n+\t\t\t\t\t \"refs/heads/\", &branch_name))\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\tbranch_name = \"HEAD\";\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+\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+\tstrbuf_release(&msg);\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+\t\t     oid_to_hex(&options.restrict_revision->object.oid) :\n+\t\t     oid_to_hex(&options.upstream->object.oid)),\n+\t\t    oid_to_hex(&options.orig_head));\n+\n+\toptions.revisions = revisions.buf;\n+\n+\tret = !!run_specific_rebase(&options);\n+\n+\tstrbuf_release(&revisions);\n+\tfree(options.head_name);\n+\treturn ret;\n }\n-- \n2.18.0\n\n"},{"id":"354676","messageId":"20180806193111.12229-3-predatoramigo@gmail.com","threadId":"48795","inReplyTo":"20180806193111.12229-1-predatoramigo@gmail.com","subject":"[GSoC] [PATCH v6 2/3] rebase: refactor common shell functions into their own file","fromName":"Pratik Karki","fromEmail":"predatoramigo@gmail.com","sentAt":"2018-08-06T19:31:10Z","receivedAt":"2018-08-06T19:31:46Z","isPatch":true,"sender":{"key":"predatoramigo@gmail.com","avatar":"https://avatars.githubusercontent.com/u/12194950?v=4"},"body":"The functions present in `git-legacy-rebase.sh` are used by the rebase\nbackends as they are implemented as shell script functions in the\n`git-rebase--<backend>` files.\n\nTo make the `builtin/rebase.c` work, we have to provide support via\na Unix shell script snippet that uses these functions and so, we\nwant to use the rebase backends *directly* from the builtin rebase\nwithout going through `git-legacy-rebase.sh`.\n\nThis commit extracts the functions to a separate file,\n`git-rebase--common`, that will be read by `git-legacy-rebase.sh` and\nby the shell script snippets which will be used extensively in the\nfollowing commits.\n\nSigned-off-by: Pratik Karki <predatoramigo@gmail.com>\n---\nUnchanged since v5.\n\n .gitignore            |  1 +\n Makefile              |  1 +\n git-legacy-rebase.sh  | 69 ++-----------------------------------------\n git-rebase--common.sh | 68 ++++++++++++++++++++++++++++++++++++++++++\n 4 files changed, 72 insertions(+), 67 deletions(-)\n create mode 100644 git-rebase--common.sh\n\ndiff --git a/.gitignore b/.gitignore\nindex ec23959014..824141cba1 100644\n--- a/.gitignore\n+++ b/.gitignore\n@@ -117,6 +117,7 @@\n /git-read-tree\n /git-rebase\n /git-rebase--am\n+/git-rebase--common\n /git-rebase--helper\n /git-rebase--interactive\n /git-rebase--merge\ndiff --git a/Makefile b/Makefile\nindex c311532791..c210681a1d 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -619,6 +619,7 @@ SCRIPT_SH += git-web--browse.sh\n SCRIPT_LIB += git-mergetool--lib\n SCRIPT_LIB += git-parse-remote\n SCRIPT_LIB += git-rebase--am\n+SCRIPT_LIB += git-rebase--common\n SCRIPT_LIB += git-rebase--interactive\n SCRIPT_LIB += git-rebase--preserve-merges\n SCRIPT_LIB += git-rebase--merge\ndiff --git a/git-legacy-rebase.sh b/git-legacy-rebase.sh\nindex 7973447645..af2cdfef03 100755\n--- a/git-legacy-rebase.sh\n+++ b/git-legacy-rebase.sh\n@@ -57,12 +57,7 @@ cd_to_toplevel\n LF='\n '\n ok_to_skip_pre_rebase=\n-resolvemsg=\"\n-$(gettext 'Resolve all conflicts manually, mark them as resolved with\n-\"git add/rm <conflicted_files>\", then run \"git rebase --continue\".\n-You can instead skip this commit: run \"git rebase --skip\".\n-To abort and get back to the state before \"git rebase\", run \"git rebase --abort\".')\n-\"\n+\n squash_onto=\n unset onto\n unset restrict_revision\n@@ -102,6 +97,7 @@ case \"$(git config --bool commit.gpgsign)\" in\n true)\tgpg_sign_opt=-S ;;\n *)\tgpg_sign_opt= ;;\n esac\n+. git-rebase--common\n \n read_basic_state () {\n \ttest -f \"$state_dir/head-name\" &&\n@@ -132,67 +128,6 @@ read_basic_state () {\n \t}\n }\n \n-write_basic_state () {\n-\techo \"$head_name\" > \"$state_dir\"/head-name &&\n-\techo \"$onto\" > \"$state_dir\"/onto &&\n-\techo \"$orig_head\" > \"$state_dir\"/orig-head &&\n-\techo \"$GIT_QUIET\" > \"$state_dir\"/quiet &&\n-\ttest t = \"$verbose\" && : > \"$state_dir\"/verbose\n-\ttest -n \"$strategy\" && echo \"$strategy\" > \"$state_dir\"/strategy\n-\ttest -n \"$strategy_opts\" && echo \"$strategy_opts\" > \\\n-\t\t\"$state_dir\"/strategy_opts\n-\ttest -n \"$allow_rerere_autoupdate\" && echo \"$allow_rerere_autoupdate\" > \\\n-\t\t\"$state_dir\"/allow_rerere_autoupdate\n-\ttest -n \"$gpg_sign_opt\" && echo \"$gpg_sign_opt\" > \"$state_dir\"/gpg_sign_opt\n-\ttest -n \"$signoff\" && echo \"$signoff\" >\"$state_dir\"/signoff\n-}\n-\n-output () {\n-\tcase \"$verbose\" in\n-\t'')\n-\t\toutput=$(\"$@\" 2>&1 )\n-\t\tstatus=$?\n-\t\ttest $status != 0 && printf \"%s\\n\" \"$output\"\n-\t\treturn $status\n-\t\t;;\n-\t*)\n-\t\t\"$@\"\n-\t\t;;\n-\tesac\n-}\n-\n-move_to_original_branch () {\n-\tcase \"$head_name\" in\n-\trefs/*)\n-\t\tmessage=\"rebase finished: $head_name onto $onto\"\n-\t\tgit update-ref -m \"$message\" \\\n-\t\t\t$head_name $(git rev-parse HEAD) $orig_head &&\n-\t\tgit symbolic-ref \\\n-\t\t\t-m \"rebase finished: returning to $head_name\" \\\n-\t\t\tHEAD $head_name ||\n-\t\tdie \"$(eval_gettext \"Could not move back to \\$head_name\")\"\n-\t\t;;\n-\tesac\n-}\n-\n-apply_autostash () {\n-\tif test -f \"$state_dir/autostash\"\n-\tthen\n-\t\tstash_sha1=$(cat \"$state_dir/autostash\")\n-\t\tif git stash apply $stash_sha1 >/dev/null 2>&1\n-\t\tthen\n-\t\t\techo \"$(gettext 'Applied autostash.')\" >&2\n-\t\telse\n-\t\t\tgit stash store -m \"autostash\" -q $stash_sha1 ||\n-\t\t\tdie \"$(eval_gettext \"Cannot store \\$stash_sha1\")\"\n-\t\t\tgettext 'Applying autostash resulted in conflicts.\n-Your changes are safe in the stash.\n-You can run \"git stash pop\" or \"git stash drop\" at any time.\n-' >&2\n-\t\tfi\n-\tfi\n-}\n-\n finish_rebase () {\n \trm -f \"$(git rev-parse --git-path REBASE_HEAD)\"\n \tapply_autostash &&\ndiff --git a/git-rebase--common.sh b/git-rebase--common.sh\nnew file mode 100644\nindex 0000000000..7e39d22871\n--- /dev/null\n+++ b/git-rebase--common.sh\n@@ -0,0 +1,68 @@\n+\n+resolvemsg=\"\n+$(gettext 'Resolve all conflicts manually, mark them as resolved with\n+\"git add/rm <conflicted_files>\", then run \"git rebase --continue\".\n+You can instead skip this commit: run \"git rebase --skip\".\n+To abort and get back to the state before \"git rebase\", run \"git rebase --abort\".')\n+\"\n+\n+write_basic_state () {\n+\techo \"$head_name\" > \"$state_dir\"/head-name &&\n+\techo \"$onto\" > \"$state_dir\"/onto &&\n+\techo \"$orig_head\" > \"$state_dir\"/orig-head &&\n+\techo \"$GIT_QUIET\" > \"$state_dir\"/quiet &&\n+\ttest t = \"$verbose\" && : > \"$state_dir\"/verbose\n+\ttest -n \"$strategy\" && echo \"$strategy\" > \"$state_dir\"/strategy\n+\ttest -n \"$strategy_opts\" && echo \"$strategy_opts\" > \\\n+\t\t\"$state_dir\"/strategy_opts\n+\ttest -n \"$allow_rerere_autoupdate\" && echo \"$allow_rerere_autoupdate\" > \\\n+\t\t\"$state_dir\"/allow_rerere_autoupdate\n+\ttest -n \"$gpg_sign_opt\" && echo \"$gpg_sign_opt\" > \"$state_dir\"/gpg_sign_opt\n+\ttest -n \"$signoff\" && echo \"$signoff\" >\"$state_dir\"/signoff\n+}\n+\n+apply_autostash () {\n+\tif test -f \"$state_dir/autostash\"\n+\tthen\n+\t\tstash_sha1=$(cat \"$state_dir/autostash\")\n+\t\tif git stash apply $stash_sha1 >/dev/null 2>&1\n+\t\tthen\n+\t\t\techo \"$(gettext 'Applied autostash.')\" >&2\n+\t\telse\n+\t\t\tgit stash store -m \"autostash\" -q $stash_sha1 ||\n+\t\t\tdie \"$(eval_gettext \"Cannot store \\$stash_sha1\")\"\n+\t\t\tgettext 'Applying autostash resulted in conflicts.\n+Your changes are safe in the stash.\n+You can run \"git stash pop\" or \"git stash drop\" at any time.\n+' >&2\n+\t\tfi\n+\tfi\n+}\n+\n+move_to_original_branch () {\n+\tcase \"$head_name\" in\n+\trefs/*)\n+\t\tmessage=\"rebase finished: $head_name onto $onto\"\n+\t\tgit update-ref -m \"$message\" \\\n+\t\t\t$head_name $(git rev-parse HEAD) $orig_head &&\n+\t\tgit symbolic-ref \\\n+\t\t\t-m \"rebase finished: returning to $head_name\" \\\n+\t\t\tHEAD $head_name ||\n+\t\tdie \"$(eval_gettext \"Could not move back to \\$head_name\")\"\n+\t\t;;\n+\tesac\n+}\n+\n+output () {\n+\tcase \"$verbose\" in\n+\t'')\n+\t\toutput=$(\"$@\" 2>&1 )\n+\t\tstatus=$?\n+\t\ttest $status != 0 && printf \"%s\\n\" \"$output\"\n+\t\treturn $status\n+\t\t;;\n+\t*)\n+\t\t\"$@\"\n+\t\t;;\n+\tesac\n+}\n-- \n2.18.0\n\n"},{"id":"354677","messageId":"20180806193111.12229-2-predatoramigo@gmail.com","threadId":"48795","inReplyTo":"20180806193111.12229-1-predatoramigo@gmail.com","subject":"[GSoC] [PATCH v6 1/3] rebase: start implementing it as a builtin","fromName":"Pratik Karki","fromEmail":"predatoramigo@gmail.com","sentAt":"2018-08-06T19:31:09Z","receivedAt":"2018-08-06T19:31:53Z","isPatch":true,"sender":{"key":"predatoramigo@gmail.com","avatar":"https://avatars.githubusercontent.com/u/12194950?v=4"},"body":"This commit imitates the strategy that was used to convert the\ndifftool to a builtin. We start by renaming the shell script\n`git-rebase.sh` to `git-legacy-rebase.sh` and introduce a\n`builtin/rebase.c` that simply executes the shell script version,\nunless the config setting `rebase.useBuiltin` is set to `true`.\n\nThe motivation behind this is to rewrite all the functionality of the\nshell script version in the aforementioned `rebase.c`, one by one and\nbe able to conveniently test new features by configuring\n`rebase.useBuiltin`.\n\nIn the original difftool conversion, if sane_execvp() that attempts to\nrun the legacy scripted version returned with non-negative status, the\ncommand silently exited without doing anything with success, but\nsane_execvp() should not return with non-negative status in the first\nplace, so we use die() to notice such an abnormal case.\n\nWe intentionally avoid reading the config directly to avoid\nmessing up the GIT_* environment variables when we need to fall back to\nexec()ing the shell script. The test of builtin rebase can be done by\n`git -c rebase.useBuiltin=true rebase ...`\n\nSigned-off-by: Pratik Karki <predatoramigo@gmail.com>\n---\nUnchanged since v5.\n\n .gitignore                            |  1 +\n Makefile                              |  3 +-\n builtin.h                             |  1 +\n builtin/rebase.c                      | 58 +++++++++++++++++++++++++++\n git-rebase.sh => git-legacy-rebase.sh |  0\n git.c                                 |  6 +++\n 6 files changed, 68 insertions(+), 1 deletion(-)\n create mode 100644 builtin/rebase.c\n rename git-rebase.sh => git-legacy-rebase.sh (100%)\n\ndiff --git a/.gitignore b/.gitignore\nindex 3284a1e9b1..ec23959014 100644\n--- a/.gitignore\n+++ b/.gitignore\n@@ -78,6 +78,7 @@\n /git-init-db\n /git-interpret-trailers\n /git-instaweb\n+/git-legacy-rebase\n /git-log\n /git-ls-files\n /git-ls-remote\ndiff --git a/Makefile b/Makefile\nindex bc4fc8eeab..c311532791 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -609,7 +609,7 @@ SCRIPT_SH += git-merge-one-file.sh\n SCRIPT_SH += git-merge-resolve.sh\n SCRIPT_SH += git-mergetool.sh\n SCRIPT_SH += git-quiltimport.sh\n-SCRIPT_SH += git-rebase.sh\n+SCRIPT_SH += git-legacy-rebase.sh\n SCRIPT_SH += git-remote-testgit.sh\n SCRIPT_SH += git-request-pull.sh\n SCRIPT_SH += git-stash.sh\n@@ -1063,6 +1063,7 @@ BUILTIN_OBJS += builtin/prune.o\n BUILTIN_OBJS += builtin/pull.o\n BUILTIN_OBJS += builtin/push.o\n BUILTIN_OBJS += builtin/read-tree.o\n+BUILTIN_OBJS += builtin/rebase.o\n BUILTIN_OBJS += builtin/rebase--helper.o\n BUILTIN_OBJS += builtin/receive-pack.o\n BUILTIN_OBJS += builtin/reflog.o\ndiff --git a/builtin.h b/builtin.h\nindex 0362f1ce25..44651a447f 100644\n--- a/builtin.h\n+++ b/builtin.h\n@@ -202,6 +202,7 @@ extern int cmd_prune_packed(int argc, const char **argv, const char *prefix);\n extern int cmd_pull(int argc, const char **argv, const char *prefix);\n extern int cmd_push(int argc, const char **argv, const char *prefix);\n extern int cmd_read_tree(int argc, const char **argv, const char *prefix);\n+extern int cmd_rebase(int argc, const char **argv, const char *prefix);\n extern int cmd_rebase__helper(int argc, const char **argv, const char *prefix);\n extern int cmd_receive_pack(int argc, const char **argv, const char *prefix);\n extern int cmd_reflog(int argc, const char **argv, const char *prefix);\ndiff --git a/builtin/rebase.c b/builtin/rebase.c\nnew file mode 100644\nindex 0000000000..c44addb2a4\n--- /dev/null\n+++ b/builtin/rebase.c\n@@ -0,0 +1,58 @@\n+/*\n+ * \"git rebase\" builtin command\n+ *\n+ * Copyright (c) 2018 Pratik Karki\n+ */\n+\n+#include \"builtin.h\"\n+#include \"run-command.h\"\n+#include \"exec-cmd.h\"\n+#include \"argv-array.h\"\n+#include \"dir.h\"\n+\n+static int use_builtin_rebase(void)\n+{\n+\tstruct child_process cp = CHILD_PROCESS_INIT;\n+\tstruct strbuf out = STRBUF_INIT;\n+\tint ret;\n+\n+\targv_array_pushl(&cp.args,\n+\t\t\t \"config\", \"--bool\", \"rebase.usebuiltin\", NULL);\n+\tcp.git_cmd = 1;\n+\tif (capture_command(&cp, &out, 6)) {\n+\t\tstrbuf_release(&out);\n+\t\treturn 0;\n+\t}\n+\n+\tstrbuf_trim(&out);\n+\tret = !strcmp(\"true\", out.buf);\n+\tstrbuf_release(&out);\n+\treturn ret;\n+}\n+\n+int cmd_rebase(int argc, const char **argv, const char *prefix)\n+{\n+\t/*\n+\t * NEEDSWORK: Once the builtin rebase has been tested enough\n+\t * and git-legacy-rebase.sh is retired to contrib/, this preamble\n+\t * can be removed.\n+\t */\n+\n+\tif (!use_builtin_rebase()) {\n+\t\tconst char *path = mkpath(\"%s/git-legacy-rebase\",\n+\t\t\t\t\t  git_exec_path());\n+\n+\t\tif (sane_execvp(path, (char **)argv) < 0)\n+\t\t\tdie_errno(_(\"could not exec %s\"), path);\n+\t\telse\n+\t\t\tBUG(\"sane_execvp() returned???\");\n+\t}\n+\n+\tif (argc != 2)\n+\t\tdie(_(\"Usage: %s <base>\"), argv[0]);\n+\tprefix = setup_git_directory();\n+\ttrace_repo_setup(prefix);\n+\tsetup_work_tree();\n+\n+\tdie(\"TODO\");\n+}\ndiff --git a/git-rebase.sh b/git-legacy-rebase.sh\nsimilarity index 100%\nrename from git-rebase.sh\nrename to git-legacy-rebase.sh\ndiff --git a/git.c b/git.c\nindex fc7d15d549..2c6b188c77 100644\n--- a/git.c\n+++ b/git.c\n@@ -521,6 +521,12 @@ static struct cmd_struct commands[] = {\n \t{ \"pull\", cmd_pull, RUN_SETUP | NEED_WORK_TREE },\n \t{ \"push\", cmd_push, RUN_SETUP },\n \t{ \"read-tree\", cmd_read_tree, RUN_SETUP | SUPPORT_SUPER_PREFIX},\n+\t/*\n+\t * NEEDSWORK: Until the rebase is independent and needs no redirection\n+\t * to rebase shell script this is kept as is, then should be changed to\n+\t * RUN_SETUP | NEED_WORK_TREE\n+\t */\n+\t{ \"rebase\", cmd_rebase },\n \t{ \"rebase--helper\", cmd_rebase__helper, RUN_SETUP | NEED_WORK_TREE },\n \t{ \"receive-pack\", cmd_receive_pack },\n \t{ \"reflog\", cmd_reflog, RUN_SETUP },\n-- \n2.18.0\n\n"},{"id":"354678","messageId":"20180806193111.12229-1-predatoramigo@gmail.com","threadId":"48795","inReplyTo":"20180730162920.20318-1-predatoramigo@gmail.com","subject":"[GSoC] [PATCH v6 0/3] rebase: rewrite rebase in C","fromName":"Pratik Karki","fromEmail":"predatoramigo@gmail.com","sentAt":"2018-08-06T19:31:08Z","receivedAt":"2018-08-06T19:32:00Z","isPatch":true,"sender":{"key":"predatoramigo@gmail.com","avatar":"https://avatars.githubusercontent.com/u/12194950?v=4"},"body":"As a GSoC project, I have been working on the builtin rebase.\n\nThe motivation behind the rewrite of rebase i.e. from shell script to C\nare for following reasons:\n\n1.  Writing shell scripts and getting it to production is much faster\n    than doing the equivalent in C but lacks in performance and extra\n    workarounds are needed for non-POSIX platforms.\n\n2.  Git for Windows is at loss as the installer size increases due to\n    addition of extra dependencies for the shell scripts which are usually\n    available in POSIX compliant platforms.\n\nThis series of patches serves to demonstrate a minimal builtin rebase\nwhich supports running `git rebase <upstream>` and also serves to ask for\nreviews.\n\nThis is only the first patch series, with  many more to come.\nI have finished the conversion, but I want to organize the patches in a neat\npatch series to make review process more pleasant, and you can see the progress\nat <https://github.com/git/git/pull/505>.\n\nThe organization of patches is also almost done. After the follow-up patches,\nthe rebase operation will be handled completely by this `builtin/rebase.c`.\n\nChanges since v5:\n\n  -  Fix `builtin/rebase: support running \"git rebase <upstream>\"` as it\n     does not need to switch to another branch and only needs to detach the\n     `HEAD` for now.\n\n  -  The `reset_head()` function is introduced in\n     `builtin/rebase: support running \"git rebase <upstream>\"`\n     which is only used to detach the `HEAD` to `onto` for starting the rebase,\n     but upcoming patches will add more functionality like moving or updating to\n     original branch.\n\n  -  Lots of changes that fix bugs discovered while getting the test suite to pass\n     with the patch series.\n\nPratik Karki (3):\n  rebase: start implementing it as a builtin\n  rebase: refactor common shell functions into their own file\n  builtin/rebase: support running \"git rebase <upstream>\"\n\n .gitignore                            |   2 +\n Makefile                              |   4 +-\n builtin.h                             |   1 +\n builtin/rebase.c                      | 421 ++++++++++++++++++++++++++\n git-rebase.sh => git-legacy-rebase.sh |  69 +----\n git-rebase--common.sh                 |  68 +++++\n git.c                                 |   6 +\n 7 files changed, 503 insertions(+), 68 deletions(-)\n create mode 100644 builtin/rebase.c\n rename git-rebase.sh => git-legacy-rebase.sh (90%)\n create mode 100644 git-rebase--common.sh\n\n-- \n2.18.0\n\n"},{"id":"355883","messageId":"xmqq7ekqdm3b.fsf@gitster-ct.c.googlers.com","threadId":"48795","inReplyTo":"20180806193111.12229-4-predatoramigo@gmail.com","subject":"Re: [GSoC] [PATCH v6 3/3] builtin/rebase: support running \"git rebase <upstream>\"","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2018-08-16T21:43:04Z","receivedAt":"2018-08-16T21:43:09Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Now, there is a parallel \"rebase-i-in-c\" effort going on, and of\ncourse, setting various shell various and formulating a command line\nthat essentially does \n\n\t. git-rebase--$backend\n\nof course stops working.\n\n> +static int run_specific_rebase(struct rebase_options *opts)\n> +{\n> +\tconst char *argv[] = { NULL, NULL };\n> + ...\n> +\tswitch (opts->type) {\n> +\tcase REBASE_AM:\n> +\t\tbackend = \"git-rebase--am\";\n> +\t\tbackend_func = \"git_rebase__am\";\n> +\t\tbreak;\n> +\tcase REBASE_INTERACTIVE:\n> +\t\tbackend = \"git-rebase--interactive\";\n> +\t\tbackend_func = \"git_rebase__interactive\";\n> +\t\tbreak;\n> + ...\n> +\tstrbuf_addf(&script_snippet,\n> +\t\t    \". git-sh-setup && . git-rebase--common &&\"\n> +\t\t    \" . %s && %s\", backend, backend_func);\n> +\targv[0] = script_snippet.buf;\n> +\n> +\tstatus = run_command_v_opt(argv, RUN_USING_SHELL);\n\n"}]}