{"thread":{"id":"14495","subject":"[PATCH 2/2] Introduce git am --abort","startedAt":"2008-07-16T20:45:20Z","lastAt":"2008-07-16T20:45:21Z","messageCount":2,"participants":["Stephan Beyer"],"isPatch":true,"patchVersion":1,"patchTotal":2},"messages":[{"id":"83588","messageId":"5f60ea3acffdb5dfdbe0ea6e81133efadab9f20d.1216233919.git.s-beyer@gmx.net","threadId":"14495","inReplyTo":"cover.1216233918.git.s-beyer@gmx.net","subject":"[PATCH 1/2] Migrate git-am to use git-sequencer","fromName":"Stephan Beyer","fromEmail":"s-beyer@gmx.net","sentAt":"2008-07-16T20:45:20Z","receivedAt":"2008-07-16T20:45:20Z","isPatch":true,"sender":{"key":"s-beyer@gmx.net","avatar":"https://avatars.githubusercontent.com/u/143889?v=4"},"body":"In principle a migration to git-sequencer is straightforward:\nPut all the mail from the mbox or Maildir into .git/rebase and\nlet the \"patch\" instruction of sequencer do the rest of the\nwork.\n\nThe git am --interactive part is a little more tricky.\nTo get this working, \"pause\" instructions are put after every\n\"patch\" instruction and then be_interactive() swoops in,\nthat allows the user to input his choice.\n\nAlso a slight behavior change, that can be seen in the diff of\nthe test cases, should be mentioned: If git-am has nothing to do,\nthe user does not have to remove .git/rebase or run git-am --skip\nmanually. It automatically aborts instead, which seems to be\nan improvement.\n\nMentored-by: Christian Couder <chriscool@tuxfamily.org>\nMentored-by: Daniel Barkalow <barkalow@iabervon.org>\nSigned-off-by: Stephan Beyer <s-beyer@gmx.net>\n---\n git-am.sh     |  612 ++++++++++++++++++++-------------------------------------\n git-rebase.sh |    1 +\n t/t4150-am.sh |    6 +-\n 3 files changed, 214 insertions(+), 405 deletions(-)\n\ndiff --git a/git-am.sh b/git-am.sh\nindex cc8787b..e36f22c 100755\n--- a/git-am.sh\n+++ b/git-am.sh\n@@ -33,102 +33,143 @@ cd_to_toplevel\n git var GIT_COMMITTER_IDENT >/dev/null ||\n \tdie \"You need to set your committer info first\"\n \n-stop_here () {\n-    echo \"$1\" >\"$dotest/next\"\n-    exit 1\n+cleanup () {\n+\tgit gc --auto\n+\trm -fr \"$dotest\"\n }\n \n-stop_here_user_resolve () {\n-    if [ -n \"$resolvemsg\" ]; then\n-\t    printf '%s\\n' \"$resolvemsg\"\n-\t    stop_here $1\n-    fi\n-    cmdline=$(basename $0)\n-    if test '' != \"$interactive\"\n-    then\n-        cmdline=\"$cmdline -i\"\n-    fi\n-    if test '' != \"$threeway\"\n-    then\n-        cmdline=\"$cmdline -3\"\n-    fi\n-    echo \"When you have resolved this problem run \\\"$cmdline --resolved\\\".\"\n-    echo \"If you would prefer to skip this patch, instead run \\\"$cmdline --skip\\\".\"\n-\n-    stop_here $1\n+die_abort () {\n+\tcleanup\n+\tdie \"$1\"\n }\n \n-go_next () {\n-\trm -f \"$dotest/$msgnum\" \"$dotest/msg\" \"$dotest/msg-clean\" \\\n-\t\t\"$dotest/patch\" \"$dotest/info\"\n-\techo \"$next\" >\"$dotest/next\"\n-\tthis=$next\n-}\n+be_interactive () {\n+\tmsg=\"$GIT_DIR/sequencer/message\"\n+\tpatch=\"$GIT_DIR/sequencer/patch\"\n+\tauthor_script=\"$GIT_DIR/sequencer/author-script\"\n+\t# we rely on sequencer here\n+\n+\ttest -t 0 ||\n+\t\tdie \"cannot be interactive without stdin connected to a terminal.\"\n+\taction=$(cat \"$dotest/interactive\")\n+\twhile test \"$action\" = again\n+\tdo\n+\t\techo\n+\t\techo \"Commit Body is:\"\n+\t\techo \"--------------------------\"\n+\t\tcat \"$msg\"\n+\t\techo \"--------------------------\"\n+\t\tif test -z \"$1\"\n+\t\tthen\n+\t\t\tprintf \"Apply? [y]es/[n]o/[e]dit/[v]iew patch/[a]ccept all \"\n+\t\telse\n+\t\t\techo 'Patch does not apply cleanly!'\n+\t\t\tprintf \"Apply+fix? [y]es/[n]o/[e]dit/[v]iew patch/[a]ccept all \"\n+\t\tfi\n \n-cannot_fallback () {\n-\techo \"$1\"\n-\techo \"Cannot fall back to three-way merge.\"\n-\texit 1\n+\t\tread reply\n+\t\tcase \"$reply\" in\n+\t\t[yY]*)\n+\t\t\treturn 0\n+\t\t\t;;\n+\t\t[nN]*)\n+\t\t\tif test -z \"$1\"\n+\t\t\tthen\n+\t\t\t\tgit reset -q --hard HEAD^\n+\t\t\telse\n+\t\t\t\tgit reset -q --hard HEAD\n+\t\t\tfi\n+\t\t\treturn 1\n+\t\t\t;;\n+\t\t[eE]*)\n+\t\t\tgit_editor \"$msg\"\n+\t\t\tgit commit --amend --file=\"$msg\" --no-verify >/dev/null\n+\t\t\t;;\n+\t\t[vV]*)\n+\t\t\tLESS=-S ${PAGER:-less} \"$patch\"\n+\t\t\t;;\n+\t\t[aA]*)\n+\t\t\techo 'accept' >\"$dotest/interactive\"\n+\t\t\treturn 0\n+\t\t\t;;\n+\t\t*)\n+\t\t\t:\n+\t\t\t;;\n+\t\tesac\n+\tdone\n+\ttest \"$action\" = accept &&\n+\t\tsed -n -e '1s/^/Applying &/p' <\"$msg\"\n+\treturn 0\n }\n \n-fall_back_3way () {\n-    O_OBJECT=`cd \"$GIT_OBJECT_DIRECTORY\" && pwd`\n-\n-    rm -fr \"$dotest\"/patch-merge-*\n-    mkdir \"$dotest/patch-merge-tmp-dir\"\n-\n-    # First see if the patch records the index info that we can use.\n-    git apply --build-fake-ancestor \"$dotest/patch-merge-tmp-index\" \\\n-\t\"$dotest/patch\" &&\n-    GIT_INDEX_FILE=\"$dotest/patch-merge-tmp-index\" \\\n-    git write-tree >\"$dotest/patch-merge-base+\" ||\n-    cannot_fallback \"Repository lacks necessary blobs to fall back on 3-way merge.\"\n-\n-    echo Using index info to reconstruct a base tree...\n-    if GIT_INDEX_FILE=\"$dotest/patch-merge-tmp-index\" \\\n-\tgit apply $binary --cached <\"$dotest/patch\"\n-    then\n-\tmv \"$dotest/patch-merge-base+\" \"$dotest/patch-merge-base\"\n-\tmv \"$dotest/patch-merge-tmp-index\" \"$dotest/patch-merge-index\"\n-    else\n-        cannot_fallback \"Did you hand edit your patch?\n-It does not apply to blobs recorded in its index.\"\n-    fi\n-\n-    test -f \"$dotest/patch-merge-index\" &&\n-    his_tree=$(GIT_INDEX_FILE=\"$dotest/patch-merge-index\" git write-tree) &&\n-    orig_tree=$(cat \"$dotest/patch-merge-base\") &&\n-    rm -fr \"$dotest\"/patch-merge-* || exit 1\n-\n-    echo Falling back to patching base and 3-way merge...\n+print_continue_info () {\n+\techo 'When you have resolved this problem run \"git am --resolved\".'\n+\techo 'If you would prefer to skip this patch, instead run \"git am --skip\".'\n+}\n \n-    # This is not so wrong.  Depending on which base we picked,\n-    # orig_tree may be wildly different from ours, but his_tree\n-    # has the same set of wildly different changes in parts the\n-    # patch did not touch, so recursive ends up canceling them,\n-    # saying that we reverted all those changes.\n+run_sequencer () {\n+\tgit sequencer $noadvice --caller='git am||--resolved|--skip' \"$@\"\n+\tcase \"$?\" in\n+\t0)\n+\t\tcleanup\n+\t\texit 0\n+\t\t;;\n+\t2|3)\n+\t\tret=$?\n+\t\tprint_continue_info\n+\t\texit $(($ret-2))\n+\t\t;;\n+\t*)\n+\t\tdie_abort 'git-sequencer died unexpected. Aborting.'\n+\t\t;;\n+\tesac\n+}\n \n-    eval GITHEAD_$his_tree='\"$FIRSTLINE\"'\n-    export GITHEAD_$his_tree\n-    git-merge-recursive $orig_tree -- HEAD $his_tree || {\n-\t    git rerere\n-\t    echo Failed to merge in the changes.\n-\t    exit 1\n-    }\n-    unset GITHEAD_$his_tree\n+run_sequencer_i () {\n+\tcommand=\"$1\"\n+\twhile true\n+\tdo\n+\t\toutput=$(git sequencer $noadvice \\\n+\t\t\t--caller='git am -i||--resolved|--skip' \\\n+\t\t\t$command 2>&1 >/dev/null)\n+\t\tnoadvice=\n+\t\tcase \"$?\" in\n+\t\t0)\n+\t\t\tcleanup\n+\t\t\texit 0\n+\t\t\t;;\n+\t\t2)\n+\t\t\tbe_interactive\n+\t\t\t;;\n+\t\t3)\n+\t\t\tbe_interactive conflict\n+\t\t\tif test $? -eq 0\n+\t\t\tthen\n+\t\t\t\tprintf '%s\\n' \"$output\" 1>&2\n+\t\t\t\tprint_continue_info\n+\t\t\t\texit 1\n+\t\t\tfi\n+\t\t\t;;\n+\t\t*)\n+\t\t\tdie_abort \"$output\"\n+\t\t\t;;\n+\t\tesac\n+\t\tcommand=--continue\n+\tdone\n }\n \n prec=4\n dotest=\"$GIT_DIR/rebase\"\n+todofile=\"$dotest/todo\"\n sign= utf8=t keep= skip= interactive= resolved= binary= rebasing=\n-resolvemsg= resume=\n-git_apply_opt=\n+resolvemsg=\n+opts=\n \n while test $# != 0\n do\n \tcase \"$1\" in\n \t-i|--interactive)\n-\t\tinteractive=t ;;\n+\t\tinteractive=_i ;;\n \t-b|--binary)\n \t\tbinary=t ;;\n \t-3|--3way)\n@@ -153,9 +194,9 @@ do\n \t--resolvemsg)\n \t\tshift; resolvemsg=$1 ;;\n \t--whitespace)\n-\t\tgit_apply_opt=\"$git_apply_opt $1=$2\"; shift ;;\n+\t\topts=\"$opts $1=$2\"; shift ;;\n \t-C|-p)\n-\t\tgit_apply_opt=\"$git_apply_opt $1$2\"; shift ;;\n+\t\topts=\"$opts $1$2\"; shift ;;\n \t--)\n \t\tshift; break ;;\n \t*)\n@@ -164,348 +205,117 @@ do\n \tshift\n done\n \n-# If the dotest directory exists, but we have finished applying all the\n-# patches in them, clear it out.\n-if test -d \"$dotest\" &&\n-   last=$(cat \"$dotest/last\") &&\n-   next=$(cat \"$dotest/next\") &&\n-   test $# != 0 &&\n-   test \"$next\" -gt \"$last\"\n-then\n-   rm -fr \"$dotest\"\n-fi\n-\n if test -d \"$dotest\"\n then\n-\tcase \"$#,$skip$resolved\" in\n-\t0,*t*)\n-\t\t# Explicit resume command and we do not have file, so\n-\t\t# we are happy.\n-\t\t: ;;\n-\t0,)\n-\t\t# No file input but without resume parameters; catch\n-\t\t# user error to feed us a patch from standard input\n-\t\t# when there is already $dotest.  This is somewhat\n-\t\t# unreliable -- stdin could be /dev/null for example\n-\t\t# and the caller did not intend to feed us a patch but\n-\t\t# wanted to continue unattended.\n-\t\ttty -s\n-\t\t;;\n-\t*)\n-\t\tfalse\n-\t\t;;\n-\tesac ||\n-\tdie \"previous rebase directory $dotest still exists but mbox given.\"\n-\tresume=yes\n-else\n-\t# Make sure we are not given --skip nor --resolved\n-\ttest \",$skip,$resolved,\" = ,,, ||\n-\t\tdie \"Resolve operation not in progress, we are not resuming.\"\n+\ttest \"$#\" != 0 &&\n+\t\tdie \"previous rebase directory $dotest still exists but mbox given.\"\n+\n+\ttest -f \"$dotest/interactive\" &&\n+\t\tinteractive=_i action=$(cat \"$dotest/interactive\")\n \n-\t# Start afresh.\n-\tmkdir -p \"$dotest\" || exit\n+\t# No file input but without resume parameters; catch\n+\t# user error to feed us a patch from standard input\n+\t# when there is already $dotest.  This is somewhat\n+\t# unreliable -- stdin could be /dev/null for example\n+\t# and the caller did not intend to feed us a patch but\n+\t# wanted to continue unattended.\n+\ttest -z \"$resolved$skip\" && tty -s\n \n-\tif test -n \"$prefix\" && test $# != 0\n-\tthen\n-\t\tfirst=t\n-\t\tfor arg\n-\t\tdo\n-\t\t\ttest -n \"$first\" && {\n-\t\t\t\tset x\n-\t\t\t\tfirst=\n-\t\t\t}\n-\t\t\tcase \"$arg\" in\n-\t\t\t/*)\n-\t\t\t\tset \"$@\" \"$arg\" ;;\n-\t\t\t*)\n-\t\t\t\tset \"$@\" \"$prefix$arg\" ;;\n-\t\t\tesac\n-\t\tdone\n-\t\tshift\n-\tfi\n-\tgit mailsplit -d\"$prec\" -o\"$dotest\" -b -- \"$@\" > \"$dotest/last\" ||  {\n-\t\trm -fr \"$dotest\"\n-\t\texit 1\n-\t}\n+\ttest -n \"$resolved\" && run_sequencer$interactive --continue\n+\ttest -n \"$skip\" && run_sequencer$interactive --skip\n \n-\t# -b, -s, -u, -k and --whitespace flags are kept for the\n-\t# resuming session after a patch failure.\n-\t# -3 and -i can and must be given when resuming.\n-\techo \"$binary\" >\"$dotest/binary\"\n-\techo \" $ws\" >\"$dotest/whitespace\"\n-\techo \"$sign\" >\"$dotest/sign\"\n-\techo \"$utf8\" >\"$dotest/utf8\"\n-\techo \"$keep\" >\"$dotest/keep\"\n-\techo 1 >\"$dotest/next\"\n-\tif test -n \"$rebasing\"\n-\tthen\n-\t\t: >\"$dotest/rebasing\"\n-\telse\n-\t\t: >\"$dotest/applying\"\n-\t\tgit update-ref ORIG_HEAD HEAD\n-\tfi\n+\tdie \"$dotest still exists. Use git am --skip/--resolved.\"\n fi\n \n-case \"$resolved\" in\n-'')\n-\tfiles=$(git diff-index --cached --name-only HEAD --) || exit\n-\tif [ \"$files\" ]; then\n-\t   echo \"Dirty index: cannot apply patches (dirty: $files)\" >&2\n-\t   exit 1\n-\tfi\n-esac\n+# Make sure we are not given --skip nor --resolved\n+test -z \"$resolved$skip\" ||\n+\tdie 'git-am is not in progress. You cannot use --skip/--resolved then.'\n \n-if test \"$(cat \"$dotest/binary\")\" = t\n-then\n-\tbinary=--allow-binary-replacement\n-fi\n-if test \"$(cat \"$dotest/utf8\")\" = t\n-then\n-\tutf8=-u\n-else\n-\tutf8=-n\n-fi\n-if test \"$(cat \"$dotest/keep\")\" = t\n-then\n-\tkeep=-k\n-fi\n-ws=`cat \"$dotest/whitespace\"`\n-if test \"$(cat \"$dotest/sign\")\" = t\n+# sequencer running?\n+git sequencer --status >/dev/null 2>&1 &&\n+\tdie \"Sequencer already started. Cannot run git-am.\"\n+\n+# Start afresh.\n+mkdir -p \"$dotest\" ||\n+\tdie \"Could not create $dotest directory.\"\n+\n+if test -n \"$prefix\" && test $# != 0\n then\n-\tSIGNOFF=`git-var GIT_COMMITTER_IDENT | sed -e '\n-\t\t\ts/>.*/>/\n-\t\t\ts/^/Signed-off-by: /'\n-\t\t`\n-else\n-\tSIGNOFF=\n+\tfirst=t\n+\tfor arg\n+\tdo\n+\t\ttest -n \"$first\" && {\n+\t\t\tset x\n+\t\t\tfirst=\n+\t\t}\n+\t\tcase \"$arg\" in\n+\t\t/*)\n+\t\t\tset \"$@\" \"$arg\" ;;\n+\t\t*)\n+\t\t\tset \"$@\" \"$prefix$arg\" ;;\n+\t\tesac\n+\tdone\n+\tshift\n fi\n+last=$(git mailsplit -d\"$prec\" -o\"$dotest\" -b -- \"$@\") ||  {\n+\tcleanup\n+\texit 1\n+}\n+this=1\n \n-last=`cat \"$dotest/last\"`\n-this=`cat \"$dotest/next\"`\n-if test \"$skip\" = t\n-then\n-\tgit rerere clear\n-\tthis=`expr \"$this\" + 1`\n-\tresume=\n+files=$(git diff-index --cached --name-only HEAD --) || exit\n+if [ \"$files\" ]; then\n+\techo \"Dirty index: cannot apply patches (dirty: $files)\" >&2\n+\texit 1\n fi\n \n-if test \"$this\" -gt \"$last\"\n+test -n \"$interactive\" && echo 'again' >\"$dotest/interactive\"\n+\n+# converting our options to git-sequencer file insn options\n+test -n \"$binary\" && opts=\"$opts --binary\"\n+test -n \"$utf8\" || opts=\"$opts -n\"\n+test -n \"$keep\" && opts=\"$opts -k\"\n+test -n \"$sign\" && opts=\"$opts --signoff\"\n+test -n \"$threeway\" && opts=\"$opts -3\"\n+\n+# these files are created for tab completion scripts\n+if test -n \"$rebasing\"\n then\n-\techo Nothing to do.\n-\trm -fr \"$dotest\"\n-\texit\n+\t: >\"$dotest/rebasing\"\n+else\n+\t: >\"$dotest/applying\"\n+\tgit update-ref ORIG_HEAD HEAD\n fi\n \n+# create todofile\n+: > \"$todofile\" ||\n+\tdie_abort \"Cannot create $todofile\"\n while test \"$this\" -le \"$last\"\n do\n-\tmsgnum=`printf \"%0${prec}d\" $this`\n-\tnext=`expr \"$this\" + 1`\n-\ttest -f \"$dotest/$msgnum\" || {\n-\t\tresume=\n-\t\tgo_next\n-\t\tcontinue\n-\t}\n-\n-\t# If we are not resuming, parse and extract the patch information\n-\t# into separate files:\n-\t#  - info records the authorship and title\n-\t#  - msg is the rest of commit log message\n-\t#  - patch is the patch body.\n-\t#\n-\t# When we are resuming, these files are either already prepared\n-\t# by the user, or the user can tell us to do so by --resolved flag.\n-\tcase \"$resume\" in\n-\t'')\n-\t\tgit mailinfo $keep $utf8 \"$dotest/msg\" \"$dotest/patch\" \\\n-\t\t\t<\"$dotest/$msgnum\" >\"$dotest/info\" ||\n-\t\t\tstop_here $this\n-\n-\t\t# skip pine's internal folder data\n-\t\tgrep '^Author: Mail System Internal Data$' \\\n-\t\t\t<\"$dotest\"/info >/dev/null &&\n-\t\t\tgo_next && continue\n-\n-\t\ttest -s \"$dotest/patch\" || {\n-\t\t\techo \"Patch is empty.  Was it split wrong?\"\n-\t\t\tstop_here $this\n-\t\t}\n-\t\tif test -f \"$dotest/rebasing\" &&\n-\t\t\tcommit=$(sed -e 's/^From \\([0-9a-f]*\\) .*/\\1/' \\\n-\t\t\t\t-e q \"$dotest/$msgnum\") &&\n-\t\t\ttest \"$(git cat-file -t \"$commit\")\" = commit\n-\t\tthen\n-\t\t\tgit cat-file commit \"$commit\" |\n-\t\t\tsed -e '1,/^$/d' >\"$dotest/msg-clean\"\n-\t\telse\n-\t\t\tSUBJECT=\"$(sed -n '/^Subject/ s/Subject: //p' \"$dotest/info\")\"\n-\t\t\tcase \"$keep_subject\" in -k)  SUBJECT=\"[PATCH] $SUBJECT\" ;; esac\n-\n-\t\t\t(printf '%s\\n\\n' \"$SUBJECT\"; cat \"$dotest/msg\") |\n-\t\t\t\tgit stripspace > \"$dotest/msg-clean\"\n-\t\tfi\n-\t\t;;\n-\tesac\n-\n-\tGIT_AUTHOR_NAME=\"$(sed -n '/^Author/ s/Author: //p' \"$dotest/info\")\"\n-\tGIT_AUTHOR_EMAIL=\"$(sed -n '/^Email/ s/Email: //p' \"$dotest/info\")\"\n-\tGIT_AUTHOR_DATE=\"$(sed -n '/^Date/ s/Date: //p' \"$dotest/info\")\"\n+\tmsgnum=$(printf \"%0${prec}d\" $this)\n+\tthis=$(($this+1))\n \n-\tif test -z \"$GIT_AUTHOR_EMAIL\"\n-\tthen\n-\t\techo \"Patch does not have a valid e-mail address.\"\n-\t\tstop_here $this\n-\tfi\n-\n-\texport GIT_AUTHOR_NAME GIT_AUTHOR_EMAIL GIT_AUTHOR_DATE\n-\n-\tcase \"$resume\" in\n-\t'')\n-\t    if test '' != \"$SIGNOFF\"\n-\t    then\n-\t\tLAST_SIGNED_OFF_BY=`\n-\t\t    sed -ne '/^Signed-off-by: /p' \\\n-\t\t    \"$dotest/msg-clean\" |\n-\t\t    sed -ne '$p'\n-\t\t`\n-\t\tADD_SIGNOFF=`\n-\t\t    test \"$LAST_SIGNED_OFF_BY\" = \"$SIGNOFF\" || {\n-\t\t    test '' = \"$LAST_SIGNED_OFF_BY\" && echo\n-\t\t    echo \"$SIGNOFF\"\n-\t\t}`\n-\t    else\n-\t\tADD_SIGNOFF=\n-\t    fi\n-\t    {\n-\t\tif test -s \"$dotest/msg-clean\"\n-\t\tthen\n-\t\t\tcat \"$dotest/msg-clean\"\n-\t\tfi\n-\t\tif test '' != \"$ADD_SIGNOFF\"\n-\t\tthen\n-\t\t\techo \"$ADD_SIGNOFF\"\n-\t\tfi\n-\t    } >\"$dotest/final-commit\"\n-\t    ;;\n-\t*)\n-\t\tcase \"$resolved$interactive\" in\n-\t\ttt)\n-\t\t\t# This is used only for interactive view option.\n-\t\t\tgit diff-index -p --cached HEAD -- >\"$dotest/patch\"\n-\t\t\t;;\n-\t\tesac\n-\tesac\n-\n-\tresume=\n-\tif test \"$interactive\" = t\n-\tthen\n-\t    test -t 0 ||\n-\t    die \"cannot be interactive without stdin connected to a terminal.\"\n-\t    action=again\n-\t    while test \"$action\" = again\n-\t    do\n-\t\techo \"Commit Body is:\"\n-\t\techo \"--------------------------\"\n-\t\tcat \"$dotest/final-commit\"\n-\t\techo \"--------------------------\"\n-\t\tprintf \"Apply? [y]es/[n]o/[e]dit/[v]iew patch/[a]ccept all \"\n-\t\tread reply\n-\t\tcase \"$reply\" in\n-\t\t[yY]*) action=yes ;;\n-\t\t[aA]*) action=yes interactive= ;;\n-\t\t[nN]*) action=skip ;;\n-\t\t[eE]*) git_editor \"$dotest/final-commit\"\n-\t\t       action=again ;;\n-\t\t[vV]*) action=again\n-\t\t       LESS=-S ${PAGER:-less} \"$dotest/patch\" ;;\n-\t\t*)     action=again ;;\n-\t\tesac\n-\t    done\n-\telse\n-\t    action=yes\n-\tfi\n-\tFIRSTLINE=$(sed 1q \"$dotest/final-commit\")\n-\n-\tif test $action = skip\n-\tthen\n-\t\tgo_next\n+\t# This ignores every mail that does not contain a patch.\n+\tgrep '^diff' \"$dotest/$msgnum\" >/dev/null ||\n \t\tcontinue\n-\tfi\n \n-\tif test -x \"$GIT_DIR\"/hooks/applypatch-msg\n-\tthen\n-\t\t\"$GIT_DIR\"/hooks/applypatch-msg \"$dotest/final-commit\" ||\n-\t\tstop_here $this\n-\tfi\n-\n-\tprintf 'Applying %s\\n' \"$FIRSTLINE\"\n-\n-\tcase \"$resolved\" in\n-\t'')\n-\t\tgit apply $git_apply_opt $binary --index \"$dotest/patch\"\n-\t\tapply_status=$?\n-\t\t;;\n-\tt)\n-\t\t# Resolved means the user did all the hard work, and\n-\t\t# we do not have to do any patch application.  Just\n-\t\t# trust what the user has in the index file and the\n-\t\t# working tree.\n-\t\tresolved=\n-\t\tgit diff-index --quiet --cached HEAD -- && {\n-\t\t\techo \"No changes - did you forget to use 'git add'?\"\n-\t\t\tstop_here_user_resolve $this\n-\t\t}\n-\t\tunmerged=$(git ls-files -u)\n-\t\tif test -n \"$unmerged\"\n-\t\tthen\n-\t\t\techo \"You still have unmerged paths in your index\"\n-\t\t\techo \"did you forget to use 'git add'?\"\n-\t\t\tstop_here_user_resolve $this\n-\t\tfi\n-\t\tapply_status=0\n-\t\tgit rerere\n-\t\t;;\n-\tesac\n-\n-\tif test $apply_status = 1 && test \"$threeway\" = t\n-\tthen\n-\t\tif (fall_back_3way)\n-\t\tthen\n-\t\t    # Applying the patch to an earlier tree and merging the\n-\t\t    # result may have produced the same tree as ours.\n-\t\t    git diff-index --quiet --cached HEAD -- && {\n-\t\t\techo No changes -- Patch already applied.\n-\t\t\tgo_next\n-\t\t\tcontinue\n-\t\t    }\n-\t\t    # clear apply_status -- we have successfully merged.\n-\t\t    apply_status=0\n-\t\tfi\n-\tfi\n-\tif test $apply_status != 0\n-\tthen\n-\t\techo Patch failed at $msgnum.\n-\t\tstop_here_user_resolve $this\n-\tfi\n-\n-\tif test -x \"$GIT_DIR\"/hooks/pre-applypatch\n-\tthen\n-\t\t\"$GIT_DIR\"/hooks/pre-applypatch || stop_here $this\n-\tfi\n-\n-\ttree=$(git write-tree) &&\n-\tparent=$(git rev-parse --verify HEAD) &&\n-\tcommit=$(git commit-tree $tree -p $parent <\"$dotest/final-commit\") &&\n-\tgit update-ref -m \"$GIT_REFLOG_ACTION: $FIRSTLINE\" HEAD $commit $parent ||\n-\tstop_here $this\n-\n-\tif test -x \"$GIT_DIR\"/hooks/post-applypatch\n-\tthen\n-\t\t\"$GIT_DIR\"/hooks/post-applypatch\n-\tfi\n-\n-\tgo_next\n+\textra=\n+\ttest -n \"$rebasing\" &&\n+\t\tcommit=$(sed -e 's/^From \\([0-9a-f]*\\) .*/\\1/' \\\n+\t\t\t-e q \"$dotest/$msgnum\") &&\n+\t\ttest \"$(git cat-file -t \"$commit\")\" = commit &&\n+\t\textra=\" -C $commit\"\n+\n+\tsubject=$(sed -n '1,/^Subject:/s/Subject: *\\(\\[.*\\]\\)\\{0,1\\} *//p' \\\n+\t\t<\"$dotest/$msgnum\")\n+\ttest -n \"$interactive\" ||\n+\t\tprintf 'run -- printf '\\''Applying \"%%s\"\\\\n'\\'' '\\''%s'\\''\\n' \\\n+\t\t\t\"$(printf '%s\\n' \"$subject\" |\n+\t\t\t\tsed \"s/'/'\\\\\\\\''/g\")\" >>\"$todofile\"\n+\tprintf 'patch%s%s \"%s\" # %s\\n' \"$opts\" \"$extra\" \"$dotest/$msgnum\" \\\n+\t\t\"$subject\" >>\"$todofile\"\n+\ttest -z \"$interactive\" || echo 'pause' >>\"$todofile\"\n done\n \n-git gc --auto\n-\n-rm -fr \"$dotest\"\n+noadvice=--no-advice\n+run_sequencer$interactive \"$todofile\"\ndiff --git a/git-rebase.sh b/git-rebase.sh\nindex 56cf6f0..231c486 100755\n--- a/git-rebase.sh\n+++ b/git-rebase.sh\n@@ -220,6 +220,7 @@ do\n \t\t\tdotest=\"$GIT_DIR\"/rebase\n \t\t\tmove_to_original_branch\n \t\tfi\n+\t\trm -rf \"$GIT_DIR/sequencer\"\n \t\tgit reset --hard $(cat \"$dotest/orig-head\")\n \t\trm -r \"$dotest\"\n \t\texit\ndiff --git a/t/t4150-am.sh b/t/t4150-am.sh\nindex 5cbd5ef..e771806 100755\n--- a/t/t4150-am.sh\n+++ b/t/t4150-am.sh\n@@ -212,14 +212,12 @@ test_expect_success 'am takes patches from a Pine mailbox' '\n '\n \n test_expect_success 'am fails on mail without patch' '\n-\t! git am <failmail &&\n-\trm -r .git/rebase/\n+\ttest_must_fail git am <failmail\n '\n \n test_expect_success 'am fails on empty patch' '\n \techo \"---\" >>failmail &&\n-\t! git am <failmail &&\n-\tgit am --skip &&\n+\ttest_must_fail git am <failmail &&\n \t! test -d .git/rebase\n '\n \n-- \n1.5.6.3.391.ge45b\n"},{"id":"83587","messageId":"9915f89fa819f7cd59de9913e08d831a37bbf418.1216233919.git.s-beyer@gmx.net","threadId":"14495","inReplyTo":"5f60ea3acffdb5dfdbe0ea6e81133efadab9f20d.1216233919.git.s-beyer@gmx.net","subject":"[PATCH 2/2] Introduce git am --abort","fromName":"Stephan Beyer","fromEmail":"s-beyer@gmx.net","sentAt":"2008-07-16T20:45:21Z","receivedAt":"2008-07-16T20:45:21Z","isPatch":true,"sender":{"key":"s-beyer@gmx.net","avatar":"https://avatars.githubusercontent.com/u/143889?v=4"},"body":"Currently, aborting a git-am process during a conflict is done by\nresetting to the HEAD before applying the patches and removing the\n.git/rebase directory manually.\n\nThis patch introduces an --abort option for git-am to make this as\neasy as in git-rebase.\n\nMentored-by: Christian Couder <chriscool@tuxfamily.org>\nMentored-by: Daniel Barkalow <barkalow@iabervon.org>\nSigned-off-by: Stephan Beyer <s-beyer@gmx.net>\n---\n Documentation/git-am.txt               |    5 ++++-\n Documentation/git-rerere.txt           |    2 +-\n contrib/completion/git-completion.bash |    2 +-\n git-am.sh                              |   19 ++++++++++++-------\n git-rebase.sh                          |    8 +++-----\n t/t4150-am.sh                          |   21 +++++++++++++++++----\n 6 files changed, 38 insertions(+), 19 deletions(-)\n\ndiff --git a/Documentation/git-am.txt b/Documentation/git-am.txt\nindex 2d7f162..df35cee 100644\n--- a/Documentation/git-am.txt\n+++ b/Documentation/git-am.txt\n@@ -13,7 +13,7 @@ SYNOPSIS\n          [--3way] [--interactive] [--binary]\n          [--whitespace=<option>] [-C<n>] [-p<n>]\n \t [<mbox> | <Maildir>...]\n-'git am' (--skip | --resolved)\n+'git am' (--abort | --skip | --resolved)\n \n DESCRIPTION\n -----------\n@@ -79,6 +79,9 @@ default.   You could use `--no-utf8` to override this.\n --interactive::\n \tRun interactively.\n \n+--abort::\n+\tAbort applying and rewind applied patches.\n+\n --skip::\n \tSkip the current patch.  This is only meaningful when\n \trestarting an aborted patch.\ndiff --git a/Documentation/git-rerere.txt b/Documentation/git-rerere.txt\nindex 678bfd3..ad81dbc 100644\n--- a/Documentation/git-rerere.txt\n+++ b/Documentation/git-rerere.txt\n@@ -37,7 +37,7 @@ its working state.\n 'clear'::\n \n This resets the metadata used by rerere if a merge resolution is to be\n-is aborted.  Calling 'git-am --skip' or 'git-rebase [--skip|--abort]'\n+is aborted.  Calling 'git-am [--skip|--abort]' or 'git-rebase [--skip|--abort]'\n will automatically invoke this command.\n \n 'diff'::\ndiff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash\nindex 29f6cd4..d271ba0 100755\n--- a/contrib/completion/git-completion.bash\n+++ b/contrib/completion/git-completion.bash\n@@ -489,7 +489,7 @@ _git_am ()\n {\n \tlocal cur=\"${COMP_WORDS[COMP_CWORD]}\" dir=\"$(__gitdir)\"\n \tif [ -d \"$dir\"/rebase ]; then\n-\t\t__gitcomp \"--skip --resolved\"\n+\t\t__gitcomp \"--skip --resolved --abort\"\n \t\treturn\n \tfi\n \tcase \"$cur\" in\ndiff --git a/git-am.sh b/git-am.sh\nindex e36f22c..7301314 100755\n--- a/git-am.sh\n+++ b/git-am.sh\n@@ -8,6 +8,7 @@ OPTIONS_SPEC=\"\\\n git-am [options] [<mbox>|<Maildir>...]\n git-am [options] --resolved\n git-am [options] --skip\n+git-am [options] --abort\n --\n d,dotest=       (removed -- do not use)\n i,interactive   run interactively\n@@ -22,6 +23,7 @@ p=              pass it through git-apply\n resolvemsg=     override error message when patch failure occurs\n r,resolved      to be used after a patch failure\n skip            skip the current patch\n+abort           abort patching and reset done patches\n rebasing        (internal use for git-rebase)\"\n \n . git-sh-setup\n@@ -108,7 +110,7 @@ print_continue_info () {\n }\n \n run_sequencer () {\n-\tgit sequencer $noadvice --caller='git am||--resolved|--skip' \"$@\"\n+\tgit sequencer $noadvice --caller='git am|--abort|--resolved|--skip' \"$@\"\n \tcase \"$?\" in\n \t0)\n \t\tcleanup\n@@ -130,7 +132,7 @@ run_sequencer_i () {\n \twhile true\n \tdo\n \t\toutput=$(git sequencer $noadvice \\\n-\t\t\t--caller='git am -i||--resolved|--skip' \\\n+\t\t\t--caller='git am -i|--abort|--resolved|--skip' \\\n \t\t\t$command 2>&1 >/dev/null)\n \t\tnoadvice=\n \t\tcase \"$?\" in\n@@ -170,6 +172,8 @@ do\n \tcase \"$1\" in\n \t-i|--interactive)\n \t\tinteractive=_i ;;\n+\t--abort)\n+\t\tabort=t ;;\n \t-b|--binary)\n \t\tbinary=t ;;\n \t-3|--3way)\n@@ -219,17 +223,18 @@ then\n \t# unreliable -- stdin could be /dev/null for example\n \t# and the caller did not intend to feed us a patch but\n \t# wanted to continue unattended.\n-\ttest -z \"$resolved$skip\" && tty -s\n+\ttest -z \"$abort$resolved$skip\" && tty -s\n \n+\ttest -n \"$abort\" && run_sequencer$interactive --abort\n \ttest -n \"$resolved\" && run_sequencer$interactive --continue\n \ttest -n \"$skip\" && run_sequencer$interactive --skip\n \n-\tdie \"$dotest still exists. Use git am --skip/--resolved.\"\n+\tdie \"$dotest still exists. Use git am --abort/--skip/--resolved.\"\n fi\n \n-# Make sure we are not given --skip nor --resolved\n-test -z \"$resolved$skip\" ||\n-\tdie 'git-am is not in progress. You cannot use --skip/--resolved then.'\n+# Make sure we are not given --skip nor --resolved nor --abort\n+test -z \"$abort$resolved$skip\" ||\n+\tdie 'git-am is not in progress. You cannot use --abort/--skip/--resolved then.'\n \n # sequencer running?\n git sequencer --status >/dev/null 2>&1 &&\ndiff --git a/git-rebase.sh b/git-rebase.sh\nindex 231c486..a83933b 100755\n--- a/git-rebase.sh\n+++ b/git-rebase.sh\n@@ -216,13 +216,11 @@ do\n \t\tif test -d \"$dotest\"\n \t\tthen\n \t\t\tmove_to_original_branch\n+\t\t\tgit reset --hard $(cat \"$dotest/orig-head\")\n+\t\t\trm -r \"$dotest\"\n \t\telse\n-\t\t\tdotest=\"$GIT_DIR\"/rebase\n-\t\t\tmove_to_original_branch\n+\t\t\tgit am --abort\n \t\tfi\n-\t\trm -rf \"$GIT_DIR/sequencer\"\n-\t\tgit reset --hard $(cat \"$dotest/orig-head\")\n-\t\trm -r \"$dotest\"\n \t\texit\n \t\t;;\n \t--onto)\ndiff --git a/t/t4150-am.sh b/t/t4150-am.sh\nindex e771806..152e2d9 100755\n--- a/t/t4150-am.sh\n+++ b/t/t4150-am.sh\n@@ -83,6 +83,10 @@ test_expect_success setup '\n \tgit commit -m third &&\n \tgit format-patch --stdout first >patch2\t&&\n \tgit checkout -b lorem &&\n+\techo new >another &&\n+\tgit add another &&\n+\ttest_tick &&\n+\tgit commit -m \"added another file\" &&\n \tsed -n -e \"11,\\$p\" msg >file &&\n \thead -n 9 msg >>file &&\n \ttest_tick &&\n@@ -181,8 +185,8 @@ test_expect_success 'am -3 falls back to 3-way merge' '\n '\n \n test_expect_success 'am pauses on conflict' '\n-\tgit checkout lorem2^^ &&\n-\t! git am lorem-move.patch &&\n+\tgit checkout lorem2~3 &&\n+\ttest_must_fail git am lorem-move.patch &&\n \ttest -d .git/rebase\n '\n \n@@ -193,9 +197,18 @@ test_expect_success 'am --skip works' '\n \ttest goodbye = \"$(cat another)\"\n '\n \n+test_expect_success 'am --abort works' '\n+\tgit checkout lorem2~3 &&\n+\ttest_must_fail git am lorem-move.patch &&\n+\ttest -d .git/rebase &&\n+\tgit am --abort &&\n+\ttest \"$(git rev-parse HEAD)\" = \"$(git rev-parse lorem2~3)\" &&\n+\t! test -f another\n+'\n+\n test_expect_success 'am --resolved works' '\n-\tgit checkout lorem2^^ &&\n-\t! git am lorem-move.patch &&\n+\tgit checkout lorem2~3 &&\n+\ttest_must_fail git am lorem-move.patch &&\n \ttest -d .git/rebase &&\n \techo resolved >>file &&\n \tgit add file &&\n-- \n1.5.6.3.391.g7ab7e\n"}]}