{"thread":{"id":"14685","subject":"git sequencer prototype","startedAt":"2008-07-26T05:20:39Z","lastAt":"2008-07-31T12:53:02Z","messageCount":20,"participants":["Stephan Beyer","Jakub Narebski","Sverre Rabbelier","Johannes Schindelin","Daniel Barkalow"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"85008","messageId":"1217049644-8874-1-git-send-email-s-beyer@gmx.net","threadId":"14685","inReplyTo":null,"subject":"git sequencer prototype","fromName":"Stephan Beyer","fromEmail":"s-beyer@gmx.net","sentAt":"2008-07-26T05:20:39Z","receivedAt":"2008-07-26T05:20:39Z","isPatch":false,"sender":{"key":"s-beyer@gmx.net","avatar":"https://avatars.githubusercontent.com/u/143889?v=4"},"body":"Hi,\n\nfor those who are interested in git-sequencer: here's the latest\nprototype, that should be able to apply to master.\n\nAn outline of the differences to the last sequencer prototype patchset:\n - typofixes, minor bugfixes\n - simplifications (seen due to builtin-ification)\n - introduced --allow-dirty\n   that is used by the git-am migration, to allow\n   usage of git-am on dirty index\n - set (\"keep\") ORIG_HEAD; somehow experimental\n\n\nIn the last patchset I mentioned the issue, that the prototype is slow\nas hell.  I know some bottlenecks, but I have not even tried to change\nthat, because this is no issue for the builtin.\n\nI paste the experiments that I did on my test machine some time ago:\n\ngit-am: Apply 100 (trivial) patches\n        original: 5.1s\n prototype-based: 17s  (wtf!)\n   builtin-based: 2.8s\n\ngit-rebase--interactive: Pick 100 (trivial) commits\n        original: 4.8s\n prototype-based: 10.1s\n   builtin-based: 1.7s\n\nThose times don't have any methodic value, it's just to get an impression.\nNevertheless some information about that:\n - performance was only tested one or two times\n - /proc/cpuinfo says my machine is an AMD 64 X2 with 4013 BogoMIPS\n - /bin/sh is dash (if the propaganda is true, bash is even slower)\n - the changes of the patches are equivalent to those of the commits\n\nRegards,\n  Stephan\n\n\nStephan Beyer (5):\n  Add git-sequencer shell prototype\n  Add git-sequencer documentation\n  Add git-sequencer test suite (t3350)\n  Migrate git-am to use git-sequencer\n  Migrate rebase-i to sequencer\n\n .gitignore                      |    1 +\n Documentation/git-sequencer.txt |  676 +++++++++++++\n Makefile                        |    1 +\n command-list.txt                |    1 +\n git-am.sh                       |  632 +++++--------\n git-rebase--interactive.sh      |  436 ++-------\n git-rebase.sh                   |    7 +-\n git-sequencer.sh                | 2042 +++++++++++++++++++++++++++++++++++++++\n t/t3350-sequencer.sh            |  838 ++++++++++++++++\n t/t3404-rebase-interactive.sh   |    8 +-\n t/t4150-am.sh                   |    4 +-\n 11 files changed, 3889 insertions(+), 757 deletions(-)\n create mode 100644 Documentation/git-sequencer.txt\n create mode 100755 git-sequencer.sh\n create mode 100755 t/t3350-sequencer.sh\n"},{"id":"85011","messageId":"1217049644-8874-2-git-send-email-s-beyer@gmx.net","threadId":"14685","inReplyTo":"1217049644-8874-1-git-send-email-s-beyer@gmx.net","subject":"[PATCH 1/5] Add git-sequencer shell prototype","fromName":"Stephan Beyer","fromEmail":"s-beyer@gmx.net","sentAt":"2008-07-26T05:20:40Z","receivedAt":"2008-07-26T05:20:40Z","isPatch":true,"sender":{"key":"s-beyer@gmx.net","avatar":"https://avatars.githubusercontent.com/u/143889?v=4"},"body":"git-sequencer is planned as a backend for user scripts\nthat execute a sequence of git instructions and perhaps\nneed manual intervention, for example git-rebase or git-am.\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 .gitignore       |    1 +\n Makefile         |    1 +\n command-list.txt |    1 +\n git-sequencer.sh | 2042 ++++++++++++++++++++++++++++++++++++++++++++++++++++++\n 4 files changed, 2045 insertions(+), 0 deletions(-)\n create mode 100755 git-sequencer.sh\n\ndiff --git a/.gitignore b/.gitignore\nindex a213e8e..a617039 100644\n--- a/.gitignore\n+++ b/.gitignore\n@@ -110,6 +110,7 @@ git-revert\n git-rm\n git-send-email\n git-send-pack\n+git-sequencer\n git-sh-setup\n git-shell\n git-shortlog\ndiff --git a/Makefile b/Makefile\nindex b01cf1c..08facb1 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -248,6 +248,7 @@ SCRIPT_SH += git-rebase--interactive.sh\n SCRIPT_SH += git-rebase.sh\n SCRIPT_SH += git-repack.sh\n SCRIPT_SH += git-request-pull.sh\n+SCRIPT_SH += git-sequencer.sh\n SCRIPT_SH += git-sh-setup.sh\n SCRIPT_SH += git-stash.sh\n SCRIPT_SH += git-submodule.sh\ndiff --git a/command-list.txt b/command-list.txt\nindex 3583a33..44bb5b0 100644\n--- a/command-list.txt\n+++ b/command-list.txt\n@@ -101,6 +101,7 @@ git-rev-parse                           ancillaryinterrogators\n git-rm                                  mainporcelain common\n git-send-email                          foreignscminterface\n git-send-pack                           synchingrepositories\n+git-sequencer                           plumbingmanipulators\n git-shell                               synchelpers\n git-shortlog                            mainporcelain\n git-show                                mainporcelain common\ndiff --git a/git-sequencer.sh b/git-sequencer.sh\nnew file mode 100755\nindex 0000000..2c14af9\n--- /dev/null\n+++ b/git-sequencer.sh\n@@ -0,0 +1,2042 @@\n+#!/bin/sh\n+# A git sequencer prototype.\n+\n+SUBDIRECTORY_OK=Yes\n+OPTIONS_KEEPDASHDASH=\n+OPTIONS_SPEC=\"\\\n+git sequencer [options] [--] [<file>]\n+git sequencer (--continue | --abort | --skip | --edit | --status)\n+--\n+ Options to start a sequencing process\n+allow-dirty    run even if working tree is dirty\n+B,batch        run in batch-mode\n+onto=          checkout the given commit or branch first\n+no-advice      suppress advice when pausing (conflicts, etc)\n+q,quiet        suppress output\n+v,verbose      be more verbose\n+ Options to restart/change a sequencing process or show information\n+continue       continue paused sequencer process\n+abort          restore original branch and abort\n+skip           skip current patch and continue\n+status         show the status of the sequencing process\n+edit           invoke editor to let user edit the remaining insns\n+ Options to be used by user scripts\n+caller=        provide information string: name|abort|cont|skip\n+\"\n+\n+. git-sh-setup\n+require_work_tree\n+\n+git var GIT_COMMITTER_IDENT >/dev/null ||\n+\tdie 'You need to set your committer info first'\n+\n+SEQ_DIR=\"$GIT_DIR/sequencer\"\n+TODO=\"$SEQ_DIR/todo\"\n+DONE=\"$SEQ_DIR/done\"\n+MSG=\"$SEQ_DIR/message\"\n+PATCH=\"$SEQ_DIR/patch\"\n+AUTHOR_SCRIPT=\"$SEQ_DIR/author-script\"\n+ORIG_AUTHOR_SCRIPT=\"$SEQ_DIR/author-script.orig\"\n+CALLER_SCRIPT=\"$SEQ_DIR/caller-script\"\n+WHY_FILE=\"$SEQ_DIR/why\"\n+MARK_PREFIX='refs/sequencer-marks'\n+\n+warn () {\n+\tprintf \"%s\\n\" \"$*\" >&2\n+}\n+\n+cleanup () {\n+\tfor ref in $(git for-each-ref --format='%(refname)' \"$MARK_PREFIX\")\n+\tdo\n+\t\tgit update-ref -d \"$ref\" \"$ref\" || return\n+\tdone\n+\ttest -z \"$ORIG_HEAD\" || git update-ref ORIG_HEAD \"$ORIG_HEAD\"\n+\trm -rf \"$SEQ_DIR\"\n+}\n+\n+print_advice () {\n+\tcase \"$ADVICE,$WHY\" in\n+\tt,conflict)\n+\t\techo \"\n+After resolving the conflicts, mark the corrected paths with\n+\n+\tgit add <paths>\n+\n+and run\n+\n+\t$(print_caller --continue)\n+\n+Note, that your working tree must match the index.\"\n+\t\t;;\n+\tt,pause)\n+\t\techo \"\n+You can now edit files and add them to the index.\n+Once you are satisfied with your changes, run\n+\n+\t$(print_caller --continue)\n+\n+If you only want to change the commit message, run\n+git commit --amend before.\"\n+\t\t;;\n+\tt,run)\n+\t\techo \"\n+Running failed:\n+\t$@\n+\n+You can now fix the problem.  When manual runs pass,\n+add the changes to the index and invoke\n+\n+\t$(print_caller --continue)\"\n+\t\t;;\n+\tt,todo)\n+\t\techo \"\n+Fix with git sequencer --edit or abort with $(print_caller --abort).\"\n+\t\t;;\n+\tesac\n+}\n+\n+# Die if there has been a conflict\n+die_to_continue () {\n+\twarn \"$*\"\n+\ttest -z \"$BATCHMODE\" ||\n+\t\tdie_abort 'Aborting, because of batch mode.'\n+\ttest -n \"$WHY\" || WHY=conflict\n+\techo \"$WHY\" >\"$WHY_FILE\"\n+\tprint_advice\n+\ttest -z \"$ORIG_HEAD\" || git update-ref ORIG_HEAD \"$ORIG_HEAD\"\n+\texit 3\n+}\n+\n+die_abort () {\n+\trestore\n+\tcleanup\n+\tdie \"$1\"\n+}\n+\n+perform () {\n+\tcase \"$VERBOSE\" in\n+\t0)\n+\t\t\"$@\" >/dev/null\n+\t\t;;\n+\t1)\n+\t\toutput=$(\"$@\" 2>&1 )\n+\t\tstatus=$?\n+\t\ttest $status -ne 0 && printf '%s\\n' \"$output\"\n+\t\treturn $status\n+\t\t;;\n+\t2)\n+\t\t\"$@\"\n+\t\t;;\n+\tesac\n+}\n+\n+# test if working tree is dirty\n+require_clean_work_tree () {\n+\tif test -z \"$ALLOW_DIRTY\"\n+\tthen\n+\t\tgit rev-parse --verify HEAD >/dev/null &&\n+\t\tgit update-index --ignore-submodules --refresh &&\n+\t\tgit diff-files --quiet --ignore-submodules ||\n+\t\t\tdie 'Working tree is dirty.'\n+\tfi\n+\tgit diff-index --cached --quiet HEAD --ignore-submodules -- ||\n+\t\tdie 'Index is dirty'\n+}\n+\n+ORIG_REFLOG_ACTION=\"$GIT_REFLOG_ACTION\"\n+\n+comment_for_reflog () {\n+\tif test -z \"$ORIG_REFLOG_ACTION\"\n+\tthen\n+\t\tGIT_REFLOG_ACTION='sequencer'\n+\t\ttest -z \"$CALLER\" ||\n+\t\t\tGIT_REFLOG_ACTION=\"$GIT_REFLOG_ACTION ($CALLER)\"\n+\t\texport GIT_REFLOG_ACTION\n+\tfi\n+}\n+\n+# Get commit message from commit $1\n+commit_message () {\n+\tgit cat-file commit \"$1\" | sed -e '1,/^$/d'\n+}\n+\n+LAST_COUNT=\n+remove_from_todo () {\n+\tsed -e 1q <\"$TODO\" >>\"$DONE\"\n+\tsed -e 1d <\"$TODO\" >\"$TODO.new\"\n+\tmv -f \"$TODO.new\" \"$TODO\"\n+\ttodo_ack \"$TODO\"\n+\tif test \"$VERBOSE\" -gt 0\n+\tthen\n+\t\tcount=$(grep -c '^[^#]' <\"$DONE\")\n+\t\ttotal=$(expr \"$count\" + \"$(grep -c '^[^#]' <\"$TODO\")\")\n+\t\tif test \"$LAST_COUNT\" != \"$count\"\n+\t\tthen\n+\t\t\tLAST_COUNT=\"$count\"\n+\t\t\ttest \"$VERBOSE\" -eq 1 -a -t 1 -o \"$VERBOSE\" -gt 1 &&\n+\t\t\t\tprintf 'Sequencing (%d/%d)\\r' \"$count\" \"$total\"\n+\t\t\ttest \"$VERBOSE\" -lt 2 || echo\n+\t\tfi\n+\tfi\n+}\n+\n+# Generate message and author script files\n+save_commit_data () {\n+\ttest -f \"$MSG\" ||\n+\t\tcommit_message \"$1\" >\"$MSG\"\n+\ttest -f \"$AUTHOR_SCRIPT\" ||\n+\t\tget_author_ident_from_commit \"$1\" >\"$AUTHOR_SCRIPT\"\n+}\n+\n+# Generate a patch and die with \"conflict\" status code\n+die_with_patch () {\n+\tsave_commit_data \"$1\"\n+\tperform git rerere\n+\tdie_to_continue \"$2\"\n+}\n+\n+reset_almost_hard () {\n+\tperform git read-tree --reset -u $ALLOW_DIRTY \"$1\" &&\n+\tperform git reset \"$1\"\n+}\n+\n+restore () {\n+\t# XXX: We should undo all \"ref\" invocations, but that's left to be\n+\t# done in the builtin-sequencer.\n+\tread HEADNAME <\"$SEQ_DIR/head-name\"\n+\tcase $HEADNAME in\n+\trefs/*)\n+\t\tgit symbolic-ref HEAD \"$HEADNAME\"\n+\t\t;;\n+\tesac &&\n+\treset_almost_hard \"$ORIG_HEAD\"\n+}\n+\n+has_action () {\n+\tgrep '^[^#]' \"$1\" >/dev/null\n+}\n+\n+# Check if text file $1 contains a commit message\n+has_message () {\n+\ttest -n \"$(sed -n -e '/^Signed-off-by:/d;/^[^#]/p' <\"$1\")\"\n+}\n+\n+# Count parents of commit $1\n+count_parents() {\n+\tgit cat-file commit \"$1\" | sed -n -e '1,/^$/p' | grep -c '^parent'\n+}\n+\n+# Evaluate the author script to get author information to\n+# apply it with \"with_author git foo\" then.\n+get_current_author () {\n+\tif test -f \"$AUTHOR_SCRIPT\"\n+\tthen\n+\t\t. \"$AUTHOR_SCRIPT\"\n+\telse\n+\t\t. \"$ORIG_AUTHOR_SCRIPT\"\n+\tfi || die_abort 'Author script is damaged. This must not happen!'\n+}\n+\n+# Run command with author information\n+with_author () {\n+\tGIT_AUTHOR_NAME=\"$GIT_AUTHOR_NAME\" \\\n+\tGIT_AUTHOR_EMAIL=\"$GIT_AUTHOR_EMAIL\" \\\n+\tGIT_AUTHOR_DATE=\"$GIT_AUTHOR_DATE\" \\\n+\t\t\"$@\"\n+}\n+\n+# clean WHY_FILE and reset WHY\n+clean_why () {\n+\trm -f \"$WHY_FILE\"\n+\tWHY=\n+}\n+\n+# Usage: pick_one (cherry-pick|revert) [-*|--edit] sha1\n+pick_one () {\n+\twhat=\"$1\"\n+\tshift\n+\n+\tcase \"$what,$1\" in\n+\trevert,*)\n+\t\ttest \"$1\" != '--edit' &&\n+\t\t\twhat='revert --no-edit'\n+\t\t;;\n+\tcherry-pick,-*)\n+\t\t;;\n+\tcherry-pick,*)\n+\t\t# fast forward\n+\t\tif test \"$(git rev-parse --verify \"$1^\" 2>/dev/null)\" = \\\n+\t\t\t\"$(git rev-parse --verify HEAD)\"\n+\t\tthen\n+\t\t\treset_almost_hard \"$1\"\n+\t\t\treturn\n+\t\tfi\n+\t\t;;\n+\tesac\n+\t$use_perform git $what \"$@\"\n+}\n+\n+nth_string () {\n+\tcase \"$1\" in\n+\t*1[0-9]|*[04-9])\n+\t\techo \"$1th\"\n+\t\t;;\n+\t*1)\n+\t\techo \"$1st\"\n+\t\t;;\n+\t*2)\n+\t\techo \"$1nd\"\n+\t\t;;\n+\t*3)\n+\t\techo \"$1rd\"\n+\t\t;;\n+\tesac\n+}\n+\n+make_squash_message () {\n+\tif test -f \"$squash_msg\"\n+\tthen\n+\t\tcount=$(($(sed -n -e 's/^# This is [^0-9]*\\([1-9][0-9]*\\).*/\\1/p' \\\n+\t\t\t<\"$squash_msg\" | sed -n -e '$p')+1))\n+\t\techo \"# This is a combination of $count commits.\"\n+\t\tsed -e '1d' -e '2,/^./{\n+\t\t\t/^$/d\n+\t\t}' <\"$squash_msg\"\n+\telse\n+\t\tcount=2\n+\t\techo '# This is a combination of 2 commits.'\n+\t\techo '# The first commit message is:'\n+\t\techo\n+\t\tcommit_message HEAD\n+\tfi\n+\techo\n+\techo \"# This is the $(nth_string \"$count\") commit message:\"\n+\techo\n+\tcommit_message \"$1\"\n+}\n+\n+make_squash_message_multiple () {\n+\trevlist=$(git rev-list --reverse \"$sha1..HEAD\")\n+\tcount=$(echo \"$revlist\" | wc -l)\n+\tsquash_i=0\n+\techo \"# This is a combination of $count commits.\"\n+\tfor cur_sha1 in $revlist\n+\tdo\n+\t\tsquash_i=$(($squash_i+1))\n+\t\tif test -f \"$squash_msg\"\n+\t\tthen\n+\t\t\tcount=$(($count + $(sed -n -e \\\n+\t\t\t\t's/^# This is [^0-9]*\\([1-9][0-9]*\\).*/\\1/p' \\\n+\t\t\t\t<\"$squash_msg\" | sed -n -e '$p')+1))\n+\t\t\tsed -e '1d' -e '2,/^./{\n+\t\t\t\t/^$/d\n+\t\t\t}' <\"$squash_msg\"\n+\t\tfi\n+\t\techo\n+\t\techo \"# This is the $(nth_string \"$squash_i\") commit message:\"\n+\t\techo\n+\t\tcommit_message \"$cur_sha1\"\n+\tdone\n+}\n+\n+peek_next_command () {\n+\tsed -n -e '/^#/d' -e '1s/ .*$//p' <\"$TODO\"\n+}\n+\n+# If $1 is a mark, make a ref from it; otherwise keep it.\n+# Note on marks:\n+#  * :0 is allowed\n+#  * :01 is the same as :1\n+mark_to_ref () {\n+\targ=\"$1\"\n+\tref=$(expr \"x$arg\" : 'x:0*\\([0-9][0-9]*\\)$')\n+\ttest -n \"$ref\" &&\n+\t\targ=\"$MARK_PREFIX/$ref\"\n+\tprintf '%s\\n' \"$arg\"\n+}\n+\n+mark_to_commit () {\n+\tgit rev-parse --verify \"$(mark_to_ref \"$1\")\"\n+}\n+\n+\n+fallback_3way () {\n+\t# Cleanup if not done before.\n+\trm -fr \"$PATCH-merge-\"*\n+\n+\t# First see if the patch records the index info that we can use.\n+\tperform git apply --build-fake-ancestor \"$PATCH-merge-index\" \"$PATCH\" &&\n+\tGIT_INDEX_FILE=\"$PATCH-merge-index\" git write-tree >\"$PATCH-merge-base\" ||\n+\t\tdie_to_continue 'Repository lacks necessary blobs to fall back on 3-way merge. Please hand-edit.'\n+\n+\ttest \"$VERBOSE\" -eq 0 ||\n+\t\techo 'Using index info to reconstruct a base tree...'\n+\tGIT_INDEX_FILE=\"$PATCH-merge-index\" git apply --cached \"$PATCH\" ||\n+\t\tdie_to_continue 'Patch does not apply to blobs recorded in its index.'\n+\n+\this_tree=$(GIT_INDEX_FILE=\"$PATCH-merge-index\" git write-tree) &&\n+\torig_tree=$(cat \"$PATCH-merge-base\") &&\n+\trm -fr \"$PATCH-merge-\"* ||\n+\t\tdie_to_continue 'Writing new tree failed.'\n+\n+\ttest \"$VERBOSE\" -eq 0 ||\n+\t\techo 'Falling back to patching base and 3-way merge...'\n+\n+\t# This is not so wrong.  Depending on which base we picked,\n+\t# orig_tree may be wildly different from ours, but his_tree\n+\t# has the same set of wildly different changes in parts the\n+\t# patch did not touch, so recursive ends up canceling them,\n+\t# saying that we reverted all those changes.\n+\n+\teval GITHEAD_$his_tree='\"$firstline\"'\n+\texport GITHEAD_$his_tree\n+\tperform git merge-recursive \"$orig_tree\" -- HEAD \"$his_tree\" || {\n+\t\tperform git rerere\n+\t\tdie_to_continue 'Failed to merge in the changes.'\n+\t}\n+}\n+\n+# Run hook \"$@\" (with arguments) if executable\n+run_hook () {\n+\ttest -z \"$1\" || return\n+\thookname=\"$1\"\n+\thook=\"$GIT_DIR/hooks/$hookname\"\n+\tshift\n+\tif test -x \"$hook\"\n+\tthen\n+\t\t\"$hook\" \"$@\" ||\n+\t\t\tdie_to_continue \"Hook $hookname failed.\"\n+\tfi\n+}\n+\n+# Add Signed-off-by: line if general option --signoff is given\n+dashdash_signoff () {\n+\tadd_signoff=\n+\tif test -n \"$SIGNOFF\"\n+\tthen\n+\t\tlast_signed_off_by=$(\n+\t\t\tsed -n -e '/^Signed-off-by: /p' <\"$MSG\" | sed -n -e '$p'\n+\t\t)\n+\t\ttest \"$last_signed_off_by\" = \"$SIGNOFF\" ||\n+\t\t\tadd_signoff=$(\n+\t\t\t\ttest '' = \"$last_signed_off_by\" && echo\n+\t\t\t\techo \"$SIGNOFF\"\n+\t\t\t)\n+\tfi\n+\t{\n+\t\ttest -s \"$MSG\" && cat \"$MSG\"\n+\t\ttest -n \"$add_signoff\" && echo \"$add_signoff\"\n+\t} >\"$MSG.new\"\n+\tmv \"$MSG.new\" \"$MSG\"\n+}\n+\n+\n+### --caller-related functions\n+\n+# Show string for caller invocation for --abort/--continue/--skip\n+print_caller_info () {\n+\tcase \"$1\" in\n+\t--abort)\n+\t\techo \"$CALLER_ABRT\"\n+\t\t;;\n+\t--continue)\n+\t\techo \"$CALLER_CONT\"\n+\t\t;;\n+\t--skip)\n+\t\techo \"$CALLER_SKIP\"\n+\t\t;;\n+\t*)\n+\t\twarn 'Internal error: Unknown print_caller argument!'\n+\t\t;;\n+\tesac\n+}\n+\n+# Print the program to invoke to (--)abort/continue/skip\n+print_caller() {\n+\tcaller_info=$(print_caller_info \"$1\")\n+\tif test -n \"$CALLERCOMPARE\" -a -n \"$caller_info\"\n+\tthen\n+\t\ttest -n \"$CALLER\" && printf \"$CALLER \"\n+\t\techo \"$caller_info\"\n+\telse\n+\t\techo \"git sequencer $1\"\n+\tfi\n+}\n+\n+# Test if --caller was set correctly\n+# $1 must be abort/continue/skip\n+test_caller () {\n+\tcaller_info=$(print_caller_info \"--$1\")\n+\ttest -n \"$CALLERCOMPARE\" -a \\\n+\t\t\"$CALLERCOMPARE\" != \"$CALLERSTRING\" -a \\\n+\t\t-n \"$caller_info\" &&\n+\t\tdie \"You must use '$CALLER $caller_info' to $1!\"\n+}\n+\n+# Generate $CALLER_SCRIPT file from \"git foo|--abort|--continue|--skip\"\n+# string $1\n+generate_caller_script () {\n+\techo \"$1\" | sed -e 's/^\\(.*\\)|\\(.*\\)|\\(.*\\)|\\(.*\\)$/\\\n+CALLERCOMPARE=\"\\0\"\\\n+CALLER=\"\\1\"\\\n+CALLER_ABRT=\"\\2\"\\\n+CALLER_CONT=\"\\3\"\\\n+CALLER_SKIP=\"\\4\"/' >\"$CALLER_SCRIPT\"\n+}\n+\n+# Run caller script and set GIT_CHERRY_PICK_HELP\n+assure_caller () {\n+\ttest -r \"$CALLER_SCRIPT\" &&\n+\t\t. \"$CALLER_SCRIPT\"\n+\n+\t# we do not want cherry-pick to print *any* help\n+\tGIT_CHERRY_PICK_HELP=\"\"\n+\texport GIT_CHERRY_PICK_HELP\n+}\n+\n+\n+### Helpers for check_* functions:\n+\n+# Print a warning on todo checking\n+todo_warn () {\n+\tprintf 'Warning at line %d, %s: %s\\n' \"$line\" \"$command\" \"$*\"\n+}\n+\n+# Raise an error on todo checking\n+todo_error () {\n+\tprintf 'Error at line %d, %s: %s\\n' \"$line\" \"$command\" \"$*\"\n+\tretval=1\n+}\n+\n+# Test if $1 is a commit on todo checking\n+commit_check () {\n+\ttest \"$(git cat-file -t \"$1\" 2>/dev/null)\" = commit ||\n+\t\ttodo_error \"'$1' is not a commit.\"\n+}\n+\n+# A helper function to check if $1 is a an available mark during check_*\n+arg_is_mark_check () {\n+\tfor cur_mark in $available_marks\n+\tdo\n+\t\ttest \"$cur_mark\" -eq \"${1#:}\" && return\n+\tdone\n+\ttodo_error \"Mark $1 is not yet defined.\"\n+}\n+\n+# A helper function for check_* and mark usage:\n+# check if \"$1\" is a commit or a defined mark\n+arg_is_mark_or_commit_check () {\n+\tif expr \"x$1\" : 'x:[0-9][0-9]*$' >/dev/null\n+\tthen\n+\t\targ_is_mark_check \"$1\"\n+\telse\n+\t\tcommit_check \"$1\"\n+\tfi\n+}\n+\n+\n+### Author script functions\n+\n+# Take \"Name <e-mail>\" in stdin and outputs author script\n+make_author_script_from_string () {\n+\tsed -e \"s/'/'\"'\\\\'\"''/g\" \\\n+\t    -e 's/^\\(.*\\) <\\(.*\\)>.*$/GIT_AUTHOR_NAME='\\''\\1'\\''\\\n+GIT_AUTHOR_EMAIL='\\''\\2'\\''\\\n+GIT_AUTHOR_DATE=/'\n+}\n+\n+\n+### General option functions (and options spec)\n+\n+OPTIONS_GENERAL=' General options\n+author= override author\n+C,reuse-commit= reuse message and authorship data from commit\n+F,file= take commit message from given file\n+m,message= specify commit message\n+M,reuse-message= reuse message from commit\n+signoff add signoff\n+e,edit invoke editor to edit commit message'\n+\n+# Check if option is a general option\n+check_general_option () {\n+\tgeneral_shift=1\n+\tcase \"$1\" in\n+\t--signoff)\n+\t\treturn 0\n+\t\t;;\n+\t--author)\n+\t\tgeneral_shift=2\n+\t\tauthor_opt=\"t$author_opt\"\n+\t\texpr \"x$2\" : 'x.* <.*>' >/dev/null ||\n+\t\t\ttodo_error \"Author \\\"$2\\\" not in the correct format \\\"Name <e-mail>\\\".\"\n+\t\t;;\n+\t-m)\n+\t\tgeneral_shift=2\n+\t\tmsg_opt=\"t$msg_opt\"\n+\t\t;;\n+\t-C)\n+\t\tgeneral_shift=2\n+\t\tmsg_opt=\"t$msg_opt\"\n+\t\tauthor_opt=\"t$author_opt\"\n+\t\tcommit_check \"$2\"\n+\t\t;;\n+\t-M)\n+\t\tgeneral_shift=2\n+\t\tmsg_opt=\"t$msg_opt\"\n+\t\tcommit_check \"$2\"\n+\t\t;;\n+\t-F)\n+\t\tgeneral_shift=2\n+\t\tmsg_opt=\"t$msg_opt\"\n+\t\ttest -r \"$2\" ||\n+\t\t\ttodo_error \"Cannot read file '$2'.\"\n+\t\t;;\n+\t-e)\n+\t\ttest -z \"$BATCHMODE\" ||\n+\t\t\ttodo_error '--batch and --edit options do not make sense together.'\n+\t\t;;\n+\t*)\n+\t\treturn 1\n+\t\t;;\n+\tesac\n+}\n+\n+# Set a general option variable or return 1\n+handle_general_option () {\n+\tgeneral_shift=1\n+\tcase \"$1\" in\n+\t--signoff)\n+\t\tSIGNOFF=$(git var GIT_COMMITTER_IDENT | sed -e '\n+\t\t\t\ts/>.*/>/\n+\t\t\t\ts/^/Signed-off-by: /')\n+\t\t;;\n+\t--author)\n+\t\tgeneral_shift=2\n+\t\tAUTHOR=t\n+\t\techo \"$2\" |\n+\t\t\tmake_author_script_from_string >\"$AUTHOR_SCRIPT\"\n+\t\t;;\n+\t-m)\n+\t\tgeneral_shift=2\n+\t\tMESSAGE=\"$2\"\n+\t\t;;\n+\t-C)\n+\t\tgeneral_shift=2\n+\t\tAUTHOR=t\n+\t\tget_author_ident_from_commit \"$2\" >\"$AUTHOR_SCRIPT\"\n+\t\tMESSAGE=$(commit_message \"$2\")\n+\t\t;;\n+\t-M)\n+\t\tgeneral_shift=2\n+\t\tMESSAGE=$(commit_message \"$2\")\n+\t\t;;\n+\t-F)\n+\t\tgeneral_shift=2\n+\t\tMESSAGE=$(cat \"$2\")\n+\t\t;;\n+\t-e)\n+\t\tEDIT=--edit\n+\t\t;;\n+\t*)\n+\t\treturn 1\n+\t\t;;\n+\tesac\n+}\n+\n+\n+### Functions for checking and realizing TODO instructions\n+# Note that options_*, check_* and insn_* function names are reserved.\n+\n+options_pause=\"\\\n+pause\n+--\n+\"\n+\n+# Check the \"pause\" instruction\n+check_pause () {\n+\tshift\n+\ttest -z \"$BATCHMODE\" ||\n+\t\ttodo_error '\"pause\" instruction and --batch do not make sense together.'\n+\ttest $# -eq 0 ||\n+\t\ttodo_error 'The pause instruction takes no arguments.'\n+\treturn 0\n+}\n+\n+# Realize the \"pause\" instruction\n+insn_pause () {\n+\tsave_commit_data HEAD\n+\techo 'pause' >\"$WHY_FILE\"\n+\tWHY=pause print_advice\n+\ttest -z \"$ORIG_HEAD\" || git update-ref ORIG_HEAD \"$ORIG_HEAD\"\n+\texit 2\n+}\n+\n+\n+options_run=\"\\\n+run [--dir=<path>] [--] <cmd> <args>...\n+--\n+dir= change directory before running command\n+\"\n+\n+# Check the \"run\" instruction\n+check_run () {\n+\twhile test $# -gt 0\n+\tdo\n+\t\tcase \"$1\" in\n+\t\t--dir)\n+\t\t\ttest -e \"$2\" ||\n+\t\t\t\ttodo_error \"Path $2 does not exist.\"\n+\t\t\ttest -d \"$2\" ||\n+\t\t\t\ttodo_error \"Path $2 is not a directory.\"\n+\t\t\tshift 2\n+\t\t\t;;\n+\t\t--)\n+\t\t\tshift\n+\t\t\tbreak\n+\t\t\t;;\n+\t\t-*)\n+\t\t\ttodo_error \"Unknown option $1\"\n+\t\t\t;;\n+\t\tesac\n+\tdone\n+\t# we don't check if cmd exists\n+\treturn 0\n+}\n+\n+# Realize the \"run\" instruction\n+insn_run () {\n+\trunpath=./\n+\twhile test $# -gt 0\n+\tdo\n+\t\tcase \"$1\" in\n+\t\t--dir)\n+\t\t\trunpath=\"$2\"\n+\t\t\tshift 2\n+\t\t\t;;\n+\t\t--)\n+\t\t\tshift\n+\t\t\tbreak\n+\t\t\t;;\n+\t\tesac\n+\tdone\n+\n+\tsavepath=\"$PWD\"\n+\tcd \"$runpath\"\n+\t\"$@\"\n+\tsuccess=\"$?\"\n+\tcd \"$savepath\"\n+\n+\tif test \"$success\" -ne 0\n+\tthen\n+\t\ttest -z \"$BATCHMODE\" ||\n+\t\t\tdie_abort \"Running $1 failed. Aborting because of batch mode.\"\n+\t\tsave_commit_data HEAD\n+\t\techo 'run' >\"$WHY_FILE\"\n+\t\tWHY=run print_advice \"$@\"\n+\t\ttest -z \"$ORIG_HEAD\" || git update-ref ORIG_HEAD \"$ORIG_HEAD\"\n+\t\texit 3\n+\tfi\n+}\n+\n+\n+options_patch=\"\\\n+patch [options] <file>\n+--\n+3,3way fall back to 3-way merge\n+k pass to git-mailinfo (keep subject)\n+n pass to git-mailinfo (no utf8)\n+$OPTIONS_GENERAL\n+ Options passed to git-apply\n+R,reverse reverse changes\n+context= ensure context of ... lines\n+p= remove ... leading slashes\n+unidiff-zero bypass unidiff checks\n+exclude= do not apply changes to given files\n+no-add ignore additions of patch\n+whitespace= set whitespace error behavior\n+inaccurate-eof support inaccurate EOFs\n+u no-op (backward compatibility)\n+binary no-op (backward compatibility)\n+\"\n+\n+# Check the \"patch\" instruction\n+check_patch () {\n+\twhile test $# -gt 1\n+\tdo\n+\t\tcase \"$1\" in\n+\t\t-3|-k|-n|-u|--binary|-R|--reverse|--unidiff-zero|--no-add|--inaccurate-eof)\n+\t\t\t:\n+\t\t\t;;\n+\t\t-p|--whitespace|--exclude|--context)\n+\t\t\tshift\n+\t\t\t;;\n+\t\t--)\n+\t\t\tshift\n+\t\t\tbreak\n+\t\t\t;;\n+\t\t-*)\n+\t\t\tcheck_general_option \"$@\" ||\n+\t\t\t\ttodo_warn \"Unknown option $1\"\n+\t\t\t;;\n+\t\t*)\n+\t\t\ttodo_error \"Wrong number of arguments. ($# given, 1 wanted)\"\n+\t\t\tbreak\n+\t\t\t;;\n+\t\tesac\n+\t\tshift $general_shift\n+\tdone\n+\n+\tif test -f \"$1\" -a -r \"$1\"\n+\tthen\n+\t\tgrep -e '^diff' \"$1\" >/dev/null ||\n+\t\t\ttodo_error \"File '$1' contains no patch.\"\n+\telse\n+\t\ttodo_error \"Cannot open file '$1'.\"\n+\tfi\n+\treturn 0\n+}\n+\n+# Realize the \"patch\" instruction\n+insn_patch () {\n+\tapply_opts=\n+\tmailinfo_opts=\n+\tthreeway=\n+\n+\t# temporary files\n+\tinfofile=\"$SEQ_DIR/patch-info\"\n+\tmsgfile=\"$SEQ_DIR/patch-msg\"\n+\n+\twhile test \"$#\" -gt 1\n+\tdo\n+\t\tcase \"$1\" in\n+\t\t-3)\n+\t\t\tthreeway=t\n+\t\t\t;;\n+\t\t-k|-n)\n+\t\t\tmailinfo_opts=\"$mailinfo_opts $1\"\n+\t\t\t;;\n+\t\t-u|--binary)\n+\t\t\t: Do nothing. It is there due to b/c only.\n+\t\t\t;;\n+\t\t-R|--reverse|--unidiff-zero|--no-add|--inaccurate-eof)\n+\t\t\tapply_opts=\"$apply_opts $1\"\n+\t\t\t;;\n+\t\t-p)\n+\t\t\tshift\n+\t\t\tapply_opts=\"$apply_opts -p$1\"\n+\t\t\t;;\n+\t\t--whitespace|--exclude)\n+\t\t\tapply_opts=\"$apply_opts $1=$2\"\n+\t\t\tshift\n+\t\t\t;;\n+\t\t--context)\n+\t\t\tshift\n+\t\t\tapply_opts=\"$apply_opts -C$1\"\n+\t\t\t;;\n+\t\t--)\n+\t\t\tshift\n+\t\t\tbreak\n+\t\t\t;;\n+\t\t*)\n+\t\t\thandle_general_option \"$@\"\n+\t\t\t;;\n+\t\tesac\n+\t\tshift $general_shift\n+\tdone\n+\n+\tfilename=\"$1\"\n+\n+\tgit mailinfo $mailinfo_opts \"$msgfile\" \"$PATCH\" \\\n+\t\t<\"$filename\" >\"$infofile\" ||\n+\t\tdie_abort 'Could not read or parse mail'\n+\n+\t# if author not set by option, read author information of patch\n+\tif test -z \"$AUTHOR\"\n+\tthen\n+\t\tcp \"$ORIG_AUTHOR_SCRIPT\" \"$AUTHOR_SCRIPT\"\n+\t\tsed -e \"s/'/'\"'\\\\'\"''/g\" -n -e '\n+\t\t\ts/^Author: \\(.*\\)$/GIT_AUTHOR_NAME='\\''\\1'\\''/p;\n+\t\t\ts/^Email: \\(.*\\)$/GIT_AUTHOR_EMAIL='\\''\\1'\\''/p;\n+\t\t\ts/^Date: \\(.*\\)$/GIT_AUTHOR_DATE='\\''\\1'\\''/p\n+\t\t' <\"$infofile\" >>\"$AUTHOR_SCRIPT\"\n+\t\t# If sed's result is empty, we keep the original\n+\t\t# author script by appending.\n+\tfi\n+\n+\t# Ignore every mail that's not containing a patch\n+\ttest -s \"$PATCH\" || {\n+\t\twarn 'Does not contain patch!'\n+\t\treturn 0\n+\t}\n+\n+\tedit_msg=\n+\tif grep -e '^Subject:' \"$infofile\" >/dev/null\n+\tthen\n+\t\t# add subject to commit message\n+\t\tsed -n -e '/^Subject:/ s/Subject: //p' <\"$infofile\"\n+\t\techo\n+\t\techo\n+\t\tcat \"$msgfile\"\n+\telse\n+\t\tcat \"$msgfile\"\n+\t\tedit_msg=t\n+\tfi | git stripspace >\"$MSG\"\n+\trm -f \"$infofile\" \"$msgfile\"\n+\n+\tfirstline=$(sed -e '1q' <\"$MSG\")\n+\n+\tget_current_author\n+\n+\ttest -n \"$MESSAGE\" && printf '%s\\n' \"$MESSAGE\" >\"$MSG\"\n+\ttest -z \"$firstline\" && firstline=$(sed -e '1q' <\"$MSG\")\n+\n+\tdashdash_signoff\n+\n+\twith_author run_hook applypatch-msg \"$MSG\"\n+\tfailed=\n+\tgit apply $apply_opts --index \"$PATCH\" || failed=t\n+\n+\tif test -n \"$failed\" -a -n \"$threeway\" && (with_author fallback_3way)\n+\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\tgit diff-index --quiet --cached HEAD -- && {\n+\t\t\techo 'No changes -- Patch already applied.'\n+\t\t\treturn 0\n+\t\t\t# XXX: do we want that?\n+\t\t}\n+\t\t# clear apply_status -- we have successfully merged.\n+\t\tfailed=\n+\tfi\n+\n+\tif test -n \"$failed\"\n+\tthen\n+\t\tdie_to_continue \"Patch failed: $firstline\"\n+\t\t# XXX: We actually needed a git-apply flag that creates\n+\t\t# conflict markers and sets the DIFF_STATUS_UNMERGED flag.\n+\tfi\n+\n+\twith_author run_hook pre-applypatch\n+\n+\ttest -n \"$EDIT\" && edit_msg=t\n+\tif ! has_message \"$MSG\" || test -n \"$edit_msg\"\n+\tthen\n+\t\techo \"\n+# Please enter the commit message for the applied patch.\n+# (Comment lines starting with '#' will not be included)\" >>\"$MSG\"\n+\n+\t\tgit_editor \"$MSG\" ||\n+\t\t\tdie_with_patch HEAD 'Editor returned error.'\n+\t\thas_message \"$MSG\" ||\n+\t\t\tdie_with_patch HEAD 'No commit message given.'\n+\tfi\n+\n+\ttree=$(git write-tree) &&\n+\tparent=$(git rev-parse --verify HEAD) &&\n+\tcommit=$(with_author git commit-tree \"$tree\" -p \"$parent\" <\"$MSG\") &&\n+\tgit update-ref -m \"$GIT_REFLOG_ACTION: $firstline\" HEAD \"$commit\" \"$parent\" ||\n+\t\tdie_to_continue 'Could not commit tree.'\n+\n+\ttest -x \"$GIT_DIR/hooks/post-applypatch\" &&\n+\t\twith_author \"$GIT_DIR/hooks/post-applypatch\"\n+\n+\treturn 0\n+}\n+\n+\n+options_pick=\"\\\n+pick [options] <commit>\n+--\n+R,reverse revert introduced changes\n+mainline= specify parent number to use for merge commits\n+$OPTIONS_GENERAL\n+\"\n+\n+# Check the \"pick\" instruction\n+check_pick () {\n+\tmainline=\n+\twhile test $# -gt 1\n+\tdo\n+\t\tcase \"$1\" in\n+\t\t-R)\n+\t\t\t;;\n+\t\t--mainline)\n+\t\t\tshift\n+\t\t\tmainline=\"$1\"\n+\t\t\ttest \"$mainline\" -gt 0 || {\n+\t\t\t\ttodo_error '--mainline needs an integer beginning from 1.'\n+\t\t\t\tmainline=\n+\t\t\t}\n+\t\t\t;;\n+\t\t--)\n+\t\t\tshift\n+\t\t\tbreak\n+\t\t\t;;\n+\t\t-*)\n+\t\t\tcheck_general_option \"$@\" ||\n+\t\t\t\ttodo_warn \"Unknown option $1\"\n+\t\t\t;;\n+\t\t*)\n+\t\t\ttodo_error \"Wrong number of arguments. ($# given, 1 wanted)\"\n+\t\t\tbreak\n+\t\t\t;;\n+\t\tesac\n+\t\tshift $general_shift\n+\tdone\n+\n+\tif test -n \"$mainline\"\n+\tthen\n+\t\tparents=$(count_parents \"$1\")\n+\t\ttest \"$parents\" -lt \"$mainline\" &&\n+\t\t\ttodo_error \"Commit has only $parents (less than $mainline) parents.\"\n+\t\ttest \"$parents\" -eq 1 &&\n+\t\t\ttodo_warn 'Commit is not a merge at all.'\n+\tfi\n+\n+\tcommit_check \"$1\"\n+\n+\treturn 0\n+}\n+\n+# Realize the \"pick\" instruction\n+insn_pick () {\n+\top=cherry-pick\n+\tmainline=\n+\twhile test $# -gt 1\n+\tdo\n+\t\tcase \"$1\" in\n+\t\t-R)\n+\t\t\top=revert\n+\t\t\t;;\n+\t\t--mainline)\n+\t\t\tmainline=\"$1 $2\"\n+\t\t\tshift\n+\t\t\t;;\n+\t\t--)\n+\t\t\tshift\n+\t\t\tbreak\n+\t\t\t;;\n+\t\t-*)\n+\t\t\thandle_general_option \"$@\"\n+\t\t\t;;\n+\t\tesac\n+\t\tshift $general_shift\n+\tdone\n+\n+\tsha1=$(git rev-parse --verify \"$1\")\n+\n+\tedit_msg=\"$EDIT\"\n+\n+\t# Don't edit on pick, but later, if author or message given.\n+\ttest -n \"$AUTHOR\" -o -n \"$MESSAGE\" && edit_msg=\n+\n+\t# Be kind to users and ignore --mainline=1 on non-merge commits\n+\ttest -n \"$mainline\" -a 2 -gt $(count_parents \"$sha1\") && mainline=\n+\n+\tuse_perform=\n+\ttest -n \"$edit_msg\" ||\n+\t\tuse_perform=perform\n+\n+\tpick_one \"$op\" $edit_msg $mainline $sha1 ||\n+\t\tdie_with_patch $sha1 \"Could not apply $sha1.\"\n+\n+\ttest -n \"$EDIT\" ||\n+\t\tuse_perform=perform\n+\n+\tget_current_author\n+\tsignoff=\n+\ttest -n \"$SIGNOFF\" && signoff=-s\n+\tif test -n \"$AUTHOR\" -a -n \"$MESSAGE\"\n+\tthen\n+\t\t# this is just because we only want to do ONE amending commit\n+\t\t$use_perform git commit --amend $EDIT $signoff --no-verify \\\n+\t\t\t--author \"$GIT_AUTHOR_NAME <$GIT_AUTHOR_EMAIL>\" \\\n+\t\t\t--message=\"$MESSAGE\"\n+\telif test -n \"$AUTHOR\"\n+\tthen\n+\t\t# correct author if AUTHOR is set\n+\t\t$use_perform git commit --amend $EDIT --no-verify -C HEAD \\\n+\t\t\t--author \"$GIT_AUTHOR_NAME <$GIT_AUTHOR_EMAIL>\"\n+\telif test -n \"$MESSAGE\"\n+\tthen\n+\t\t# correct commit message if MESSAGE is set\n+\t\t$use_perform git commit --amend $EDIT $signoff --no-verify \\\n+\t\t\t-C HEAD --message=\"$MESSAGE\"\n+\telif test -n \"$SIGNOFF\"\n+\tthen\n+\t\t# only add signoff\n+\t\t$use_perform git commit --amend $EDIT $signoff --no-verify \\\n+\t\t\t-C HEAD\n+\tfi\n+\n+\treturn 0\n+}\n+\n+options_edit=\"\\\n+edit <commit>\n+--\n+\"\n+\n+# Check the \"edit\" instruction\n+check_edit () {\n+\tshift\n+\ttest -z \"$BATCHMODE\" ||\n+\t\ttodo_error '\"edit\" instruction and --batch do not make sense together.'\n+\ttest $# -eq 1 ||\n+\t\ttodo_error \"Wrong number of arguments. ($# given, 1 wanted)\"\n+\treturn 0\n+}\n+\n+# Realize the \"edit\" instruction\n+insn_edit () {\n+\tshift\n+\tinsn_pick \"$1\"\n+\techo '# pausing' >>\"$DONE\"\n+\tinsn_pause\n+}\n+\n+\n+options_squash=\"\\\n+squash <commit>\n+squash [options] --from <mark>\n+--\n+from squash all commits from <mark>\n+collect-signoffs collect Signed-off-by: lines\n+include-merges do not fail on merge commits\n+$OPTIONS_GENERAL\n+\"\n+\n+# Check the \"squash\" instruction\n+check_squash () {\n+\tfrom=\n+\tcollect=\n+\tmerges=\n+\twhile test $# -gt 1\n+\tdo\n+\t\tcase \"$1\" in\n+\t\t--from)\n+\t\t\tfrom=t\n+\t\t\t;;\n+\t\t--collect-signoffs)\n+\t\t\tcollect=t\n+\t\t\ttodo_warn 'Not yet implemented.'\n+\t\t\t;;\n+\t\t--include-merges)\n+\t\t\tmerges=t\n+\t\t\t;;\n+\t\t--)\n+\t\t\tshift\n+\t\t\tbreak\n+\t\t\t;;\n+\t\t*)\n+\t\t\tcheck_general_option \"$@\" ||\n+\t\t\t\ttodo_error \"Unknown option $1\"\n+\t\t\t;;\n+\t\tesac\n+\t\tshift $general_shift\n+\tdone\n+\n+\t# in --from mode?\n+\tif test -n \"$from\"\n+\tthen\n+\t\ttest -z \"$merges\" &&\n+\t\t\tcat \"$DONE\" \"$TODO\" |\n+\t\t\tsed -n -e '/^[ \\t]*mark[ \\t]*:\\{0,1\\}'\"${1#:}\"'\\($\\|[^0-9]\\)/,'\"$line\"'p' |\n+\t\t\tgrep '^[ \\t]*merge' >/dev/null &&\n+\t\t\ttodo_error \"$1..HEAD contains a merge commit. You may try --include-merges.\"\n+\n+\t\targ_is_mark_check \"$1\"\n+\telse\n+\t\ttest -n \"$merges\" &&\n+\t\t\ttodo_error '--include-merges only makes sense with --from <mark>.'\n+\t\ttest -n \"$collect\" &&\n+\t\t\ttodo_error '--collect-signoffs only makes sense with --from <mark>.'\n+\n+\t\tcommit_check \"$1\"\n+\tfi\n+\n+\treturn 0\n+}\n+\n+# Realize the \"squash\" instruction\n+insn_squash () {\n+\tsquash_msg=\"$MSG-squash\"\n+\tfrom=\n+\twhile test $# -gt 1\n+\tdo\n+\t\tcase \"$1\" in\n+\t\t--from)\n+\t\t\tfrom=t\n+\t\t\t;;\n+\t\t--collect-signoffs)\n+\t\t\twarn '--collect-signoffs is not implemented.'\n+\t\t\t# XXX\n+\t\t\t;;\n+\t\t--include-merges)\n+\t\t\t: # This has to be done during check_squash\n+\t\t\t;;\n+\t\t--)\n+\t\t\tshift\n+\t\t\tbreak\n+\t\t\t;;\n+\t\t*)\n+\t\t\thandle_general_option \"$@\"\n+\t\t\t;;\n+\t\tesac\n+\t\tshift $general_shift\n+\tdone\n+\n+\tif test -n \"$from\"\n+\tthen\n+\t\tsha1=$(mark_to_commit \":${1#:}\")\n+\telse\n+\t\tsha1=$(git rev-parse --verify \"$1\")\n+\tfi\n+\n+\t# Hm, somehow I don't think --skip on a conflicting squash\n+\t# may be useful, but if someone wants to do it, it should\n+\t# do the obvious: skip what squash would do.\n+\techo \"$(git rev-parse HEAD)\" >\"$SEQ_DIR/skiphead\"\n+\n+\tif test -n \"$MESSAGE\"\n+\tthen\n+\t\tprintf '%s\\n' \"$MESSAGE\" >\"$MSG\"\n+\telse\n+\t\tif test -n \"$from\"\n+\t\tthen\n+\t\t\tmake_squash_message_multiple \"$sha1\" >\"$MSG\"\n+\t\telse\n+\t\t\tmake_squash_message \"$sha1\" >\"$MSG\"\n+\t\tfi\n+\tfi\n+\n+\tcase \"$(peek_next_command)\" in\n+\tsquash)\n+\t\tedit_commit=\n+\t\tuse_perform=perform\n+\t\tcp \"$MSG\" \"$squash_msg\"\n+\t\t;;\n+\t*)\n+\t\tedit_commit=-e\n+\t\tuse_perform=\n+\t\trm -f \"$squash_msg\"\n+\t\t;;\n+\tesac\n+\n+\ttest -n \"$MESSAGE\" && edit_commit=\n+\ttest -n \"$EDIT\" && edit_commit=-e\n+\n+\t# is --author (or equivalent) set?\n+\tif test -n \"$AUTHOR\"\n+\tthen\n+\t\t# evaluate author script\n+\t\tget_current_author\n+\telse\n+\t\t# if --author is not given, we get the authorship\n+\t\t# information from the commit before.\n+\t\teval \"$(get_author_ident_from_commit HEAD)\"\n+\t\t# but we do not write an author script\n+\tfi\n+\n+\t# --from or not\n+\tfailed=\n+\tif test -n \"$from\"\n+\tthen\n+\t\tperform git reset --soft \"$sha1\"\n+\telse\n+\t\tperform git reset --soft HEAD^\n+\n+\t\tpick_one cherry-pick -n \"$sha1\" || failed=t\n+\tfi\n+\n+\tdashdash_signoff\n+\n+\tif test -z \"$failed\"\n+\tthen\n+\t\t# This is like --amend, but with a different message\n+\t\twith_author $use_perform git commit --no-verify \\\n+\t\t\t-F \"$MSG\" $edit_commit || failed=t\n+\telse\n+\t\tcp \"$MSG\" \"$GIT_DIR/SQUASH_MSG\"\n+\t\twarn\n+\t\tdie_with_patch $sha1 \"Could not apply $sha1.\"\n+\tfi\n+\n+\treturn 0\n+}\n+\n+\n+options_mark=\"\\\n+mark <mark>\n+--\n+\"\n+\n+# Check the \"mark\" instruction\n+check_mark () {\n+\tshift\n+\ttest $# -eq 1 ||\n+\t\ttodo_error \"Wrong number of arguments. ($# given, 1 wanted)\"\n+\tmy_mark=$(expr \"x${1#:}\" : 'x0*\\([0-9][0-9]*\\)$')\n+\ttest -n \"$my_mark\" ||\n+\t\ttodo_error \"Mark $1 not an integer.\"\n+\texpr \"x$available_marks \" : \" $my_mark \" >/dev/null &&\n+\t\ttodo_error \"Mark :$my_mark already defined. Choose another integer.\"\n+\tavailable_marks=\"$available_marks $my_mark\"\n+\n+\treturn 0\n+}\n+\n+# Realize the \"mark\" instruction\n+insn_mark () {\n+\tshift\n+\tgiven=\"$1\"\n+\n+\tmark=$(mark_to_ref \":${given#:}\")\n+\tgit update-ref \"$mark\" HEAD\n+\treturn 0\n+}\n+\n+\n+options_merge=\"\\\n+merge [options] <commit-ish> ...\n+--\n+standard generate default commit message\n+s,strategy= use merge strategy ...\n+$OPTIONS_GENERAL\n+\"\n+\n+# Check the \"merge\" instruction\n+check_merge () {\n+\twhile test $# -gt 1\n+\tdo\n+\t\tcase \"$1\" in\n+\t\t--standard)\n+\t\t\tmsg_opt=\"t$msg_opt\"\n+\t\t\t;;\n+\t\t-s)\n+\t\t\tshift\n+\t\t\t;;\n+\t\t--)\n+\t\t\tshift\n+\t\t\tbreak\n+\t\t\t;;\n+\t\t-*)\n+\t\t\tcheck_general_option \"$@\" ||\n+\t\t\t\ttodo_error \"Unknown option $1\"\n+\t\t\t;;\n+\t\tesac\n+\t\tshift $general_shift\n+\tdone\n+\n+\ttest $# -gt 0 ||\n+\t\ttodo_error 'What are my parents? Need new parents!'\n+\n+\twhile test $# -gt 0\n+\tdo\n+\t\targ_is_mark_or_commit_check \"$1\"\n+\t\tshift\n+\tdone\n+\treturn 0\n+}\n+\n+# Realize the \"merge\" instruction\n+insn_merge () {\n+\tstandard=\n+\n+\twhile test $# -gt 1\n+\tdo\n+\t\tcase \"$1\" in\n+\t\t--standard)\n+\t\t\tstandard=t\n+\t\t\t;;\n+\t\t-s)\n+\t\t\tshift\n+\t\t\tstrategy=\"-s $1\"\n+\t\t\t;;\n+\t\t--)\n+\t\t\tshift\n+\t\t\tbreak\n+\t\t\t;;\n+\t\t-*)\n+\t\t\thandle_general_option \"$@\"\n+\t\t\t;;\n+\t\tesac\n+\t\tshift $general_shift\n+\tdone\n+\n+\tnew_parents=\n+\tfor p in \"$@\"\n+\tdo\n+\t\tnew_parents=\"$new_parents $(mark_to_ref $p)\"\n+\tdone\n+\tnew_parents=\"${new_parents# }\"\n+\n+\tget_current_author\n+\n+\tif test -n \"$standard\"\n+\tthen\n+\t\tfor cur_parent in $new_parents\n+\t\tdo\n+\t\t\tprintf '%s\\t\\t%s' \\\n+\t\t\t\t\"$(git rev-parse \"$cur_parent\")\" \"$cur_parent\"\n+\t\tdone | git fmt-merge-msg >\"$MSG\"\n+\tfi\n+\n+\ttest -n \"$MESSAGE\" &&\n+\t\tprintf '%s\\n' \"$MESSAGE\" >\"$MSG\"\n+\n+\tdashdash_signoff\n+\tif ! has_message \"$MSG\" || test -n \"$EDIT\"\n+\tthen\n+\t\techo \"\n+# Please enter the merge commit message.\n+# (Comment lines starting with '#' will not be included)\" >>\"$MSG\"\n+\n+\t\tgit_editor \"$MSG\" ||\n+\t\t\tdie_with_patch HEAD 'Editor returned error.'\n+\t\thas_message \"$MSG\" ||\n+\t\t\tdie_with_patch HEAD 'No commit message given.'\n+\tfi\n+\n+\tif ! perform git merge --no-commit $strategy $new_parents\n+\tthen\n+\t\tperform git rerere\n+\t\tcp \"$MSG\" \"$GIT_DIR/MERGE_MSG\"\n+\t\tdie_to_continue \"Error merging $new_parents.\"\n+\tfi\n+\twith_author perform git commit -F \"$MSG\" --no-verify\n+\treturn 0\n+}\n+\n+\n+options_reset=\"\\\n+reset <commit-ish>\n+--\n+\"\n+\n+# Check the \"reset\" instruction\n+check_reset () {\n+\tshift\n+\ttest $# -eq 1 ||\n+\t\ttodo_error \"Wrong number of arguments. ($# given, 1 wanted)\"\n+\targ_is_mark_or_commit_check \"$1\"\n+\n+\treturn 0\n+}\n+\n+# Realize the \"reset\" instruction\n+insn_reset () {\n+\tshift\n+\treset_almost_hard \"$(mark_to_commit \"$1\")\"\n+}\n+\n+\n+options_ref=\"\\\n+ref <ref>\n+--\n+\"\n+\n+# Check the \"ref\" instruction\n+check_ref () {\n+\tshift\n+\ttest $# -eq 1 ||\n+\t\ttodo_error \"Wrong number of arguments. ($# given, 1 wanted)\"\n+\treturn 0\n+}\n+\n+# Realize the \"ref\" instruction\n+insn_ref () {\n+\tshift\n+\tperform git update-ref \"$1\" HEAD\n+}\n+\n+\n+### Instruction main loop\n+\n+# Run check_* or insn_* with massaged options\n+# Usage: run_insn (check|do) <insn> <insn options>\n+run_insn () {\n+\tc_or_i=\"$1\"\n+\tinsn=\"$2\"\n+\tshift\n+\tshift\n+\teval \"option_spec=\\\"\\$options_$insn\\\"\"\n+\teval \"$(printf \"%s\" \"$option_spec\" |\n+\t\tgit rev-parse --parseopt -- \"$@\" ||\n+\t\techo return 1)\"\n+\tcase \"$c_or_i\" in\n+\tcheck)\n+\t\tcheck_$insn \"$@\"\n+\t\t;;\n+\tdo)\n+\t\tinsn_$insn \"$@\"\n+\t\t;;\n+\tesac\n+}\n+\n+# Execute the first line of the current TODO file\n+execute_next () {\n+\tread -r command rol <\"$TODO\"\n+\ttest \"$VERBOSE\" -gt 1 &&\n+\t\tprintf 'Next line: %s\\n' \"$command $rol\"\n+\n+\tremove_from_todo\n+\tcase \"$command\" in\n+\t'#'*|'')\n+\t\t;;\n+\t*)\n+\t\tcomment_for_reflog $command\n+\t\t# reset general options\n+\t\trm -f \"$AUTHOR_SCRIPT\" \"$MSG\"\n+\t\techo 'HEAD' >\"$SEQ_DIR/skiphead\"\n+\t\tgeneral_shift=1\n+\t\tAUTHOR=\n+\t\tEDIT=\n+\t\tMESSAGE=\n+\t\tSIGNOFF=\n+\t\t# XXX: eval is evil!\n+\t\teval \"run_insn do $command $rol\" ||\n+\t\t\tdie_to_continue 'An unexpected error occured.'\n+\t\t;;\n+\tesac\n+}\n+\n+# Execute the rest of the TODO file and finish\n+execute_rest () {\n+\twhile has_action \"$TODO\"\n+\tdo\n+\t\texecute_next\n+\tdone\n+\n+\tcomment_for_reflog finish\n+\tif test -n \"$ONTO\"\n+\tthen\n+\t\tgit update-ref -m \"$GIT_REFLOG_ACTION: $ONTO\" \"$ONTO\" HEAD &&\n+\t\tgit symbolic-ref HEAD \"$ONTO\"\n+\tfi &&\n+\tcleanup\n+\texit\n+}\n+\n+# We don't need to check a todo file if it has not changed\n+# since it has last been acknowledged to be sane.\n+todo_has_changed () {\n+\ttest -f \"$1.sum\" || return 0\n+\ttest \"$(git hash-object \"$1\")\" != \"$(cat \"$1.sum\")\"\n+}\n+\n+# acknowledge todo file to be sane\n+todo_ack () {\n+\tgit hash-object \"$1\" >\"$1.sum\"\n+}\n+\n+# Main loop to check instructions\n+todo_check () {\n+\ttodo=\"$TODO\"\n+\ttest -n \"$1\" && todo=\"$1\"\n+\ttodo_has_changed \"$todo\" || return 0\n+\n+\ttest \"$VERBOSE\" -eq 1 -a -t 1 -o \"$VERBOSE\" -gt 1 &&\n+\t\tprintf 'Checking...\\r'\n+\ttest \"$VERBOSE\" -lt 2 || echo\n+\tavailable_marks=' '\n+\tfor cur_mark in $(git for-each-ref --format='%(refname)' \"$MARK_PREFIX\")\n+\tdo\n+\t\tavailable_marks=\"$available_marks ${cur_mark##*/}\"\n+\tdone\n+\n+\tretval=0\n+\tline=1\n+\twhile read -r command rol\n+\tdo\n+\t\tcase \"$command\" in\n+\t\t'#'*|'')\n+\t\t\t;;\n+\t\t*)\n+\t\t\teval 'test -n \"$options_'\"$command\"'\"' || {\n+\t\t\t\tretval=1\n+\t\t\t\ttodo_error \"Unknown $command instruction\"\n+\t\t\t\tcontinue\n+\t\t\t}\n+\n+\t\t\tgeneral_shift=1\n+\t\t\tmsg_opt=\n+\t\t\tauthor_opt=\n+\t\t\teval \"run_insn check $command $rol\" ||\n+\t\t\t\ttodo_error \"Unknown option used\"\n+\t\t\texpr \"$msg_opt\" : 'ttt*' >/dev/null &&\n+\t\t\t\ttodo_error 'You can only provide one commit message option.'\n+\t\t\texpr \"$author_opt\" : 'ttt*' >/dev/null &&\n+\t\t\t\ttodo_error 'You can only provide one author option.'\n+\t\t\t;;\n+\t\tesac\n+\t\tline=$(expr \"$line\" + 1)\n+\tdone <\"$todo\"\n+\ttest $retval -ne 0 || todo_ack \"$todo\"\n+\treturn $retval\n+}\n+\n+prepare_editable_todo () {\n+\techo '# ALREADY DONE:'\n+\tsed -e 's/^/#  /' <\"$DONE\"\n+\techo '# '\n+\techo \"$markline\"\n+\tcat \"$TODO\"\n+}\n+\n+# expand shortcuts in TODO file $1\n+expand_shortcuts () {\n+\tsed -e '\n+\t\ts/^[ \\t]*p\\>/pick/;\n+\t\ts/^[ \\t]*e\\>/edit/;\n+\t\ts/^[ \\t]*s\\>/squash/;\n+\t' <\"$1\" >\"$TODO.cut\"\n+\tmv \"$TODO.cut\" \"$1\"\n+}\n+\n+get_saved_options () {\n+\tread ALLOW_DIRTY <\"$SEQ_DIR/allow-dirty\"\n+\tread VERBOSE <\"$SEQ_DIR/verbose\"\n+\tread ADVICE <\"$SEQ_DIR/advice\"\n+\tread ONTO <\"$SEQ_DIR/onto\"\n+\tread ORIG_HEAD <\"$SEQ_DIR/head\"\n+\ttest -f \"$WHY_FILE\" &&\n+\t\tread WHY <\"$WHY_FILE\"\n+\treturn 0\n+}\n+\n+# Realize sequencer invocation\n+do_startup () {\n+\ttest -d \"$SEQ_DIR\" &&\n+\t\tdie 'sequencer already started'\n+\n+\trequire_clean_work_tree\n+\n+\tORIG_HEAD=$(git rev-parse --verify HEAD) ||\n+\t\tdie 'No HEAD?'\n+\n+\tmkdir \"$SEQ_DIR\" ||\n+\t\tdie \"Could not create temporary $SEQ_DIR\"\n+\n+\t# save options\n+\techo \"$ALLOW_DIRTY\" >\"$SEQ_DIR/allow-dirty\"\n+\techo \"$VERBOSE\" >\"$SEQ_DIR/verbose\"\n+\techo \"$ADVICE\" >\"$SEQ_DIR/advice\"\n+\ttest -n \"$CALLERSTRING\" &&\n+\t\tgenerate_caller_script \"$CALLERSTRING\"\n+\t# generate empty DONE and \"onto\" file\n+\t: >\"$DONE\"\n+\t: >\"$SEQ_DIR/onto\"\n+\n+\tif test -n \"$BATCHMODE\"\n+\tthen\n+\t\tGIT_CHERRY_PICK_HELP='  Aborting (batch mode)'\n+\t\texport GIT_CHERRY_PICK_HELP\n+\telse\n+\t\tassure_caller\n+\tfi\n+\n+\tcomment_for_reflog start\n+\n+\t# save old head before checking out the given <branch>\n+\tgit symbolic-ref HEAD >\"$SEQ_DIR/head-name\" 2>/dev/null ||\n+\t\techo 'detached HEAD' >\"$SEQ_DIR/head-name\"\n+\techo $ORIG_HEAD >\"$SEQ_DIR/head\"\n+\t# do it here so that die_abort can work ;)\n+\n+\tif test -n \"$ONTO\"\n+\tthen\n+\t\t# if ONTO is a branch name, then keep it, otherwise\n+\t\t# we don't care anymore and erase ONTO.\n+\t\tif git-show-ref --quiet --verify -- \"refs/heads/${ONTO##*/}\"\n+\t\tthen\n+\t\t\tONTO=\"refs/heads/${ONTO##*/}\"\n+\t\t\techo \"$ONTO\" >\"$SEQ_DIR/onto\"\n+\t\t\tperform git checkout \"$(git rev-parse \"$ONTO\")\" ||\n+\t\t\t\tdie_abort \"Could not checkout branch $ONTO\"\n+\t\telse\n+\t\t\tperform git checkout \"$ONTO\" ||\n+\t\t\t\tdie_abort \"Could not checkout commit $ONTO\"\n+\t\t\tONTO=\n+\t\tfi\n+\tfi\n+\n+\t(git var GIT_AUTHOR_IDENT || git var COMMITTER_IDENT) |\n+\t\tmake_author_script_from_string >\"$ORIG_AUTHOR_SCRIPT\"\n+\n+\t# read from file or from stdin?\n+\tif test -z \"$1\"\n+\tthen\n+\t\t: >\"$TODO\" ||\n+\t\t\tdie_abort \"Could not generate TODO file $TODO\"\n+\t\twhile read -r line\n+\t\tdo\n+\t\t\tprintf '%s\\n' \"$line\" >>\"$TODO\" ||\n+\t\t\t\tdie_abort \"Could not append to TODO file $TODO\"\n+\t\tdone\n+\telse\n+\t\tcp \"$1\" \"$TODO\" ||\n+\t\t\tdie_abort \"Could not find TODO file $1.\"\n+\tfi\n+\texpand_shortcuts \"$TODO\"\n+\n+\thas_action \"$TODO\" || die_abort 'Nothing to do'\n+\ttodo_check || WHY=todo die_to_continue \"TODO file contains errors.\"\n+\n+\texecute_rest\n+\texit\n+}\n+\n+# Realize --continue.\n+do_continue () {\n+\ttest -d \"$SEQ_DIR\" || die 'No sequencer running'\n+\ttest_caller 'continue'\n+\n+\texpand_shortcuts \"$TODO\"\n+\ttodo_check || WHY=todo die_to_continue \"TODO file contains errors.\"\n+\n+\tcomment_for_reflog continue\n+\n+\tgit rev-parse --verify HEAD >/dev/null ||\n+\t\tdie_to_continue 'Cannot read HEAD'\n+\n+\tget_saved_options\n+\tif test -z \"$ALLOW_DIRTY\"\n+\tthen\n+\t\tgit update-index --ignore-submodules --refresh &&\n+\t\t\tgit diff-files --quiet --ignore-submodules ||\n+\t\t\tdie_to_continue 'Working tree is dirty. (Use git add or git stash first?)'\n+\tfi\n+\n+\t# do we have anything to commit? (staged changes)\n+\tif ! git diff-index --cached --quiet --ignore-submodules HEAD --\n+\tthen\n+\t\tget_current_author\n+\n+\t\t# After \"pause\", we should amend (merge-safe!).\n+\t\t# On conflict, we do not have a commit to amend, so we\n+\t\t# should just commit.\n+\t\tcase \"$WHY\" in\n+\t\tpause|run)\n+\t\t\twith_author git commit --amend --no-verify -F \"$MSG\" -e ||\n+\t\t\t\tdie_to_continue 'Could not commit staged changes.'\n+\t\t\t;;\n+\t\tconflict)\n+\t\t\twith_author git commit --no-verify -F \"$MSG\" -e ||\n+\t\t\t\tdie_to_continue 'Could not commit staged changes.'\n+\t\t\techo '# resolved CONFLICTS of the last instruction' >>\"$DONE\"\n+\t\t\t;;\n+\t\t*)\n+\t\t\tdie_to_continue 'There are staged changes. Do not know what to do with them.'\n+\t\tesac\n+\tfi\n+\n+\trequire_clean_work_tree\n+\tclean_why\n+\texecute_rest\n+\texit\n+}\n+\n+# Realize --abort.\n+do_abort () {\n+\ttest -d \"$SEQ_DIR\" || die 'No sequencer running'\n+\ttest_caller 'abort'\n+\tget_saved_options\n+\n+\tcomment_for_reflog abort\n+\tperform git rerere clear\n+\trestore\n+\tcleanup\n+\texit\n+}\n+\n+# Realize --skip.\n+do_skip () {\n+\ttest -d \"$SEQ_DIR\" || die 'No sequencer running'\n+\ttest_caller 'skip'\n+\n+\texpand_shortcuts \"$TODO\"\n+\ttodo_check || WHY=todo die_to_continue \"TODO file contains errors.\"\n+\tget_saved_options\n+\n+\tcomment_for_reflog skip\n+\tperform git rerere clear\n+\tclean_why\n+\n+\treset_almost_hard \"$(cat \"$SEQ_DIR/skiphead\")\" &&\n+\techo '# SKIPPED the last instruction' >>\"$DONE\" &&\n+\t\texecute_rest\n+\texit\n+}\n+\n+# Realize --edit.\n+do_edit () {\n+\ttest -d \"$SEQ_DIR\" || die 'No sequencer running'\n+\n+\tmarkline='### BEGIN EDITING BELOW THIS LINE ###'\n+\tprepare_editable_todo >\"$TODO.new\"\n+\tif todo_has_changed \"$TODO\"\n+\tthen\n+\t\tsane=\n+\telse\n+\t\tsane=t\n+\t\ttodo_ack \"$TODO.new\"\n+\tfi\n+\n+\t# XXX: does not make sense\n+\t#      when input does not come from a terminal\n+\tgit_editor \"$TODO.new\" ||\n+\t\tdie 'Editor returned an error.'\n+\n+\tif test -t 0 -a -t 1\n+\tthen\n+\t\tsane=t\n+\t\techo\n+\t\t# interactive:\n+\t\tuntil has_action \"$TODO.new\" && todo_check \"$TODO.new\"\n+\t\tdo\n+\t\t\thas_action \"$TODO.new\" || echo 'TODO file empty.'\n+\t\t\tprintf 'What to do with the file? [c]orrect/[e]dit again/[r]ewind/[s]ave/[?] '\n+\t\t\tread reply\n+\t\t\tcase \"$reply\" in\n+\t\t\t[cC]*)\n+\t\t\t\tgit_editor \"$TODO.new\"\n+\t\t\t\texpand_shortcuts \"$TODO.new\"\n+\t\t\t\t;;\n+\t\t\t[eE]*)\n+\t\t\t\tprepare_editable_todo >\"$TODO.new\"\n+\t\t\t\tgit_editor \"$TODO.new\"\n+\t\t\t\texpand_shortcuts \"$TODO.new\"\n+\t\t\t\t;;\n+\t\t\t[rRxXqQ]*)\n+\t\t\t\trm -f \"$TODO.new\" \"$TODO.new.sum\"\n+\t\t\t\texit 0\n+\t\t\t\t;;\n+\t\t\t[sS]*)\n+\t\t\t\ttest \"$WHY\" != 'pause' ||\n+\t\t\t\t\techo 'todo' >\"$WHY_FILE\"\n+\t\t\t\tsane=\n+\t\t\t\tbreak\n+\t\t\t\t;;\n+\t\t\t[?hH]*)\n+\t\t\t\tcat <<EOF\n+\n+Help:\n+s - save TODO file and exit\n+c - respawn editor to correct TODO file\n+e - drop changes and respawn editor on original TODO file\n+r - drop changes and exit as if nothing happened\n+? - print this help\n+EOF\n+\t\t\t\t;;\n+\t\t\tesac\n+\t\t\techo\n+\t\tdone\n+\telse\n+\t\t# defaults:\n+\t\thas_action \"$TODO.new\" || {\n+\t\t\techo \"Nothing to do\"\n+\t\t\texit\n+\t\t}\n+\t\ttodo_check \"$TODO.new\" ||\n+\t\t\tdie 'TODO file contains errors. Aborting.'\n+\tfi\n+\tcp \"$TODO\" \"$TODO.old\"\n+\tif grep \"^$markline\" \"$TODO.new\" >/dev/null\n+\tthen\n+\t\tsed -e \"1,/^$markline/d\" <\"$TODO.new\" >\"$TODO\"\n+\telse\n+\t\tcp \"$TODO.new\" \"$TODO\"\n+\tfi\n+\trm -f \"$TODO.new\" \"$TODO.new.sum\"\n+\ttest -z \"$sane\" || todo_ack \"$TODO\"\n+\techo\n+\techo 'TODO file contains:'\n+\techo\n+\tcat \"$TODO\"\n+\texit 0\n+}\n+\n+# Realize --status.\n+do_status () {\n+\ttest -d \"$SEQ_DIR\" || die 'No sequencer running.'\n+\tget_saved_options\n+\n+\tif has_action \"$DONE\"\n+\tthen\n+\t\techo 'Already done (or tried):'\n+\t\tsed -e 's/^/  /' <\"$DONE\"\n+\t\techo\n+\tfi\n+\tcase \"$WHY\" in\n+\tpause)\n+\t\techo 'Intentionally paused.'\n+\t\t;;\n+\trun)\n+\t\techo 'Interrupted because running failed.'\n+\t\t;;\n+\tconflict)\n+\t\techo 'Interrupted by conflict at'\n+\t\tsed -n -e 's/^/  /;$p' <\"$DONE\"\n+\t\t;;\n+\ttodo)\n+\t\techo 'Interrupted because of errors in the TODO file.'\n+\t\t;;\n+\t*)\n+\t\techo 'Current state is broken.'\n+\tesac\n+\ttest \"$VERBOSE\" -gt 1 && echo 'Running verbosely.'\n+\ttest \"$VERBOSE\" -lt 1 && echo 'Running quietly.'\n+\ttest -n \"$ONTO\" &&\n+\t\techo \"Sequencing on branch ${ONTO##*/}.\"\n+\tif has_action \"$TODO\"\n+\tthen\n+\t\techo\n+\n+\t\techo 'Still to do:'\n+\t\tsed -e 's/^/  /' <\"$TODO\"\n+\tfi\n+\tif test \"$WHY\" = todo\n+\tthen\n+\t\techo\n+\t\techo 'But there are errors. To edit, run:'\n+\t\techo '    git sequencer --edit'\n+\telse\n+\t\techo\n+\t\techo 'To abort & restore, invoke:'\n+\t\techo \"    $(print_caller --abort)\"\n+\t\techo 'To continue, invoke:'\n+\t\techo \"    $(print_caller --continue)\"\n+\t\ttest \"$WHY\" = 'pause' -o \"$WHY\" = 'run' || {\n+\t\t\techo 'To skip the current instruction, invoke:'\n+\t\t\techo \"    $(print_caller --skip)\"\n+\t\t}\n+\tfi\n+\texit 0\n+}\n+\n+is_standalone () {\n+\ttest $# -eq 2 &&\n+\ttest \"$2\" = '--' &&\n+\ttest -z \"$ALLOW_DIRTY\" &&\n+\ttest -z \"$BATCHMODE\" &&\n+\ttest \"$ADVICE\" = t &&\n+\ttest -z \"$onto\" &&\n+\ttest \"$VERBOSE\" -eq 1\n+}\n+\n+\n+### Option handling and startup\n+\n+onto=\n+BATCHMODE=\n+ALLOW_DIRTY=\n+CALLERSTRING=\n+VERBOSE=1\n+ADVICE=t\n+CALLER=\n+CALLER_ABRT=\n+CALLER_CONT=\n+CALLER_SKIP=\n+while test $# -gt 0\n+do\n+\tcase \"$1\" in\n+\t--continue)\n+\t\tis_standalone \"$@\" || usage\n+\t\tassure_caller\n+\t\tdo_continue\n+\t\t;;\n+\t--abort)\n+\t\tis_standalone \"$@\" || usage\n+\t\tassure_caller\n+\t\tdo_abort\n+\t\t;;\n+\t--skip)\n+\t\tis_standalone \"$@\" || usage\n+\t\tassure_caller\n+\t\tdo_skip\n+\t\t;;\n+\t--status)\n+\t\tis_standalone \"$@\" || usage\n+\t\tassure_caller\n+\t\tdo_status\n+\t\t;;\n+\t--edit)\n+\t\tis_standalone \"$@\" || usage\n+\t\tdo_edit\n+\t\t;;\n+\t--caller)\n+\t\t###############################################################\n+\t\t# This feature is for user scripts only. (Hence undocumented.)\n+\t\t# User scripts should pass an argument like:\n+\t\t# --caller=\"git foo|abrt|go|next\"\n+\t\t# on every git sequencer call. (It is only ignored on\n+\t\t# --edit and --status.)\n+\t\t# So git sequencer knows that\n+\t\t# \"git foo abrt\" will abort,\n+\t\t# \"git foo go\" will continue and\n+\t\t# \"git foo next\" will skip the sequencing process.\n+\t\t# This is useful if your user script does some extra\n+\t\t# preparations or cleanup before/after calling\n+\t\t#   git sequencer --caller=\"...\" --abort|--continue|--skip\n+\t\t#\n+\t\t# Running git-sequencer without the same --caller string\n+\t\t# fails then, until the sequencing process has finished or\n+\t\t# aborted.\n+\t\t#\n+\t\t# Btw, --caller=\"my_tiny_script.sh|-a||\" will be\n+\t\t# interpreted, that users must invoke \"my_tiny_script.sh -a\"\n+\t\t# to abort, but can invoke \"git sequencer --continue\" and\n+\t\t# \"git sequencer --skip\" to continue or skip.\n+\t\t# And it is also possible to provide three different scripts\n+\t\t# by --caller=\"|script 1|tool 2|util 3\".\n+\t\t#\n+\t\t# If your user script does not need any special\n+\t\t# abort/continue/skip behavior, then just do NOT pass\n+\t\t# the --caller option.\n+\t\t###############################################################\n+\t\tshift\n+\t\texpr \"x$1\" : 'x.*|.*|.*|.*$' >/dev/null ||\n+\t\t\tdie 'Wrong --caller format.'\n+\t\tCALLERSTRING=\"$1\"\n+\t\t;;\n+\t--allow-dirty)\n+\t\tALLOW_DIRTY='HEAD'\n+\t\t# this means: true\n+\t\t;;\n+\t-B)\n+\t\tBATCHMODE=t\n+\t\t# XXX: we still have abort on editor invokations\n+\t\t;;\n+\t--no-advice)\n+\t\tADVICE=f\n+\t\t;;\n+\t--onto)\n+\t\tshift\n+\t\tONTO=\"$1\"\n+\t\ttest $(git cat-file -t \"$ONTO\") = 'commit' ||\n+\t\t\tdie \"$ONTO is no commit or branch.\"\n+\t\t;;\n+\t-q)\n+\t\tVERBOSE=0\n+\t\tADVICE=f\n+\t\t# XXX: If there were no editors,\n+\t\t# we could just do exec >/dev/null\n+\t\t;;\n+\t-v)\n+\t\tVERBOSE=2\n+\t\t# or increment it if we have several verbosity steps\n+\t\t;;\n+\t--)\n+\t\tshift\n+\t\tbreak\n+\t\t;;\n+\t*)\n+\t\tdie \"$1 currently not implemented.\"\n+\t\t;;\n+\tesac\n+\tshift\n+done\n+test $# -gt 1 && usage\n+\n+do_startup \"$1\"\n-- \n1.6.0.rc0.49.gd39f\n"},{"id":"85013","messageId":"1217049644-8874-3-git-send-email-s-beyer@gmx.net","threadId":"14685","inReplyTo":"1217049644-8874-2-git-send-email-s-beyer@gmx.net","subject":"[PATCH 2/5] Add git-sequencer documentation","fromName":"Stephan Beyer","fromEmail":"s-beyer@gmx.net","sentAt":"2008-07-26T05:20:41Z","receivedAt":"2008-07-26T05:20:41Z","isPatch":true,"sender":{"key":"s-beyer@gmx.net","avatar":"https://avatars.githubusercontent.com/u/143889?v=4"},"body":"Mentored-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-sequencer.txt |  676 +++++++++++++++++++++++++++++++++++++++\n 1 files changed, 676 insertions(+), 0 deletions(-)\n create mode 100644 Documentation/git-sequencer.txt\n\ndiff --git a/Documentation/git-sequencer.txt b/Documentation/git-sequencer.txt\nnew file mode 100644\nindex 0000000..04fea2c\n--- /dev/null\n+++ b/Documentation/git-sequencer.txt\n@@ -0,0 +1,676 @@\n+git-sequencer(1)\n+================\n+\n+NAME\n+----\n+git-sequencer - Execute a sequence of git instructions\n+\n+SYNOPSIS\n+--------\n+[verse]\n+'git sequencer' [--batch] [--onto=<base>] [--allow-dirty]\n+\t\t[--verbose | --no-advice | --quiet]\n+\t\t[--] [<file>]\n+'git sequencer' --continue | --skip | --abort | --edit | --status\n+\n+\n+DESCRIPTION\n+-----------\n+Executes a sequence of git instructions to HEAD or `<base>`.\n+The sequence is given by `<file>` or standard input.\n+Also see 'TODO FILE FORMAT' below.\n+\n+Before doing anything, the TODO file is checked for correct syntax\n+and sanity.\n+\n+In case of a conflict or request in the TODO file, 'git-sequencer' will\n+pause. On conflict you can use 'git-diff' to locate the markers (`<<<<<<<`)\n+and make edits to resolve the conflict.\n+\n+For each file you edit, you need to tell git the changes by doing\n+\n+    git add <file>\n+\n+After resolving the conflict manually and updating the index with the\n+desired resolution, you can continue the sequencing process with\n+\n+    git sequencer --continue\n+\n+Alternatively, you can undo the 'git-sequencer' progress with\n+\n+    git sequencer --abort\n+\n+or skip the current instruction with\n+\n+    git sequencer --skip\n+\n+or correct the TODO file with\n+\n+    git sequencer --edit\n+\n+During pauses or when finished with the sequencing task, the current\n+HEAD will always be the result of the last processed instruction.\n+\n+\n+OPTIONS\n+-------\n+<file>::\n+\tFilename of the TODO file.  If omitted, standard input is used.\n+\tSee 'TODO FILE FORMAT' below.\n+\n+--allow-dirty::\n+\tRun even if working tree is dirty.\n+\n+-B::\n+--batch::\n+\tRun in batch mode. If unexpected user intervention is needed\n+\t(e.g. a conflict or the need to run an editor), 'git-sequencer' fails.\n++\n+Note that the sanity check fails, if you use this option\n+and an instruction like `edit` or `pause` is in the TODO file.\n+\n+--onto=<base>::\n+\tCheckout given commit or branch before sequencing.\n+\tIf you provide a branch, sequencer will make the provided\n+\tchanges on the branch, i.e. the branch will be changed.\n+\n+--continue::\n+\tRestart the sequencing process after having resolved a merge conflict.\n+\n+--abort::\n+\tRestore the original branch and abort the sequence operation.\n+\n+--skip::\n+\tRestart the sequencing process by skipping the current instruction.\n+\n+--status::\n+\tShow the current status of 'git-sequencer' and what\n+\toperations can be done to change that status.\n+\n+--edit::\n+\tInvoke editor to edit the unprocessed part of the TODO file.\n++\n+The file is syntax- and sanity-checked afterwards, so that you can\n+safely run `git sequencer --skip` or `--continue` after editing.\n+If you nonetheless noticed that you made a mistake, you can\n+overwrite `.git/sequencer/todo` with `.git/sequencer/todo.old` and\n+rerun `git sequencer --edit`.\n++\n+If the check fails you are prompted if you want to correct your\n+changes, edit again, cancel editing or really want to save.\n+\n+--no-advice::\n+\tSuppress advice on intentional and unintentional pauses.\n+\n+-q::\n+--quiet::\n+\tSuppress output. Implies `--no-advice`.\n+\t(Not yet implemented.)\n+\n+-v::\n+--verbose::\n+\tBe more verbose.\n+\n+\n+NOTES\n+-----\n+\n+When sequencing, it is possible, that you are changing the history of\n+a branch in a way that can cause problems for anyone who already has\n+a copy of the branch in their repository and tries to pull updates from\n+you.  You should understand the implications of using 'git-sequencer' on\n+a repository that you share.\n+\n+'git-sequencer' will usually be called by another git porcelain, like\n+linkgit:git-am[1] or linkgit:git-rebase[1].\n+\n+\n+TODO FILE FORMAT\n+----------------\n+\n+The TODO file contains basically one instruction per line.\n+\n+Blank lines will be ignored.\n+All characters after a `#` character will be ignored until the end of a line.\n+\n+The following instructions can be used:\n+\n+\n+edit <commit>::\n+\tPick a commit and pause the sequencer process to let you\n+\tmake changes.\n++\n+This is a short form for `pick <commit> and `pause` on separate lines.\n+\n+\n+mark <mark>::\n+\tSet a symbolic mark for the last commit.\n+\t`<mark>` is an unsigned integer starting at 1 and\n+\tprefixed with a colon, e.g. `:1`.\n++\n+The marks can help if you want to refer to commits that you\n+created during the sequencer process, e.g. if you want to\n+merge such a commit.\n++\n+The set marks are removed after the sequencer has completed.\n+\n+\n+merge [options] <commit-ish1> <commit-ish2> ... <commit-ishN>::\n+\tMerge commits into HEAD.\n++\n+You can refer to a commit by a mark.\n++\n+If you do not provide a commit message (using `-F`, `-m`, `-C`, `-M`,\n+or `--standard`), an editor will be invoked.\n++\n+See the following list and 'GENERAL OPTIONS' for values of `options`:\n+\n+\t--standard;;\n+\t\tGenerate a commit message like 'Merge ... into HEAD'.\n+\t\tSee also linkgit:git-fmt-merge-msg[1].\n+\n+\t-s <strategy>;;\n+\t--strategy=<strategy>;;\n+\t\tUse the given merge strategy.\n+\t\tSee also linkgit:git-merge[1].\n+\n+\n+pick [options] <commit>::\n+\tPick (see linkgit:git-cherry-pick[1]) a commit.\n+\tSequencer will pause on conflicts.\n++\n+See the following list and 'GENERAL OPTIONS' for values of `options`:\n+\n+\t-R;;\n+\t--reverse;;\n+\t\tRevert the changes introduced by pick <commit>.\n+\n+\t--mainline=<n>;;\n+\t\tAllow you to pick merge commits by specifying the\n+\t\tparent number (beginning from 1) to let sequencer\n+\t\treplay the changes relative to the specified parent.\n+\t\t+\n+This option does not work together with `-R`.\n+\n+\n+patch [options] <file>::\n+\tIf file `<file>` is a pure (diff) patch, then apply the patch.\n+\tIf no `--message` option is given, an editor will\n+\tbe invoked to enter a commit message.\n++\n+If `<file>` is a linkgit:git-format-patch[1]-formatted patch,\n+then the patch will be commited.\n++\n+See the following list and 'GENERAL OPTIONS' for values of `options`:\n+\n+\t-3;;\n+\t--3way;;\n+\t\tWhen the patch does not apply cleanly, fall back on\n+\t\t3-way merge, if the patch records the identity of blobs\n+\t\tit is supposed to apply to, and we have those blobs\n+\t\tavailable locally.\n+\n+\t-k;;\n+\t\tPass `-k` flag to 'git-mailinfo' (see linkgit:git-mailinfo[1]).\n+\n+\t-n;;\n+\t\tPass `-n` flag to 'git-mailinfo' (see linkgit:git-mailinfo[1]).\n+\n+\t--exclude=<path-pattern>;;\n+\t\tDo not apply changes to files matching the given path pattern.\n+\t\tThis can be useful when importing patchsets, where you want to\n+\t\texclude certain files or directories.\n+\n+\t-R;;\n+\t--reverse;;\n+\t\tApply the patch in reverse.\n+\n+\t--no-add;;\n+\t\tWhen applying a patch, ignore additions made by the\n+\t\tpatch.  This can be used to extract the common part between\n+\t\ttwo files by first running 'diff' on them and applying\n+\t\tthe result with this option, which would apply the\n+\t\tdeletion part but not addition part.\n+\n+\t--whitespace=<action>;;\n+\t\tSpecify behavior on whitespace errors.\n+\t\tSee linkgit:git-apply[1] for a detailed description.\n+\n+\t--context=<n>;;\n+\t\tEnsure at least <n> lines of surrounding context match before\n+\t\tand after each change.  When fewer lines of surrounding\n+\t\tcontext exist they all must match.  By default no context is\n+\t\tever ignored.\n+\n+\t--inaccurate-eof;;\n+\t\tUnder certain circumstances, some versions of 'diff' do not\n+\t\tcorrectly detect a missing new-line at the end of the file.\n+\t\tAs a result, patches created by such 'diff' programs do not\n+\t\trecord incomplete lines correctly.\n+\t\tThis option adds support for applying such patches by\n+\t\tworking around this bug.\n+\n+\t-p<n>;;\n+\t\tRemove <n> leading slashes from traditional diff paths.\n+\t\tThe default is 1.\n+\n+\t--unidiff-zero;;\n+\t\tBy default, 'git-apply' expects that the patch being\n+\t\tapplied is a unified diff with at least one line of context.\n+\t\tThis provides good safety measures, but breaks down when\n+\t\tapplying a diff generated with --unified=0. To bypass these\n+\t\tchecks use this option.\n+\n+\n+pause::\n+\tPause the sequencer process to let you manually make changes.\n+\tFor example, you can re-edit the done commit, split a commit,\n+\tfix bugs or typos, or make further commits on top of HEAD before\n+\tcontinuing.\n++\n+After you have finished your changes and added them to the index,\n+invoke `git sequencer --continue`.\n+If you only want to edit the last commit message with an editor,\n+run `git commit --amend` (see linkgit:git-commit[1]) before saying\n+`--continue`.\n+\n+\n+ref <ref>::\n+\tSet ref `<ref>` to the current HEAD, see also\n+\tlinkgit:git-update-ref[1].\n+\n+\n+reset <commit-ish>::\n+\tGo back (see linkgit:git-reset[1] `--hard`) to commit `<commit-ish>`.\n+\t`<commit-ish>` can also be given by a mark, if prefixed with a colon.\n+\n+\n+squash [options] <commit>::\n+\tAdd the changes introduced by `<commit>` to the last commit.\n++\n+See 'GENERAL OPTIONS' for values of `options`.\n+\n+squash [options] --from <mark>::\n+\tSquash all commits from the given mark into one commit.\n+\tThere must not be any `merge` instructions between the\n+\t`mark` instruction and this `squash --from` instruction.\n++\n+See the following list and 'GENERAL OPTIONS' for values of `options`:\n+\n+\t--collect-signoffs;;\n+\t\tCollect the Signed-off-by: lines of each commit and\n+\t\tadd them to the squashed commit message.\n+\t\t(Not yet implemented.)\n+\n+\t--include-merges;;\n+\t\tSanity check does not fail if you have merges\n+\t\tbetween HEAD and <mark>.\n+\n+\n+run [--dir=<path>] [--] <cmd> <args>...::\n+\tRun command `<cmd>` with arguments `<args>`.\n+\tPause (conflict-like) if exit status is non-zero.\n++\n+If `<path>` is set, sequencer will change directory to `<path>`\n+before running the command and change back after exit.\n+\n+\n+GENERAL OPTIONS\n+---------------\n+\n+Besides some special options, the instructions\n+`patch`, `merge`, `pick`, `squash` take the following general options:\n+\n+--author=<author>::\n+\tOverride the author name and e-mail address used in the commit.\n+\tUse `A U Thor <author@example.com>` format.\n+\n+-C <commit-ish>::\n+--reuse-commit=<commit-ish>::\n+\tReuse message and authorship data from specified commit.\n+\n+-M <commit-ish>\n+--reuse-message=<commit-ish>::\n+\tReuse message from specified commit.\n+\tNote, that only the commit message is reused\n+\tand not the authorship information.\n+\n+-F <file>::\n+--file=<file>::\n+\tTake the commit message from the given file.\n+\n+-m <msg>::\n+--message=<msg>::\n+\tUse the given `<msg>` as the commit message.\n+\n+--signoff::\n+\tAdd `Signed-off-by:` line to the commit message (if not yet there),\n+\tusing the committer identity of yourself.\n+\n+-e::\n+--edit::\n+\tRegardless what commit message options are given,\n+\tinvoke the editor to allow editing of the commit message.\n+\n+\n+RETURN VALUES\n+-------------\n+\n+'git-sequencer' returns:\n+\n+* `0`, if 'git-sequencer' successfully completed all the instructions\n+       in the TODO file or successfully aborted after\n+       `git sequencer --abort`,\n+* `2`, on user-requested pausing, e.g.\n+       when using the `edit` instruction.\n+* `3`, on pauses that are not requested, e.g.\n+       when there are conflicts to resolve\n+       or errors in the TODO file.\n+* any other value on error, e.g.\n+  running 'git-sequencer' on a bare repository.\n+\n+\n+EXAMPLES\n+--------\n+\n+Here are some examples that shall ease the start with the TODO\n+file format.\n+Make sure you have understood the `pick` and perhaps the `patch` command.\n+Those will not be explained further.\n+\n+Manually editing and adding commits\n+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n+\n+Sequencer allows manual intervention in between.\n+This can be useful to\n+\n+* check if everything has gone right so far,\n+\n+* split commits,\n+\n+* edit changes and/or commit messages, or\n+\n+* add further manual commits on top of the current one.\n+\n+If you want to do one of this, either change `pick` to `edit`, or\n+add a `pause` line after the specific instruction.\n+\n+Note that if you only want to edit the commit message in an\n+editor, just use the `--edit` option of your `pick` or `patch`\n+instruction.\n+\n+`HEAD` refers to the last commit being done by sequencer.\n+So if you want to split a commit, repeat something like\n+\n+------------\n+$ git reset HEAD^   # Reset index to HEAD^, but keep working tree\n+\t\t    # HEAD is the last commit being done by sequencer\n+$ git add -p        # Add changes interactively to the index, and/or\n+$ git add file1     # Add changes from file1 to the index\n+$ git commit        # Commit staged changes\n+------------\n+\n+until you have no changes to commit, and then run\n+\n+------------\n+$ git sequencer --continue   # Continue sequencer process\n+------------\n+\n+Be aware that if there are still staged changes,\n+'git-sequencer' will add those changes to the last commit being done.\n+\n+\n+Squashing commits\n+~~~~~~~~~~~~~~~~~\n+\n+Squashing commits means putting the changes of many commits into one.\n+If you have two commits `abcdef1` and `fa1afe1` and you want to squash them,\n+feed 'git-sequencer' with a TODO file like:\n+\n+------------\n+pick abcdef1\n+squash fa1afe1\n+------------\n+\n+Squash will concatenate the commit messages of `abcdef1` and `fa1afe1` and\n+invoke an editor so that you can edit them.\n+Perhaps you just want to reuse the commit message of `abcdef1` and\n+add a signoff.  Then use:\n+\n+------------\n+pick abcdef1\n+squash -C abcdef1 --signoff fa1afe1\n+------------\n+\n+You can also squash more than two commits.\n+Basically you can do:\n+\n+------------\n+pick A\n+squash B\n+squash C\n+squash D\n+squash --message \"Make indentation consistent\" --signoff E\n+------------\n+\n+If somebody sent you a patch that you have not yet applied and you want\n+to apply it and squash it, or if you have a `pick <commit>` list generated\n+with something like\n+\n+------------\n+$ git rev-list --no-merges --reverse A^..E | sed -e 's/^/pick /'`\n+------------\n+\n+you can use the `mark` and `squash --from` instructions to\n+squash all commits between them into one:\n+\n+------------\n+mark :0\n+pick A\n+pick B\n+pick C\n+pick D\n+pick E\n+squash --message \"Make indentation consistent\" --signoff --from :0\n+------------\n+\n+\n+Branching and Merging\n+~~~~~~~~~~~~~~~~~~~~~\n+\n+Merging branches can easily be done using the `merge` instruction.\n+For an example, it is more interesting to branch, pick some commits\n+and merge.  Imagine you want to 'copy' this onto the current branch:\n+\n+------------\n+ ...--A1--A2--A3--A4--A5---MA-A6  refs/heads/old\n+       |       \\          /\n+       |        C1--MC--C2  refs/heads/topic\n+\t\\          /\n+\t B1--B2--B3\n+------------\n+\n+You want the copy to look exactly like this, except that you\n+are not on branch `old`, and you want to call the copy of `topic`\n+simply `topic2`.\n+Here is a way to achieve this:\n+\n+------------\n+pick A1\n+mark :0    # remember this to pick further commits on trunk A\n+\n+pick B1    # pick commits for trunk B\n+pick B2\n+pick B3\n+mark :1    # remember this for merge\n+# Why not just merge B3 later?\n+# Then you would merge the original B3 and not the copy.\n+# But in this example you want to merge the copy of B3.\n+\n+reset :0   # go back to the copy of A1\n+pick A2    # go on picking the commits of trunk A\n+pick A3\n+mark :2    # remember this to pick further commits on trunk A\n+\n+pick C1    # pick commits for trunk C\n+merge -C MC :1    # merge trunk B\n+pick C2\n+ref refs/heads/topic2    # create branch for the C trunk\n+\n+reset :2   # go back to last commit of trunk A (copy of A3)\n+pick A4    # go on picking the commits of trunk A\n+pick A5\n+merge --standard topic2   # merge trunk C\n+pick A6\n+------------\n+\n+\n+Proper handling of conflicts\n+~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n+\n+First of all, you are encouraged to use linkgit:git-rerere[1]:\n+\n+------------\n+$ git config rerere.enabled true    # enable rerere\n+------------\n+\n+Sequencer invokes 'git-rerere' automatically on conflict.\n+\n+If you experience conflicts, try\n+\n+------------\n+$ git diff     # Show conflicting code\n+$ git status   # Show conflicting files\n+------------\n+\n+Then fix these conflicts using your editor and run\n+\n+------------\n+$ git add file1 file2 file3   # Add modified files to the index\n+$ git status                  # Make sure working tree is clean\n+$ git sequencer --continue    # Continue sequencer process\n+------------\n+\n+Now assume a conflict happens because you have unproperly edited\n+the TODO file.\n+\n+Imagine your initial TODO file was:\n+\n+------------\n+pick A\n+pick C\n+pick D\n+------------\n+\n+But you wanted to pick B before C, and now you have this conflict on\n+picking C.  You may first have a look at:\n+\n+------------\n+$ git sequencer --status\n+------------\n+\n+This will show you, what has been done, in what step the conflict\n+happened and what is still to do, like this:\n+\n+------------\n+Already done (or tried):\n+  pick A\n+  pick C\n+\n+Interrupted by conflict at\n+  pick C\n+\n+Still to do:\n+  pick D\n+\n+To abort & restore, invoke:\n+    git sequencer --abort\n+To continue, invoke:\n+    git sequencer --continue\n+To skip the current instruction, invoke:\n+    git sequencer --skip\n+------------\n+\n+A good way to solve that situation is running\n+\n+------------\n+$ git sequencer --edit\n+------------\n+\n+and change the file to:\n+\n+------------\n+pick B\n+pick C\n+pick D\n+------------\n+\n+Save the file, and invoke:\n+\n+------------\n+$ git sequencer --skip\n+------------\n+\n+Then the conflict-ridden `pick C` will be skipped and B is picked,\n+before C will again be picked.\n+\n+\n+Running tests\n+~~~~~~~~~~~~~\n+\n+Imagine you have test programs within a `tests/` directory in your working\n+tree.  But before running your test programs, you have to invoke `make` in\n+the root directory of the working tree to compile your project.\n+\n+If the commit policy of your project says that after every commit the\n+software must be able to compile and the test suite must pass, you\n+are required to check this after every pick.\n+\n+This example shows how 'git-sequencer' can assist you:\n+\n+------------\n+pick A      # Fix foo\n+run make\n+run --dir=tests ./test-foo\n+pick B      # Extend bar\n+run make\n+run --dir tests -- ./test-bar --expensive-tests\n+pick C\n+run make\n+run --dir tests make tests\n+------------\n+\n+Sequencer will be paused, when a run fails (i.e. on non-zero exit status).\n+Then it is your turn to fix the problem and make the tests pass.\n+\n+Note, that on `git sequencer --continue`, 'git-sequencer' will not\n+repeat the failed `run` instruction.\n+\n+\n+SEE ALSO\n+--------\n+\n+linkgit:git-add[1],\n+linkgit:git-am[1],\n+linkgit:git-cherry-pick[1],\n+linkgit:git-commit[1],\n+linkgit:git-fmt-merge-msg[1],\n+linkgit:git-format-patch[1],\n+linkgit:git-rebase[1],\n+linkgit:git-rerere[1],\n+linkgit:git-reset[1],\n+linkgit:git-update-ref[1]\n+\n+\n+Authors\n+-------\n+Written by Stephan Beyer <s-beyer@gmx.net>.\n+\n+\n+Documentation\n+-------------\n+Documentation by Stephan Beyer and the git-list <git@vger.kernel.org>.\n+\n+GIT\n+---\n+Part of the linkgit:git[1] suite\n-- \n1.6.0.rc0.49.gd39f\n"},{"id":"85010","messageId":"1217049644-8874-4-git-send-email-s-beyer@gmx.net","threadId":"14685","inReplyTo":"1217049644-8874-3-git-send-email-s-beyer@gmx.net","subject":"[PATCH 3/5] Add git-sequencer test suite (t3350)","fromName":"Stephan Beyer","fromEmail":"s-beyer@gmx.net","sentAt":"2008-07-26T05:20:42Z","receivedAt":"2008-07-26T05:20:42Z","isPatch":true,"sender":{"key":"s-beyer@gmx.net","avatar":"https://avatars.githubusercontent.com/u/143889?v=4"},"body":"Mentored-by: Christian Couder <chriscool@tuxfamily.org>\nMentored-by: Daniel Barkalow <barkalow@iabervon.org>\nSigned-off-by: Stephan Beyer <s-beyer@gmx.net>\n---\n t/t3350-sequencer.sh |  838 ++++++++++++++++++++++++++++++++++++++++++++++++++\n 1 files changed, 838 insertions(+), 0 deletions(-)\n create mode 100755 t/t3350-sequencer.sh\n\ndiff --git a/t/t3350-sequencer.sh b/t/t3350-sequencer.sh\nnew file mode 100755\nindex 0000000..3cc7da8\n--- /dev/null\n+++ b/t/t3350-sequencer.sh\n@@ -0,0 +1,838 @@\n+#!/bin/sh\n+#\n+# Copyright (c) 2008 Stephan Beyer\n+#\n+# `setup' is based on t3404* by Johannes Schindelin.\n+\n+test_description='git sequencer\n+\n+These are basic usage tests for git sequencer.\n+'\n+. ./test-lib.sh\n+\n+# set up two branches like this:\n+#\n+# A - B - C - D - E\n+#   \\\n+#     F - G - H\n+#       \\\n+#         I\n+#\n+# where B, D and G touch increment value in file1.\n+# The others generate empty file[23456].\n+\n+SEQDIR=\".git/sequencer\"\n+SEQMARK=\"refs/sequencer-marks\"\n+MARKDIR=\".git/$SEQMARK\"\n+\n+test_expect_success 'setup' '\n+\t: >file1 &&\n+\tgit add file1 &&\n+\ttest_tick &&\n+\tgit commit -m \"generate empty file1\" &&\n+\tgit tag A &&\n+\techo 1 >file1 &&\n+\ttest_tick &&\n+\tgit commit -m \"write 1 into file1\" file1 &&\n+\tgit tag B &&\n+\t: >file2 &&\n+\tgit add file2 &&\n+\ttest_tick &&\n+\tgit commit -m \"generate empty file2\" &&\n+\tgit tag C &&\n+\techo 2 >file1 &&\n+\ttest_tick &&\n+\tgit commit -m \"write 2 into file1\" file1 &&\n+\tgit tag D &&\n+\t: >file3 &&\n+\tgit add file3 &&\n+\ttest_tick &&\n+\tgit commit -m \"generate empty file3\" &&\n+\tgit tag E &&\n+\tgit checkout -b branch1 A &&\n+\t: >file4 &&\n+\tgit add file4 &&\n+\ttest_tick &&\n+\tgit commit -m \"generate empty file4\" &&\n+\tgit tag F &&\n+\techo 3 >file1 &&\n+\ttest_tick &&\n+\tgit commit -m \"write 3 into file1\" file1 &&\n+\tgit tag G &&\n+\t: >file5 &&\n+\tgit add file5 &&\n+\ttest_tick &&\n+\tgit commit -m \"generate empty file5\" &&\n+\tgit tag H &&\n+\tgit checkout -b branch2 F &&\n+\t: >file6 &&\n+\tgit add file6 &&\n+\ttest_tick &&\n+\tgit commit -m \"generate empty file6\" &&\n+\tgit tag I &&\n+\tgit diff -p --raw C..D >patchD.raw &&\n+\tgit diff -p --raw A..F >patchF.raw &&\n+\tgit format-patch --stdout A..B >patchB &&\n+\tgit format-patch --stdout B..C >patchC &&\n+\tgit format-patch --stdout C..D >patchD &&\n+\tgit format-patch --stdout A..F >patchF &&\n+\tgit format-patch --stdout F..G >patchG\n+'\n+\n+orig_author=\"$GIT_AUTHOR_NAME <$GIT_AUTHOR_EMAIL>\"\n+\n+# Functions to verify exit status of sequencer.\n+# Do not just use \"test_must_fail git sequencer ...\"!\n+expect_fail () {\n+\t\"$@\"\n+\ttest $? -eq 1\n+}\n+expect_continue () {\n+\t\"$@\"\n+\ttest $? -eq 2\n+}\n+expect_conflict () {\n+\t\"$@\"\n+\ttest $? -eq 3\n+}\n+\n+\n+# Other test helpers:\n+\n+# Test if commit $1 has author $2\n+expect_author () {\n+\ttest \"$2\" = \"$(git cat-file commit \"$1\" |\n+\t\tsed -n -e \"s/^author \\(.*\\)> .*$/\\1>/p\")\"\n+}\n+\n+# Test if commit $1 has commit message in file $2\n+# Side effect: overwrites actual\n+expect_msg () {\n+\tgit cat-file commit \"$1\" | sed -e \"1,/^$/d\" >actual &&\n+\ttest_cmp \"$2\" actual\n+}\n+\n+# Test that no marks are set.\n+no_marks_set () {\n+\tif test -e \"$MARKDIR\"\n+\tthen\n+\t\trmdir \"$MARKDIR\"\n+\tfi\n+}\n+\n+test_expect_success 'fail on empty TODO from stdin' '\n+\texpect_fail git sequencer <file6 &&\n+\t! test -d \"$SEQDIR\"\n+'\n+\n+# Generate fake editor\n+#\n+# Simple and practical concept:\n+#  We use only a small string identifier for \"editor sessions\".\n+#  Each sessions knows what to do and perhaps defines\n+#  which session to choose next.\n+echo \"#!$SHELL_PATH\" >fake-editor.sh\n+cat >>fake-editor.sh <<\\EOF\n+test -f fake-editor-session || exit 1\n+#test -t 1 || exit 1\n+# This test could be useful, but as the test-lib is not always\n+# verbose, this will fail.\n+next=ok\n+read this <fake-editor-session\n+case \"$this\" in\n+commitmsg)\n+\techo 'echo 2 >file1'\n+\t;;\n+squashCE)\n+\techo 'generate file2 and file3'\n+\t;;\n+squashCI)\n+\techo 'generate file2 and file6'\n+\tnext=squashDCE\n+\t;;\n+squashDCE)\n+\techo 'generate file2 and file3 and write 2 into file1'\n+\tnext=merge1\n+\t;;\n+merge1)\n+\techo 'A typed merge message.'\n+\t;;\n+merge2)\n+\ttest \"$(sed -n -e 1p \"$1\")\" = 'test merge' &&\n+\t\techo 'cleanup merge' ||\n+\t\techo error\n+\tsed -e 1d \"$1\"\n+\t;;\n+editXXXXXXXXX)\n+\tprintf 'last edited'\n+\t;;\n+edit*)\n+\tprintf 'edited: '\n+\tcat \"$1\"\n+\tnext=\"${this}X\"\n+\t;;\n+nochange)\n+\tcat \"$1\"\n+\t;;\n+ok|fail)\n+\techo '-- THIS IS UNEXPECTED --'\n+\tnext=fail\n+\t;;\n+*)\n+\techo 'I do not know.'\n+\t;;\n+esac >\"$1\".tmp\n+mv \"$1\".tmp \"$1\"\n+echo $next >fake-editor-session\n+exit 0\n+EOF\n+chmod a+x fake-editor.sh\n+test_set_editor \"$(pwd)/fake-editor.sh\"\n+\n+next_session () {\n+\techo \"$1\" >fake-editor-session\n+}\n+\n+# check if fake-editor-session is ok.\n+# If \"$1\" is set to anything, it will set the\n+# next session to \"ok\", which is nice for\n+# test_expect_failure.\n+session_ok () {\n+\ttest \"ok\" = $(cat fake-editor-session)\n+\tret=$?\n+\ttest -n \"$1\" && next_session ok\n+\treturn $ret\n+}\n+\n+\n+cat >todotest1 <<EOF\n+pick C\n+squash E\n+ref refs/tags/CE\n+EOF\n+\n+test_expect_success '\"pick\", \"squash\", \"ref\" from stdin' '\n+\tnext_session squashCE &&\n+\tgit sequencer <todotest1 &&\n+\t! test -d \"$SEQDIR\" &&\n+\tsession_ok &&\n+\ttest -f file2 &&\n+\ttest -f file3 &&\n+\ttest $(git rev-parse CE) = $(git rev-parse HEAD) &&\n+\ttest $(git rev-parse I) = $(git rev-parse HEAD^)\n+'\n+\n+cat >todotest2 <<EOF\n+# This is a test\n+\n+reset I  # go back to I\n+\n+EOF\n+\n+test_expect_success '\"reset\" from file with comments and blank lines' '\n+\tgit sequencer todotest2 &&\n+\tsession_ok &&\n+\ttest $(git rev-parse I) = $(git rev-parse HEAD)\n+'\n+\n+cat >todotest1 <<EOF\n+pick C\n+EOF\n+\n+test_expect_success '--onto <branch> keeps branch' '\n+\tgit checkout -b test-branch A &&\n+\tgit checkout master &&\n+\tgit sequencer --onto test-branch <todotest1 &&\n+\tsession_ok &&\n+\ttest \"$(git symbolic-ref -q HEAD)\" = \"refs/heads/test-branch\" &&\n+\ttest \"$(git rev-parse test-branch^)\" = \"$(git rev-parse A)\"\n+'\n+\n+test_expect_success '--onto commit (detached HEAD) works' '\n+\tgit sequencer --onto A <todotest1 &&\n+\tsession_ok &&\n+\ttest_must_fail git symbolic-ref -q HEAD &&\n+\ttest \"$(git rev-parse HEAD)\" = \"$(git rev-parse test-branch)\"\n+'\n+\n+echo 'pick -R C' >>todotest1\n+\n+test_expect_success 'pick -R works' '\n+\tgit checkout A &&\n+\tgit sequencer todotest1 &&\n+\tsession_ok &&\n+\t! test -f file2\n+'\n+\n+mkdir testdir\n+cat >testdir/script <<EOF\n+#!/bin/sh\n+test -s ../file1\n+EOF\n+chmod 755 testdir/script\n+cat >todotest1 <<EOF\n+run -- test -s file1  # this will fail\n+pick B\n+run --dir testdir -- test -s ../file1\n+pick D\n+run --dir=testdir ./script\n+EOF\n+\n+test_expect_success '\"run\" insn works' '\n+\tgit checkout A &&\n+\texpect_conflict git sequencer todotest1 &&\n+\t: >newfile &&\n+\tgit add newfile &&\n+\tnext_session nochange &&\n+\tgit sequencer --continue &&\n+\tsession_ok &&\n+\ttest -f newfile\n+'\n+\n+echo thisdoesnotexist >>todotest1\n+\n+test_expect_success 'junk is conflict' '\n+\tgit checkout A &&\n+\texpect_conflict git sequencer todotest1 &&\n+\ttest -d \"$SEQDIR\" &&\n+\tgit sequencer --abort &&\n+\t! test -d \"$SEQDIR\" &&\n+\tsession_ok &&\n+\ttest $(git rev-parse A) = $(git rev-parse HEAD)\n+'\n+\n+GIT_AUTHOR_NAME=\"Another 'ant' Thor\"\n+GIT_AUTHOR_EMAIL=\"a.thor@example.com\"\n+GIT_COMMITTER_NAME=\"Co M Miter\"\n+GIT_COMMITTER_EMAIL=\"c.miter@example.com\"\n+export GIT_AUTHOR_NAME GIT_AUTHOR_EMAIL GIT_COMMITTER_NAME GIT_COMMITTER_EMAIL\n+yet_another=\"Max Min <mm@example.com>\"\n+\n+cat >todotest1 <<EOF\n+patch patchB      # write 1 into file1\n+patch -k patchC   # generate file2\n+patch patchD.raw  # write 2 into file1\n+EOF\n+\n+echo 'write 1 into file1' >expected1\n+echo '[PATCH] generate empty file2' >expected2\n+echo 'echo 2 >file1' >expected3\n+\n+test_expect_success '\"patch\" insn works' '\n+\tgit checkout A &&\n+\tnext_session commitmsg &&\n+\tgit sequencer todotest1 &&\n+\t! test -d \"$SEQDIR\" &&\n+\tsession_ok &&\n+\ttest \"$(git rev-parse HEAD~3)\" = \"$(git rev-parse A)\" &&\n+\ttest \"$(git show HEAD~2:file1)\" = \"1\" &&\n+\ttest -z \"$(git show HEAD^:file2)\" &&\n+\ttest \"$(git show HEAD:file1)\" = \"2\" &&\n+\texpect_author HEAD~2 \"$orig_author\" &&\n+\texpect_author HEAD~1 \"$orig_author\" &&\n+\texpect_author HEAD~0 \"$GIT_AUTHOR_NAME <$GIT_AUTHOR_EMAIL>\" &&\n+\texpect_msg HEAD~2 expected1 &&\n+\texpect_msg HEAD~1 expected2 &&\n+\texpect_msg HEAD~0 expected3\n+'\n+\n+cat >todotest1 <<EOF\n+pick B\t# write 1 into file1\n+pause\n+pick C\t# generate file2\n+EOF\n+\n+echo 'generate empty file2' >expected1\n+echo 'write 1 into file1' >expected2\n+\n+test_expect_success \"pick ; pause insns and --continue works\" '\n+\tgit checkout A &&\n+\texpect_continue git sequencer todotest1 &&\n+\tsession_ok &&\n+\techo 5 >file1 &&\n+\tgit add file1 &&\n+\tnext_session nochange &&\n+\tgit sequencer --continue &&\n+\ttest \"$(git show HEAD:file1)\" = 5 &&\n+\ttest -z \"$(git show HEAD:file2)\" &&\n+\texpect_msg HEAD expected1 &&\n+\texpect_msg HEAD^ expected2 &&\n+\tsession_ok\n+'\n+\n+cat >todotest1 <<EOF\n+edit B\t# write 1 into file1\n+pick C\t# generate file2\n+EOF\n+\n+test_expect_success \"edit insn and --continue works\" '\n+\tgit checkout A &&\n+\texpect_continue git sequencer todotest1 &&\n+\tsession_ok &&\n+\techo 5 >file1 &&\n+\tgit add file1 &&\n+\tnext_session nochange &&\n+\tgit sequencer --continue &&\n+\ttest \"$(git show HEAD:file1)\" = 5 &&\n+\ttest -z \"$(git show HEAD:file2)\" &&\n+\texpect_msg HEAD expected1 &&\n+\texpect_msg HEAD^ expected2 &&\n+\tsession_ok\n+'\n+\n+cat >todotest1 <<EOF\n+patch patchB\t# write 1 into file1\n+pick H\t\t# generate file5\n+mark :1\n+patch patchC\t# generate file2\n+squash I\t# generate file6\n+patch patchD\t# write 2 into file1\n+ref refs/tags/CID\n+mark :2\n+reset :1\t# reset to new H\n+patch patchD\t# write 2 into file1\n+squash CE\t# generate file2 and file3\n+ref refs/tags/DCE\n+merge :2\t# merge :2 into HEAD\n+patch patchF\t# generate file4\n+EOF\n+\n+test_expect_success 'all insns work without options' '\n+\tgit checkout A &&\n+\tnext_session squashCI &&\n+\tno_marks_set &&\n+\tgit sequencer todotest1 &&\n+\tno_marks_set &&\n+\ttest \"$(git show HEAD:file1)\" = \"2\" &&\n+\ttest -z \"$(git show HEAD:file2)\" &&\n+\ttest -z \"$(git show HEAD:file3)\" &&\n+\ttest -z \"$(git show HEAD:file4)\" &&\n+\ttest -z \"$(git show HEAD:file5)\" &&\n+\ttest -z \"$(git show HEAD:file6)\" &&\n+\techo \"$(git rev-parse DCE)\" >expected &&\n+\techo \"$(git rev-parse CID)\" >>expected &&\n+\tgit cat-file commit HEAD^ | sed -n -e \"s/^parent //p\" >actual &&\n+\ttest_cmp expected actual &&\n+\tsession_ok\n+'\n+\n+cat >todotest1 <<EOF\n+merge --standard DCE\n+EOF\n+\n+echo \"Merge DCE into HEAD\" >expected1\n+\n+test_expect_success 'merge --standard works' '\n+\tgit checkout CID &&\n+\tgit sequencer todotest1 &&\n+\texpect_msg HEAD expected1 &&\n+\tsession_ok\n+'\n+\n+cat >todotest1 <<EOF\n+merge --standard --message=\"foo\" DCE\n+EOF\n+\n+\n+test_expect_success 'merge --standard --message=\"foo\" is conflict' '\n+\tgit checkout CID &&\n+\texpect_conflict git sequencer todotest1 &&\n+\tgit sequencer --abort &&\n+\tsession_ok\n+'\n+\n+for command in 'pick ' 'patch patch' 'squash ' 'merge --standard '\n+do\n+\tcat >todotest1 <<EOF\n+patch patchB\t# 1 into file1\n+${command}G\t# 3 into file1\n+patch -3 patchF\t# empty file4\n+EOF\n+\n+\ttest_expect_success \"conflict test: ${command%% *} and --abort\" '\n+\t\tgit checkout A &&\n+\t\texpect_conflict git sequencer todotest1 &&\n+\t\tsession_ok &&\n+\t\ttest -d \"$SEQDIR\" &&\n+\t\tgit sequencer --abort &&\n+\t\tsession_ok &&\n+\t\ttest $(git rev-parse HEAD) = $(git rev-parse A)\n+\t'\n+\n+\ttest_expect_success \"conflict test: ${command%% *} and --continue\" '\n+\t\tgit checkout A &&\n+\t\texpect_conflict git sequencer todotest1 &&\n+\t\tsession_ok &&\n+\t\ttest -d \"$SEQDIR\" &&\n+\t\t## XXX: It would be perfect if we could remove the if\n+\t\t{ if test \"${command%% *}\" != \"patch\"\n+\t\tthen grep \"^<<<<<<<\" file1 ; fi } &&\n+\t\techo 3 >file1 &&\n+\t\tgit add file1 &&\n+\t\tnext_session nochange &&\n+\t\tgit sequencer --continue &&\n+\t\tsession_ok &&\n+\t\t! test -d \"$SEQDIR\" &&\n+\t\ttest \"$(git show HEAD:file1)\" = \"3\" &&\n+\t\ttest -f file4\n+\t'\n+\n+\ttest_expect_success \"conflict test: ${command%% *} and --skip\" '\n+\t\tgit checkout A &&\n+\t\texpect_conflict git sequencer todotest1 &&\n+\t\tsession_ok &&\n+\t\ttest -d \"$SEQDIR\" &&\n+\t\tgit sequencer --skip &&\n+\t\tsession_ok &&\n+\t\t! test -d \"$SEQDIR\" &&\n+\t\ttest \"$(git show HEAD:file1)\" = \"1\" &&\n+\t\ttest -f file4\n+\t'\n+done\n+\n+echo 'file5-gen' >commitmsg\n+\n+cat >todotest1 <<EOF\n+patch --signoff patchB\n+pause\n+pick --author=\"$yet_another\" --file=\"commitmsg\" --signoff H\n+mark :1\n+patch --message=\"file2-gen\" patchC\n+squash --signoff --author=\"$yet_another\" I\n+pause\n+patch --message=\"echo 2 >file1\" patchD\n+mark :2\n+reset :1\n+patch --author=\"$yet_another\" patchD\n+squash --signoff --message=\"generate file[23]\" CE\n+merge --signoff --message=\"test merge\" --author=\"$yet_another\" :2\n+pause\n+ref refs/tags/a_merge\n+patch --message=\"Generate file4 and write 23 into it\" patchF.raw\n+pause\n+pick I\n+EOF\n+\n+cat >expected1 <<EOF\n+write 1 into file\n+\n+Signed-off-by: $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL>\n+EOF\n+\n+test_expect_success 'insns work with options and another author 1' '\n+\tgit checkout A &&\n+\tno_marks_set &&\n+\n+\t# patch --signoff patchB  # write 1 into file1\n+\t# pause\n+\texpect_continue git sequencer todotest1 &&\n+\ttest \"Signed-off-by: $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL>\" = \\\n+\t\t\"$(git cat-file commit HEAD | grep \"^Signed-off-by\")\" &&\n+\texpect_author HEAD \"$orig_author\" &&\n+\ttest -d \"$SEQDIR\" &&\n+\tsession_ok\n+'\n+\n+cat >expected1 <<EOF\n+file5-gen\n+\n+Signed-off-by: $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL>\n+EOF\n+\n+cat >expected2 <<EOF\n+file2-gen\n+\n+generate empty file6\n+\n+Signed-off-by: $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL>\n+EOF\n+\n+test_expect_success 'insns work with options and another author 2' '\n+\t: >file7 &&\n+\tgit add file7 &&\n+\tnext_session nochange &&\n+\tgit commit --amend &&\n+\tsession_ok &&\n+\n+\tnext_session nochange &&\n+\texpect_continue git sequencer --continue &&\n+\tsession_ok &&\n+\n+\t# amended commit\n+\ttest \"Signed-off-by: $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL>\" = \\\n+\t\t\"$(git cat-file commit HEAD^^ | grep \"^Signed-off-by\")\" &&\n+\texpect_author HEAD^^ \"$orig_author\" &&\n+\ttest -z \"$(git show HEAD:file7)\" &&\n+\n+\t# pick --author=\"$yet_another\" --file=\"commitmsg\" --signoff H\n+\texpect_author HEAD^ \"$yet_another\" &&\n+\texpect_msg HEAD^ expected1 &&\n+\ttest -z \"$(git show HEAD:file5)\" &&\n+\n+\t# mark :1\n+\ttest \"$(git rev-parse \"$SEQMARK/1\")\" = \"$(git rev-parse HEAD^)\" &&\n+\n+\t# patch --message=\"file2-gen\" patchC\n+\t# squash --signoff --author=\"$yet_another\" I # generate file6\n+\t# pause\n+\ttest -z \"$(git show HEAD:file2)\" &&\n+\ttest -z \"$(git show HEAD:file6)\" &&\n+\tgit ls-files | grep \"^file2\" &&\n+\tgit ls-files | grep \"^file6\" &&\n+\texpect_msg HEAD expected2 &&\n+\texpect_author HEAD \"$yet_another\"\n+'\n+\n+echo 'echo 2 >file1' >expected1\n+\n+cat >expected2 <<EOF\n+generate file[23]\n+\n+Signed-off-by: $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL>\n+EOF\n+\n+cat >expected3 <<EOF\n+test merge\n+\n+Signed-off-by: $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL>\n+EOF\n+\n+cat >expected4 <<EOF\n+file1\n+file2\n+file3\n+file5\n+file6\n+file7\n+EOF\n+\n+test_expect_success 'insns work with options and another author 3' '\n+\t# do not change anything\n+\texpect_continue git sequencer --continue &&\n+\tsession_ok &&\n+\n+\t# patch --message=\"echo 2 >file1\" patchD\n+\t# mark :2\n+\tcommit=\"$(git rev-parse --verify \"$SEQMARK/2\")\" &&\n+\texpect_author \"$commit\" \"$orig_author\" &&\n+\texpect_msg \"$commit\" expected1 &&\n+\n+\t# reset :1\n+\t# patch --author=\"$yet_another\" patchD # write 2 into file1\n+\t# squash --signoff --message=\"generate file[23]\" CE\n+\texpect_author HEAD^ \"$yet_another\" &&\n+\texpect_msg HEAD^ expected2 &&\n+\n+\t# merge --signoff --message=\"test merge\" --author=\"$yet_another\" :2\n+\t# pause\n+\texpect_author HEAD \"$yet_another\" &&\n+\texpect_msg HEAD expected3 &&\n+\tgit ls-files >actual &&\n+\ttest_cmp expected4 actual\n+'\n+\n+cat >expected_merge <<EOF\n+cleanup merge\n+\n+Signed-off-by: $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL>\n+EOF\n+\n+echo 'Generate file4 and write 23 into it' >expected2\n+\n+test_expect_success 'insns work with options and another author 4' '\n+\tgit rm file5 file6 file7 &&\n+\tnext_session merge2 &&\n+\texpect_continue git sequencer --continue &&\n+\tsession_ok &&\n+\n+\t# ref refs/tags/a_merge\n+\texpect_author a_merge \"$yet_another\" &&\n+\texpect_msg a_merge expected_merge &&\n+\n+\t# patch --message=\"Generate file4 and write 23 into it\" patchF.raw\n+\t# pause\n+\tgit ls-files | grep \"^file4\" &&\n+\techo 23 >file4 &&\n+\tgit add file4 &&\n+\tnext_session nochange &&\n+\tgit sequencer --continue &&\n+\tsession_ok &&\n+\tno_marks_set &&\n+\ttest \"$(git show HEAD:file1)\" = \"2\" &&\n+\ttest \"$(git show HEAD:file4)\" = \"23\" &&\n+\texpect_msg HEAD^ expected2 &&\n+\texpect_author HEAD^ \"$GIT_AUTHOR_NAME <$GIT_AUTHOR_EMAIL>\" &&\n+\n+\t# pick I\n+\ttest -z \"$(git show HEAD:file6)\" &&\n+\tgit ls-files | grep \"^file6\" &&\n+\tsession_ok\n+'\n+\n+# almost the same to test --quiet\n+cat >todotest1 <<EOF\n+patch patchB\n+pick H\n+mark :1\n+patch patchC\n+squash --message=\"a squash\" I\n+patch patchD\n+mark :2\n+reset :1\n+patch patchD\n+squash --message=\"another squash\" CE\n+merge --message=\"test merge\" :2\n+pause\n+patch patchF\n+EOF\n+\n+test_expect_failure '--quiet works' '\n+\tgit checkout A &&\n+\texpect_continue git sequencer --quiet todotest1 >actual &&\n+\tsession_ok &&\n+\t! test -s actual\n+'\n+\n+test_expect_failure '--quiet works on continue' '\n+\tgit sequencer --continue >>actual &&\n+\tsession_ok &&\n+\t! test -s actual\n+'\n+\n+echo 'merge --strategy=ours --reuse-commit=a_merge branch1 branch2 CE CID' >todotest1\n+\n+test_expect_success 'merge multiple branches and --reuse-commit works' '\n+\tgit checkout -b merge-multiple master &&\n+\tgit sequencer todotest1 &&\n+\tsession_ok &&\n+\texpect_msg HEAD expected_merge &&\n+\tgit rev-parse HEAD^ >expected &&\n+\tgit rev-parse branch1 >>expected &&\n+\tgit rev-parse branch2 >>expected &&\n+\tgit rev-parse CE >>expected &&\n+\tgit rev-parse CID >>expected &&\n+\tgit cat-file commit HEAD | sed -n -e \"s/^parent //p\" >actual &&\n+\ttest_cmp expected actual &&\n+\t! test -f file6\n+'\n+\n+echo 'pick --mainline=5 merge-multiple' >todotest1\n+\n+test_expect_success 'pick --mainline works' '\n+\tgit checkout -b mainline CID &&\n+\tgit sequencer todotest1 &&\n+\tsession_ok &&\n+\texpect_msg HEAD expected_merge &&\n+\t! test -f file6 &&\n+\ttest -f file3 &&\n+\ttest -f file2 &&\n+\ttest \"$(git show HEAD:file1)\" = 2\n+'\n+\n+cat >todotest1 <<EOF\n+pick C\t\t# file2\n+mark :1\n+patch patchB\t# write 1 into file1\n+patch patchD\t# write 2 into file1\n+pick I\t\t# file6\n+squash --message=\"2 in file1 and file6 exists\" --signoff --from :1\n+EOF\n+\n+cat >expected1 <<EOF\n+2 in file1 and file6 exists\n+\n+Signed-off-by: $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL>\n+EOF\n+\n+test_expect_success 'squash --from works' '\n+\tgit checkout A &&\n+\tgit sequencer <todotest1 &&\n+\tsession_ok &&\n+\ttest \"$(git rev-parse A)\" = \"$(git rev-parse HEAD~2)\" &&\n+\ttest \"$(git show HEAD:file1)\" = \"2\" &&\n+\ttest -z \"$(git show HEAD:file6)\" &&\n+\texpect_msg HEAD expected1\n+'\n+\n+cat >todotest1 <<EOF\n+patch patchB\t# write 1 into file1\n+pick H\t\t# generate file5\n+mark :1\n+patch patchC\t# generate file2\n+squash --message=\"file5\" I\t# generate file6\n+patch patchD\t# write 2 into file1\n+mark :2\n+reset :1\t# reset to new H\n+patch patchD\t# write 2 into file1\n+squash --message=\"CE\" CE\t# generate file2 and file3\n+merge --standard :2\t# merge :2 into HEAD\n+patch patchF\t# generate file4\n+EOF\n+cp todotest1 todotest2\n+cat todotest1 | sed -e 's/^\\(patch\\|pick\\|squash\\|merge\\) /&--edit /' >todotest3\n+echo 'squash --message=\"doesnt work either\" --from :1' >>todotest1\n+echo 'squash --include-merges --message=\"stupid\" --from :1' >>todotest2\n+\n+test_expect_success 'squash --from conflicts with merge in between' '\n+\tgit checkout A &&\n+\texpect_conflict git sequencer todotest1 &&\n+\tgit sequencer --abort &&\n+\tsession_ok &&\n+\t! test -d \"$SEQDIR\"\n+'\n+\n+test_expect_success 'squash --include-merges --from succeeds with merge in between' '\n+\tgit checkout A &&\n+\tgit sequencer todotest2 &&\n+\tsession_ok &&\n+\ttest \"$(git rev-parse HEAD~3)\" = \"$(git rev-parse A)\"\n+'\n+\n+test_expect_success 'patch|pick|squash|merge --edit works' '\n+\tgit checkout A &&\n+\tnext_session editX &&\n+\tgit sequencer todotest3 &&\n+\tsession_ok\n+'\n+\n+cat >todotest1 <<EOF\n+patch patchB\n+pause\n+EOF\n+\n+test_expect_success 'batch mode fails on pause insn' '\n+\tgit checkout A &&\n+\texpect_fail git sequencer --batch todotest1 &&\n+\tsession_ok &&\n+\t! test -d \"$SEQDIR\"\n+'\n+\n+cat >todotest1 <<EOF\n+patch patchB\n+pick G\n+EOF\n+\n+test_expect_success 'batch mode fails on conflict' '\n+\tgit checkout A &&\n+\texpect_fail git sequencer --batch <todotest1 &&\n+\tsession_ok &&\n+\t! test -d \"$SEQDIR\" &&\n+\ttest -z \"$(git show HEAD:file1)\"\n+'\n+\n+cat >todotest1 <<EOF\n+patch patchB\n+pause\n+EOF\n+\n+test_expect_success '--caller works' '\n+\tgit checkout A &&\n+\texpect_continue git sequencer \\\n+\t\t--caller=\"this works|abrt||skip\" todotest1 &&\n+\texpect_fail git sequencer --abort &&\n+\texpect_fail git sequencer --skip &&\n+\tgit sequencer --continue &&\n+\tsession_ok\n+'\n+\n+test_done\n-- \n1.6.0.rc0.49.gd39f\n"},{"id":"85012","messageId":"1217049644-8874-5-git-send-email-s-beyer@gmx.net","threadId":"14685","inReplyTo":"1217049644-8874-4-git-send-email-s-beyer@gmx.net","subject":"[PATCH 4/5] Migrate git-am to use git-sequencer","fromName":"Stephan Beyer","fromEmail":"s-beyer@gmx.net","sentAt":"2008-07-26T05:20:43Z","receivedAt":"2008-07-26T05:20:43Z","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-apply\nand let 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\ndo, the user does not have to remove .git/rebase-apply or run\ngit-am --skip manually. It automatically aborts instead, which\nseems to be an 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     |  632 ++++++++++++++++++++-------------------------------------\n git-rebase.sh |    7 +-\n t/t4150-am.sh |    4 +-\n 3 files changed, 220 insertions(+), 423 deletions(-)\n\ndiff --git a/git-am.sh b/git-am.sh\nindex f4abd9d..ba93f02 100755\n--- a/git-am.sh\n+++ b/git-am.sh\n@@ -34,103 +34,148 @@ 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=\"git am\"\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-    echo \"To restore the original branch and stop patching run \\\"$cmdline --abort\\\".\"\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+\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\t# pretend we never tried to apply\n+\t\t\tto=HEAD\n+\t\t\ttest conflict = \"$1\" ||\n+\t\t\t\tto=HEAD^\n+\t\t\tgit read-tree -m -u HEAD $to\n+\t\t\tgit reset -q $to >/dev/null\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+\techo 'To restore the original branch and stop patching run \"git am --abort\".'\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 $seqopts --caller='git am|--abort|--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 $seqopts \\\n+\t\t\t--caller='git am -i|--abort|--resolved|--skip' \\\n+\t\t\t$command 2>&1)\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\tif test -f \"$dotest/conflict\"\n+\t\t\tthen\n+\t\t\t\trm \"$dotest/conflict\"\n+\t\t\telse\n+\t\t\t\tbe_interactive\n+\t\t\tfi\n+\t\t\t;;\n+\t\t3)\n+\t\t\t: >\"$dotest/conflict\"\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\tseqopts=\n+\t\tcommand=--continue\n+\tdone\n }\n \n prec=4\n dotest=\"$GIT_DIR/rebase-apply\"\n+todofile=\"$dotest/todo\"\n sign= utf8=t keep= skip= interactive= resolved= binary= rebasing= abort=\n-resolvemsg= resume=\n-git_apply_opt=\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@@ -157,9 +202,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@@ -168,363 +213,118 @@ 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$abort\" 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+\ttest \"$#\" != 0 &&\n+\t\tdie \"previous rebase directory $dotest still exists but mbox given.\"\n \n-\tcase \"$skip,$abort\" in\n-\tt,)\n-\t\tgit rerere clear\n-\t\tgit read-tree --reset -u HEAD HEAD\n-\t\torig_head=$(cat \"$GIT_DIR/ORIG_HEAD\")\n-\t\tgit reset HEAD\n-\t\tgit update-ref ORIG_HEAD $orig_head\n-\t\t;;\n-\t,t)\n-\t\tgit rerere clear\n-\t\tgit read-tree --reset -u HEAD ORIG_HEAD\n-\t\tgit reset ORIG_HEAD\n-\t\trm -fr \"$dotest\"\n-\t\texit ;;\n-\tesac\n-else\n-\t# Make sure we are not given --skip, --resolved, nor --abort\n-\ttest \"$skip$resolved$abort\" = \"\" ||\n-\t\tdie \"Resolve operation not in progress, we are not resuming.\"\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 \"$abort$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 \"$abort\" && run_sequencer$interactive --abort\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 --abort/--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, --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-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-\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-\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+\tmsgnum=$(printf \"%0${prec}d\" $this)\n+\tthis=$(($this+1))\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+seqopts=\"--no-advice --allow-dirty\"\n+run_sequencer$interactive \"$todofile\"\ndiff --git a/git-rebase.sh b/git-rebase.sh\nindex 412e135..67c1868 100755\n--- a/git-rebase.sh\n+++ b/git-rebase.sh\n@@ -216,12 +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-apply\n-\t\t\tmove_to_original_branch\n+\t\t\tgit am --abort\n \t\tfi\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 6e6aaf5..d49c69d 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-\ttest_must_fail git am <failmail &&\n-\trm -r .git/rebase-apply/\n+\ttest_must_fail git am <failmail\n '\n \n test_expect_success 'am fails on empty patch' '\n \techo \"---\" >>failmail &&\n \ttest_must_fail git am <failmail &&\n-\tgit am --skip &&\n \t! test -d .git/rebase-apply\n '\n \n-- \n1.6.0.rc0.49.gd39f\n"},{"id":"85009","messageId":"1217049644-8874-6-git-send-email-s-beyer@gmx.net","threadId":"14685","inReplyTo":"1217049644-8874-5-git-send-email-s-beyer@gmx.net","subject":"[PATCH 5/5] Migrate rebase-i to sequencer","fromName":"Stephan Beyer","fromEmail":"s-beyer@gmx.net","sentAt":"2008-07-26T05:20:44Z","receivedAt":"2008-07-26T05:20:44Z","isPatch":true,"sender":{"key":"s-beyer@gmx.net","avatar":"https://avatars.githubusercontent.com/u/143889?v=4"},"body":"The migration of pure rebase-i to sequencer is simply done by\ngenerating the todo list, but with a comment marker (`#')\nbefore the description, and then feed it to git sequencer.\n\nFor git-rebase-i -p (preserving merges) merges should be\nrewritten. For this, the sequencer instructions \"mark\", \"merge\"\nand \"reset\" are used.\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-rebase--interactive.sh    |  436 ++++++++++-------------------------------\n t/t3404-rebase-interactive.sh |    8 +-\n 2 files changed, 110 insertions(+), 334 deletions(-)\n\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex 4e334ba..2136e02 100755\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -42,11 +42,6 @@ STRATEGY=\n ONTO=\n VERBOSE=\n \n-GIT_CHERRY_PICK_HELP=\"  After resolving the conflicts,\n-mark the corrected paths with 'git add <paths>', and\n-run 'git rebase --continue'\"\n-export GIT_CHERRY_PICK_HELP\n-\n warn () {\n \techo \"$*\" >&2\n }\n@@ -74,48 +69,6 @@ require_clean_work_tree () {\n \tdie \"Working tree is dirty\"\n }\n \n-ORIG_REFLOG_ACTION=\"$GIT_REFLOG_ACTION\"\n-\n-comment_for_reflog () {\n-\tcase \"$ORIG_REFLOG_ACTION\" in\n-\t''|rebase*)\n-\t\tGIT_REFLOG_ACTION=\"rebase -i ($1)\"\n-\t\texport GIT_REFLOG_ACTION\n-\t\t;;\n-\tesac\n-}\n-\n-last_count=\n-mark_action_done () {\n-\tsed -e 1q < \"$TODO\" >> \"$DONE\"\n-\tsed -e 1d < \"$TODO\" >> \"$TODO\".new\n-\tmv -f \"$TODO\".new \"$TODO\"\n-\tcount=$(grep -c '^[^#]' < \"$DONE\")\n-\ttotal=$(($count+$(grep -c '^[^#]' < \"$TODO\")))\n-\tif test \"$last_count\" != \"$count\"\n-\tthen\n-\t\tlast_count=$count\n-\t\tprintf \"Rebasing (%d/%d)\\r\" $count $total\n-\t\ttest -z \"$VERBOSE\" || echo\n-\tfi\n-}\n-\n-make_patch () {\n-\tparent_sha1=$(git rev-parse --verify \"$1\"^) ||\n-\t\tdie \"Cannot get patch for $1^\"\n-\tgit diff-tree -p \"$parent_sha1\"..\"$1\" > \"$DOTEST\"/patch\n-\ttest -f \"$DOTEST\"/message ||\n-\t\tgit cat-file commit \"$1\" | sed \"1,/^$/d\" > \"$DOTEST\"/message\n-\ttest -f \"$DOTEST\"/author-script ||\n-\t\tget_author_ident_from_commit \"$1\" > \"$DOTEST\"/author-script\n-}\n-\n-die_with_patch () {\n-\tmake_patch \"$1\"\n-\tgit rerere\n-\tdie \"$2\"\n-}\n-\n die_abort () {\n \trm -rf \"$DOTEST\"\n \tdie \"$1\"\n@@ -125,48 +78,20 @@ has_action () {\n \tgrep '^[^#]' \"$1\" >/dev/null\n }\n \n-pick_one () {\n-\tno_ff=\n-\tcase \"$1\" in -n) sha1=$2; no_ff=t ;; *) sha1=$1 ;; esac\n-\toutput git rev-parse --verify $sha1 || die \"Invalid commit name: $sha1\"\n-\ttest -d \"$REWRITTEN\" &&\n-\t\tpick_one_preserving_merges \"$@\" && return\n-\tparent_sha1=$(git rev-parse --verify $sha1^) ||\n-\t\tdie \"Could not get the parent of $sha1\"\n-\tcurrent_sha1=$(git rev-parse --verify HEAD)\n-\tif test \"$no_ff$current_sha1\" = \"$parent_sha1\"; then\n-\t\toutput git reset --hard $sha1\n-\t\ttest \"a$1\" = a-n && output git reset --soft $current_sha1\n-\t\tsha1=$(git rev-parse --short $sha1)\n-\t\toutput warn Fast forward to $sha1\n-\telse\n-\t\toutput git cherry-pick \"$@\"\n-\tfi\n-}\n-\n-pick_one_preserving_merges () {\n-\tcase \"$1\" in -n) sha1=$2 ;; *) sha1=$1 ;; esac\n+create_todo_preserving_merges () {\n+\tshortsha1=$sha1\n \tsha1=$(git rev-parse $sha1)\n \n-\tif test -f \"$DOTEST\"/current-commit\n-\tthen\n-\t\tcurrent_commit=$(cat \"$DOTEST\"/current-commit) &&\n-\t\tgit rev-parse HEAD > \"$REWRITTEN\"/$current_commit &&\n-\t\trm \"$DOTEST\"/current-commit ||\n-\t\tdie \"Cannot write current commit's replacement sha1\"\n-\tfi\n-\n-\t# rewrite parents; if none were rewritten, we can fast-forward.\n-\tfast_forward=t\n \tpreserve=t\n \tnew_parents=\n+\tfirst_parent=\n \tfor p in $(git rev-list --parents -1 $sha1 | cut -d' ' -f2-)\n \tdo\n+\t\t# check if we've already seen this parent\n \t\tif test -f \"$REWRITTEN\"/$p\n \t\tthen\n \t\t\tpreserve=f\n \t\t\tnew_p=$(cat \"$REWRITTEN\"/$p)\n-\t\t\ttest $p != $new_p && fast_forward=f\n \t\t\tcase \"$new_parents\" in\n \t\t\t*$new_p*)\n \t\t\t\t;; # do nothing; that parent is already there\n@@ -177,185 +102,46 @@ pick_one_preserving_merges () {\n \t\telse\n \t\t\tnew_parents=\"$new_parents $p\"\n \t\tfi\n+\t\ttest -n \"$first_parent\" || first_parent=$p\n \tdone\n-\tcase $fast_forward in\n-\tt)\n-\t\toutput warn \"Fast forward to $sha1\"\n-\t\ttest $preserve = f || echo $sha1 > \"$REWRITTEN\"/$sha1\n-\t\t;;\n-\tf)\n-\t\ttest \"a$1\" = a-n && die \"Refusing to squash a merge: $sha1\"\n-\n-\t\tfirst_parent=$(expr \"$new_parents\" : ' \\([^ ]*\\)')\n-\t\t# detach HEAD to current parent\n-\t\toutput git checkout $first_parent 2> /dev/null ||\n-\t\t\tdie \"Cannot move HEAD to $first_parent\"\n-\n-\t\techo $sha1 > \"$DOTEST\"/current-commit\n-\t\tcase \"$new_parents\" in\n-\t\t' '*' '*)\n-\t\t\t# redo merge\n-\t\t\tauthor_script=$(get_author_ident_from_commit $sha1)\n-\t\t\teval \"$author_script\"\n-\t\t\tmsg=\"$(git cat-file commit $sha1 | sed -e '1,/^$/d')\"\n-\t\t\t# No point in merging the first parent, that's HEAD\n-\t\t\tnew_parents=${new_parents# $first_parent}\n-\t\t\tif ! GIT_AUTHOR_NAME=\"$GIT_AUTHOR_NAME\" \\\n-\t\t\t\tGIT_AUTHOR_EMAIL=\"$GIT_AUTHOR_EMAIL\" \\\n-\t\t\t\tGIT_AUTHOR_DATE=\"$GIT_AUTHOR_DATE\" \\\n-\t\t\t\toutput git merge $STRATEGY -m \"$msg\" \\\n-\t\t\t\t\t$new_parents\n-\t\t\tthen\n-\t\t\t\tgit rerere\n-\t\t\t\tprintf \"%s\\n\" \"$msg\" > \"$GIT_DIR\"/MERGE_MSG\n-\t\t\t\tdie Error redoing merge $sha1\n-\t\t\tfi\n-\t\t\t;;\n-\t\t*)\n-\t\t\toutput git cherry-pick \"$@\" ||\n-\t\t\t\tdie_with_patch $sha1 \"Could not pick $sha1\"\n-\t\t\t;;\n-\t\tesac\n-\t\t;;\n-\tesac\n-}\n+\t# We do not have parent, so ignore this commit\n+\ttest t = $preserve && return\n \n-nth_string () {\n-\tcase \"$1\" in\n-\t*1[0-9]|*[04-9]) echo \"$1\"th;;\n-\t*1) echo \"$1\"st;;\n-\t*2) echo \"$1\"nd;;\n-\t*3) echo \"$1\"rd;;\n-\tesac\n-}\n+\t# We always write a mark, because we do not know if there will\n+\t# be a \"reset\" or \"merge\"\n+\t# Filter the unneeded marks out afterwards.\n+\techo \"mark :$mark\"\n+\tmark=$(($mark+1))\n \n-make_squash_message () {\n-\tif test -f \"$SQUASH_MSG\"; then\n-\t\tCOUNT=$(($(sed -n \"s/^# This is [^0-9]*\\([1-9][0-9]*\\).*/\\1/p\" \\\n-\t\t\t< \"$SQUASH_MSG\" | sed -ne '$p')+1))\n-\t\techo \"# This is a combination of $COUNT commits.\"\n-\t\tsed -e 1d -e '2,/^./{\n-\t\t\t/^$/d\n-\t\t}' <\"$SQUASH_MSG\"\n-\telse\n-\t\tCOUNT=2\n-\t\techo \"# This is a combination of two commits.\"\n-\t\techo \"# The first commit's message is:\"\n-\t\techo\n-\t\tgit cat-file commit HEAD | sed -e '1,/^$/d'\n-\tfi\n-\techo\n-\techo \"# This is the $(nth_string $COUNT) commit message:\"\n-\techo\n-\tgit cat-file commit $1 | sed -e '1,/^$/d'\n-}\n+\tnew_first_parent=$(expr \"$new_parents\" : ' \\([^ ]*\\)')\n \n-peek_next_command () {\n-\tsed -n \"1s/ .*$//p\" < \"$TODO\"\n-}\n+\t# Reset if needed\n+\ttest -z \"$first_parent\" -o \"$first_parent\" = $lastsha1 ||\n+\t\techo \"reset $new_first_parent\"\n \n-do_next () {\n-\trm -f \"$DOTEST\"/message \"$DOTEST\"/author-script \\\n-\t\t\"$DOTEST\"/amend || exit\n-\tread command sha1 rest < \"$TODO\"\n-\tcase \"$command\" in\n-\t'#'*|'')\n-\t\tmark_action_done\n-\t\t;;\n-\tpick|p)\n-\t\tcomment_for_reflog pick\n+\techo \":$mark\" > \"$REWRITTEN\"/$sha1\n \n-\t\tmark_action_done\n-\t\tpick_one $sha1 ||\n-\t\t\tdie_with_patch $sha1 \"Could not apply $sha1... $rest\"\n-\t\t;;\n-\tedit|e)\n-\t\tcomment_for_reflog edit\n-\n-\t\tmark_action_done\n-\t\tpick_one $sha1 ||\n-\t\t\tdie_with_patch $sha1 \"Could not apply $sha1... $rest\"\n-\t\tmake_patch $sha1\n-\t\t: > \"$DOTEST\"/amend\n-\t\twarn \"Stopped at $sha1... $rest\"\n-\t\twarn \"You can amend the commit now, with\"\n-\t\twarn\n-\t\twarn \"\tgit commit --amend\"\n-\t\twarn\n-\t\twarn \"Once you are satisfied with your changes, run\"\n-\t\twarn\n-\t\twarn \"\tgit rebase --continue\"\n-\t\twarn\n-\t\texit 0\n-\t\t;;\n-\tsquash|s)\n-\t\tcomment_for_reflog squash\n-\n-\t\thas_action \"$DONE\" ||\n-\t\t\tdie \"Cannot 'squash' without a previous commit\"\n-\n-\t\tmark_action_done\n-\t\tmake_squash_message $sha1 > \"$MSG\"\n-\t\tcase \"$(peek_next_command)\" in\n-\t\tsquash|s)\n-\t\t\tEDIT_COMMIT=\n-\t\t\tUSE_OUTPUT=output\n-\t\t\tcp \"$MSG\" \"$SQUASH_MSG\"\n-\t\t\t;;\n-\t\t*)\n-\t\t\tEDIT_COMMIT=-e\n-\t\t\tUSE_OUTPUT=\n-\t\t\trm -f \"$SQUASH_MSG\" || exit\n-\t\t\t;;\n-\t\tesac\n-\n-\t\tfailed=f\n-\t\tauthor_script=$(get_author_ident_from_commit HEAD)\n-\t\toutput git reset --soft HEAD^\n-\t\tpick_one -n $sha1 || failed=t\n-\t\techo \"$author_script\" > \"$DOTEST\"/author-script\n-\t\tif test $failed = f\n-\t\tthen\n-\t\t\t# This is like --amend, but with a different message\n-\t\t\teval \"$author_script\"\n-\t\t\tGIT_AUTHOR_NAME=\"$GIT_AUTHOR_NAME\" \\\n-\t\t\tGIT_AUTHOR_EMAIL=\"$GIT_AUTHOR_EMAIL\" \\\n-\t\t\tGIT_AUTHOR_DATE=\"$GIT_AUTHOR_DATE\" \\\n-\t\t\t$USE_OUTPUT git commit --no-verify -F \"$MSG\" $EDIT_COMMIT || failed=t\n-\t\tfi\n-\t\tif test $failed = t\n-\t\tthen\n-\t\t\tcp \"$MSG\" \"$GIT_DIR\"/MERGE_MSG\n-\t\t\twarn\n-\t\t\twarn \"Could not apply $sha1... $rest\"\n-\t\t\tdie_with_patch $sha1 \"\"\n-\t\tfi\n+\t# Merge or pick\n+\tcase \"$new_parents\" in\n+\t' '*' '*)\n+\t\tnew_parents=${new_parents# $new_first_parent}\n+\t\tprintf 'merge%s -C %s%s\\t%s\\n' \"$STRATEGY\" \\\n+\t\t\t\"$shortsha1\" \"$new_parents\" \"$rest\"\n \t\t;;\n \t*)\n-\t\twarn \"Unknown command: $command $sha1 $rest\"\n-\t\tdie_with_patch $sha1 \"Please fix this in the file $TODO.\"\n+\t\tprintf 'pick %s\\t%s\\n' \"$shortsha1\" \"$rest\"\n \t\t;;\n \tesac\n-\ttest -s \"$TODO\" && return\n \n-\tcomment_for_reflog finish &&\n+\tlastsha1=\"$sha1\"\n+\treturn 0\n+}\n+\n+update_refs_and_exit () {\n \tHEADNAME=$(cat \"$DOTEST\"/head-name) &&\n \tOLDHEAD=$(cat \"$DOTEST\"/head) &&\n \tSHORTONTO=$(git rev-parse --short $(cat \"$DOTEST\"/onto)) &&\n-\tif test -d \"$REWRITTEN\"\n-\tthen\n-\t\ttest -f \"$DOTEST\"/current-commit &&\n-\t\t\tcurrent_commit=$(cat \"$DOTEST\"/current-commit) &&\n-\t\t\tgit rev-parse HEAD > \"$REWRITTEN\"/$current_commit\n-\t\tif test -f \"$REWRITTEN\"/$OLDHEAD\n-\t\tthen\n-\t\t\tNEWHEAD=$(cat \"$REWRITTEN\"/$OLDHEAD)\n-\t\telse\n-\t\t\tNEWHEAD=$OLDHEAD\n-\t\tfi\n-\telse\n-\t\tNEWHEAD=$(git rev-parse HEAD)\n-\tfi &&\n+\tNEWHEAD=$(git rev-parse HEAD) &&\n \tcase $HEADNAME in\n \trefs/*)\n \t\tmessage=\"$GIT_REFLOG_ACTION: $HEADNAME onto $SHORTONTO)\" &&\n@@ -373,13 +159,6 @@ do_next () {\n \texit\n }\n \n-do_rest () {\n-\twhile :\n-\tdo\n-\t\tdo_next\n-\tdone\n-}\n-\n # check if no other options are set\n is_standalone () {\n \ttest $# -eq 2 -a \"$2\" = '--' &&\n@@ -395,80 +174,47 @@ get_saved_options () {\n \ttest -f \"$DOTEST\"/verbose && VERBOSE=t\n }\n \n-while test $# != 0\n-do\n-\tcase \"$1\" in\n-\t--continue)\n-\t\tis_standalone \"$@\" || usage\n-\t\tget_saved_options\n-\t\tcomment_for_reflog continue\n-\n-\t\ttest -d \"$DOTEST\" || die \"No interactive rebase running\"\n-\n-\t\t# Sanity check\n-\t\tgit rev-parse --verify HEAD >/dev/null ||\n-\t\t\tdie \"Cannot read HEAD\"\n-\t\tgit update-index --ignore-submodules --refresh &&\n-\t\t\tgit diff-files --quiet --ignore-submodules ||\n-\t\t\tdie \"Working tree is dirty\"\n-\n-\t\t# do we have anything to commit?\n-\t\tif git diff-index --cached --quiet --ignore-submodules HEAD --\n+run_sequencer () {\n+\tgit sequencer --caller='git rebase -i|--abort|--continue|--skip' \"$@\"\n+\tcase \"$?\" in\n+\t0)\n+\t\tif test \"$1\" = --abort\n \t\tthen\n-\t\t\t: Nothing to commit -- skip this\n+\t\t\trm -rf \"$DOTEST\"\n+\t\t\texit\n \t\telse\n-\t\t\t. \"$DOTEST\"/author-script ||\n-\t\t\t\tdie \"Cannot find the author identity\"\n-\t\t\tif test -f \"$DOTEST\"/amend\n-\t\t\tthen\n-\t\t\t\tgit reset --soft HEAD^ ||\n-\t\t\t\tdie \"Cannot rewind the HEAD\"\n-\t\t\tfi\n-\t\t\texport GIT_AUTHOR_NAME GIT_AUTHOR_EMAIL GIT_AUTHOR_DATE &&\n-\t\t\tgit commit --no-verify -F \"$DOTEST\"/message -e ||\n-\t\t\tdie \"Could not commit staged changes.\"\n+\t\t\tupdate_refs_and_exit\n \t\tfi\n-\n-\t\trequire_clean_work_tree\n-\t\tdo_rest\n \t\t;;\n-\t--abort)\n-\t\tis_standalone \"$@\" || usage\n-\t\tget_saved_options\n-\t\tcomment_for_reflog abort\n-\n-\t\tgit rerere clear\n-\t\ttest -d \"$DOTEST\" || die \"No interactive rebase running\"\n-\n-\t\tHEADNAME=$(cat \"$DOTEST\"/head-name)\n-\t\tHEAD=$(cat \"$DOTEST\"/head)\n-\t\tcase $HEADNAME in\n-\t\trefs/*)\n-\t\t\tgit symbolic-ref HEAD $HEADNAME\n-\t\t\t;;\n-\t\tesac &&\n-\t\toutput git reset --hard $HEAD &&\n-\t\trm -rf \"$DOTEST\"\n-\t\texit\n+\t2)\n+\t\t# pause\n+\t\texit 0\n \t\t;;\n-\t--skip)\n-\t\tis_standalone \"$@\" || usage\n-\t\tget_saved_options\n-\t\tcomment_for_reflog skip\n-\n-\t\tgit rerere clear\n-\t\ttest -d \"$DOTEST\" || die \"No interactive rebase running\"\n+\t3)\n+\t\t# conflict\n+\t\texit 1\n+\t\t;;\n+\t*)\n+\t\tdie_abort 'git-sequencer died unexpected.'\n+\t\t;;\n+\tesac\n+}\n \n-\t\toutput git reset --hard && do_rest\n+while test $# != 0\n+do\n+\tcase \"$1\" in\n+\t--abort|--continue|--skip)\n+\t\tis_standalone \"$@\" || usage\n+\t\trun_sequencer \"$1\"\n \t\t;;\n \t-s)\n \t\tcase \"$#,$1\" in\n \t\t*,*=*)\n-\t\t\tSTRATEGY=\"-s \"$(expr \"z$1\" : 'z-[^=]*=\\(.*\\)') ;;\n+\t\t\tSTRATEGY=\" -s \"$(expr \"z$1\" : 'z-[^=]*=\\(.*\\)') ;;\n \t\t1,*)\n \t\t\tusage ;;\n \t\t*)\n-\t\t\tSTRATEGY=\"-s $2\"\n+\t\t\tSTRATEGY=\" -s $2\"\n \t\t\tshift ;;\n \t\tesac\n \t\t;;\n@@ -494,12 +240,12 @@ do\n \t\ttest $# -eq 1 -o $# -eq 2 || usage\n \t\ttest -d \"$DOTEST\" &&\n \t\t\tdie \"Interactive rebase already started\"\n+\t\tgit sequencer --status >/dev/null 2>&1 &&\n+\t\t\tdie \"Sequencer already started. Cannot run rebase.\"\n \n \t\tgit var GIT_COMMITTER_IDENT >/dev/null ||\n \t\t\tdie \"You need to set your committer info first\"\n \n-\t\tcomment_for_reflog start\n-\n \t\trequire_clean_work_tree\n \n \t\tUPSTREAM=$(git rev-parse --verify \"$1\") || die \"Invalid base\"\n@@ -516,42 +262,72 @@ do\n \t\tHEAD=$(git rev-parse --verify HEAD) || die \"No HEAD?\"\n \t\tmkdir \"$DOTEST\" || die \"Could not create temporary $DOTEST\"\n \n-\t\t: > \"$DOTEST\"/interactive || die \"Could not mark as interactive\"\n+\t\t: > \"$DOTEST\"/interactive || die_abort \"Could not mark as interactive\"\n \t\tgit symbolic-ref HEAD > \"$DOTEST\"/head-name 2> /dev/null ||\n \t\t\techo \"detached HEAD\" > \"$DOTEST\"/head-name\n \n \t\techo $HEAD > \"$DOTEST\"/head\n-\t\techo $UPSTREAM > \"$DOTEST\"/upstream\n \t\techo $ONTO > \"$DOTEST\"/onto\n \t\ttest -z \"$STRATEGY\" || echo \"$STRATEGY\" > \"$DOTEST\"/strategy\n \t\ttest t = \"$VERBOSE\" && : > \"$DOTEST\"/verbose\n \t\tif test t = \"$PRESERVE_MERGES\"\n \t\tthen\n+\t\t\tlastsha1=\n \t\t\t# $REWRITTEN contains files for each commit that is\n-\t\t\t# reachable by at least one merge base of $HEAD and\n-\t\t\t# $UPSTREAM. They are not necessarily rewritten, but\n-\t\t\t# their children might be.\n-\t\t\t# This ensures that commits on merged, but otherwise\n-\t\t\t# unrelated side branches are left alone. (Think \"X\"\n-\t\t\t# in the man page's example.)\n+\t\t\t# reachable on the way between $UPSTREAM and $HEAD.\n+\t\t\t# The filename is the SHA1 of the old value and the\n+\t\t\t# content is the SHA1 or :mark of the new one.\n \t\t\tmkdir \"$REWRITTEN\" &&\n \t\t\tfor c in $(git merge-base --all $HEAD $UPSTREAM)\n \t\t\tdo\n+\t\t\t\ttest -n \"$lastsha1\" || lastsha1=$c\n \t\t\t\techo $ONTO > \"$REWRITTEN\"/$c ||\n \t\t\t\t\tdie \"Could not init rewritten commits\"\n \t\t\tdone\n-\t\t\tMERGES_OPTION=\n-\t\telse\n-\t\t\tMERGES_OPTION=--no-merges\n+\t\t\tgit rev-list --abbrev-commit --abbrev=7 \\\n+\t\t\t\t--pretty=format:\"%m%h\t# %s\" --topo-order \\\n+\t\t\t\t--reverse --cherry-pick $UPSTREAM...$HEAD | \\\n+\t\t\t\tsed -n -e \"s/^>//p\" > \"$DOTEST\"/commit-list\n+\n+\t\t\tmark=0\n+\t\t\twhile read -r sha1 rest\n+\t\t\tdo\n+\t\t\t\tcreate_todo_preserving_merges\n+\t\t\tdone < \"$DOTEST\"/commit-list > \"$TODO\"\n+\n+\t\t\t# We now have more \"mark :...\" lines than needed.\n+\t\t\t# Remove the unused.  This is just a step to keep\n+\t\t\t# the list clean.\n+\t\t\tkeep_marks=$(sed -e \"/^mark :/d\" <\"$TODO\" |\n+\t\t\t\tsed -n -e 's/^[^#]* :\\([0-9][0-9]*\\).*$/:\\1:/p')\n+\t\t\twhile read -r line\n+\t\t\tdo\n+\t\t\t\tcase \"$line\" in\n+\t\t\t\t'mark :'*)\n+\t\t\t\t\tcase \"$keep_marks \" in\n+\t\t\t\t\t*${line#mark }:*)\n+\t\t\t\t\t\techo \"$line\"\n+\t\t\t\t\t\t;;\n+\t\t\t\t\tesac\n+\t\t\t\t\t;;\n+\t\t\t\t*)\n+\t\t\t\t\tprintf '%s\\n' \"$line\"\n+\t\t\t\t\t;;\n+\t\t\t\tesac\n+\t\t\tdone < \"$TODO\" > \"$TODO\".new\n+\t\t\tmv \"$TODO\".new \"$TODO\"\n+\t\tfi\n+\t\tif test -z \"$PRESERVE_MERGES\"\n+\t\tthen\n+\t\t\tgit rev-list --no-merges --abbrev-commit --abbrev=7 \\\n+\t\t\t\t--pretty=format:\"%mpick %h\t# %s\" \\\n+\t\t\t\t--reverse --cherry-pick $UPSTREAM...$HEAD | \\\n+\t\t\t\tsed -n -e \"s/^>//p\" > \"$TODO\"\n \t\tfi\n \n \t\tSHORTUPSTREAM=$(git rev-parse --short $UPSTREAM)\n \t\tSHORTHEAD=$(git rev-parse --short $HEAD)\n \t\tSHORTONTO=$(git rev-parse --short $ONTO)\n-\t\tgit rev-list $MERGES_OPTION --pretty=oneline --abbrev-commit \\\n-\t\t\t--abbrev=7 --reverse --left-right --cherry-pick \\\n-\t\t\t$UPSTREAM...$HEAD | \\\n-\t\t\tsed -n \"s/^>/pick /p\" > \"$TODO\"\n \t\tcat >> \"$TODO\" << EOF\n \n # Rebase $SHORTUPSTREAM..$SHORTHEAD onto $SHORTONTO\n@@ -577,7 +353,7 @@ EOF\n \t\t\tdie_abort \"Nothing to do\"\n \n \t\tgit update-ref ORIG_HEAD $HEAD\n-\t\toutput git checkout $ONTO && do_rest\n+\t\trun_sequencer --onto \"$ONTO\" \"$TODO\"\n \t\t;;\n \tesac\n \tshift\ndiff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh\nindex ffe3dd9..506477b 100755\n--- a/t/t3404-rebase-interactive.sh\n+++ b/t/t3404-rebase-interactive.sh\n@@ -159,19 +159,19 @@ test_expect_success 'stop on conflicting pick' '\n \tgit tag new-branch1 &&\n \ttest_must_fail git rebase -i master &&\n \ttest \"$(git rev-parse HEAD~3)\" = \"$(git rev-parse master)\" &&\n-\ttest_cmp expect .git/rebase-merge/patch &&\n \ttest_cmp expect2 file1 &&\n \ttest \"$(git-diff --name-status |\n \t\tsed -n -e \"/^U/s/^U[^a-z]*//p\")\" = file1 &&\n-\ttest 4 = $(grep -v \"^#\" < .git/rebase-merge/done | wc -l) &&\n-\ttest 0 = $(grep -c \"^[^#]\" < .git/rebase-merge/git-rebase-todo)\n+\ttest 4 = $(grep -v \"^#\" < .git/sequencer/done | wc -l) &&\n+\ttest 0 = $(grep -c \"^[^#]\" < .git/sequencer/todo) &&\n+\ttest -d .git/rebase-merge\n '\n \n test_expect_success 'abort' '\n \tgit rebase --abort &&\n \ttest $(git rev-parse new-branch1) = $(git rev-parse HEAD) &&\n \ttest \"$(git symbolic-ref -q HEAD)\" = \"refs/heads/branch1\" &&\n-\t! test -d .git/rebase-merge\n+\t! test -d .git/sequencer\n '\n \n test_expect_success 'retain authorship' '\n-- \n1.6.0.rc0.49.gd39f\n"},{"id":"85031","messageId":"g6emhb$p1a$1@ger.gmane.org","threadId":"14685","inReplyTo":"1217049644-8874-3-git-send-email-s-beyer@gmx.net","subject":"Re: [PATCH 2/5] Add git-sequencer documentation","fromName":"Jakub Narebski","fromEmail":"jnareb@gmail.com","sentAt":"2008-07-26T08:16:44Z","receivedAt":"2008-07-26T08:16:44Z","isPatch":true,"sender":{"key":"jnareb@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2706?v=4"},"body":"Stephan Beyer wrote:\n\n> +All characters after a `#` character will be ignored until the end of a line.\n\nProbably should be 'are comments and' somewhere...\n\n-- \nJakub Narebski\nWarsaw, Poland\nShadeHawk on #git\n"},{"id":"85033","messageId":"bd6139dc0807260126u2f9e4902j8721b39d19ae340d@mail.gmail.com","threadId":"14685","inReplyTo":"g6emhb$p1a$1@ger.gmane.org","subject":"Re: [PATCH 2/5] Add git-sequencer documentation","fromName":"Sverre Rabbelier","fromEmail":"alturin@gmail.com","sentAt":"2008-07-26T08:26:47Z","receivedAt":"2008-07-26T08:26:47Z","isPatch":true,"sender":{"key":"alturin@gmail.com","avatar":null},"body":"On Sat, Jul 26, 2008 at 10:16, Jakub Narebski <jnareb@gmail.com> wrote:\n> Stephan Beyer wrote:\n>> +All characters after a `#` character will be ignored until the end of a line.\n>\n> Probably should be 'are comments and' somewhere...\n\ns/ and$//\ns/^/and /\n\n-- \nCheers,\n\nSverre Rabbelier\n"},{"id":"85060","messageId":"alpine.DEB.1.00.0807261617010.26810@eeepc-johanness","threadId":"14685","inReplyTo":"1217049644-8874-1-git-send-email-s-beyer@gmx.net","subject":"Re: git sequencer prototype","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2008-07-26T14:19:17Z","receivedAt":"2008-07-26T14:19:17Z","isPatch":false,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Sat, 26 Jul 2008, Stephan Beyer wrote:\n\n> In the last patchset I mentioned the issue, that the prototype is slow\n> as hell.  I know some bottlenecks, but I have not even tried to change\n> that, because this is no issue for the builtin.\n\nWhy is it no issue for the builtin?  Is it so much different from the \nprototype?\n\nPersonally, I think if the prototype is so much slower, there is no sense \napplying it into git.git, but I'd rather see you work on the builtin and \nfinalize it.\n\nCiao,\nDscho\n"},{"id":"85063","messageId":"alpine.DEB.1.00.0807261623530.26810@eeepc-johanness","threadId":"14685","inReplyTo":"1217049644-8874-3-git-send-email-s-beyer@gmx.net","subject":"Re: [PATCH 2/5] Add git-sequencer documentation","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2008-07-26T14:47:46Z","receivedAt":"2008-07-26T14:47:46Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Sat, 26 Jul 2008, Stephan Beyer wrote:\n\n> +-B::\n> +--batch::\n> +\tRun in batch mode. If unexpected user intervention is needed\n> +\t(e.g. a conflict or the need to run an editor), 'git-sequencer' fails.\n\nDoes it abort, or leave a dirty tree?\n\n> +--onto=<base>::\n> +\tCheckout given commit or branch before sequencing.\n> +\tIf you provide a branch, sequencer will make the provided\n> +\tchanges on the branch, i.e. the branch will be changed.\n\nWhoa, does that mean that\n\n\t$ git checkout my-private-branch\n\t$ git sequencer --onto=master\n\nwill change _master_?\n\n> +--continue::\n> +\tRestart the sequencing process after having resolved a merge conflict.\n\nWhat about 'edit'?  Does it restart the sequencing process after editing a \nfile or commit message, too?\n\n> +--skip::\n> +\tRestart the sequencing process by skipping the current instruction.\n\ns/ by/,/\n\n> +--status::\n> +\tShow the current status of 'git-sequencer' and what\n> +\toperations can be done to change that status.\n\nNice.\n\n> +--edit::\n> +\tInvoke editor to edit the unprocessed part of the TODO file.\n\nNice!\n\n> +If you nonetheless noticed that you made a mistake, you can\n> +overwrite `.git/sequencer/todo` with `.git/sequencer/todo.old` and\n> +rerun `git sequencer --edit`.\n\nSpeaking of \"todo\": there was an explicit request to change that to \n\"git-rebase-todo\" for rebase -i, so that syntax highlighting could be \nswitched on.\n\n> +-q::\n> +--quiet::\n> +\tSuppress output. Implies `--no-advice`.\n> +\t(Not yet implemented.)\n\nSo this is not meant for application yet.  Okay.\n\n> +-v::\n> +--verbose::\n> +\tBe more verbose.\n\nMore?\n\n> +NOTES\n> +-----\n> +\n> +When sequencing, it is possible, that you are changing the history of\n\ns/possible,/possible/  I know that mistake, being a German myself.\n\n> +a branch in a way that can cause problems for anyone who already has\n> +a copy of the branch in their repository and tries to pull updates from\n> +you.  You should understand the implications of using 'git-sequencer' on\n> +a repository that you share.\n\nHow about this instead?\n\n\tNote that sequencing will rewrite the history of the branch.  \n\tThis will cause problems if you published the branch prior to\n\trewriting the history, as the former tip is no longer an \n\tancestor of the new tip.\n\n\tIn other words, if you rewrite an already published branch, users \n\tthat pull from you _will_ get a bogus merge.\n\t\n> +'git-sequencer' will usually be called by another git porcelain, like\n\ns/another git procelain/other git programs/\n\n> +TODO FILE FORMAT\n> +----------------\n> +\n> +The TODO file contains basically one instruction per line.\n\ns/basically //\n\n> +edit <commit>::\n> +\tPick a commit and pause the sequencer process to let you\n> +\tmake changes.\n> ++\n> +This is a short form for `pick <commit> and `pause` on separate lines.\n\nIt might make sense to explain 'pick' before 'edit', then.\n\n> +mark <mark>::\n> +\tSet a symbolic mark for the last commit.\n> +\t`<mark>` is an unsigned integer starting at 1 and\n> +\tprefixed with a colon, e.g. `:1`.\n> ++\n> +The marks can help if you want to refer to commits that you\n> +created during the sequencer process, e.g. if you want to\n> +merge such a commit.\n\nIt might make sense to explain 'merge' before that, then.\n\n> +\t--mainline=<n>;;\n> +\t\tAllow you to pick merge commits by specifying the\n> +\t\tparent number (beginning from 1) to let sequencer\n> +\t\treplay the changes relative to the specified parent.\n\nWhy is this called \"mainline\", and not \"parent\"?\n\n> [... talking about 'patch']\n>\n> +\t--exclude=<path-pattern>;;\n> +\t\tDo not apply changes to files matching the given path pattern.\n> +\t\tThis can be useful when importing patchsets, where you want to\n> +\t\texclude certain files or directories.\n\nYou might just as well support the new \"--directory\" option of git-apply, \ntoo, and/or --recount.\n\n> [talking about 'squash']\n>\n> +\t--collect-signoffs;;\n> +\t\tCollect the Signed-off-by: lines of each commit and\n> +\t\tadd them to the squashed commit message.\n> +\t\t(Not yet implemented.)\n\nI really have to wonder how useful that is.  Or how correct, for that \nmatter.\n\n> +\n> +\t--include-merges;;\n> +\t\tSanity check does not fail if you have merges\n> +\t\tbetween HEAD and <mark>.\n\nIt may be a commit, too, right?  And why does it make sense to check that \nthere are no merges?  I mean, it is just as if I did two cherry-picks, the \nsecond with -n, and then commit --amend it.  Can make tons of sense...\n\n> +Here are some examples that shall ease the start with the TODO\n> +file format.\n> +Make sure you have understood the `pick` and perhaps the `patch` command.\n> +Those will not be explained further.\n\nThis sentence is insulting.  Strike it.\n\n> +------------\n> +$ git rev-list --no-merges --reverse A^..E | sed -e 's/^/pick /'`\n> +------------\n\nDon't.\n\n$ git log --pretty=format:'pick %h' --no-merges --reverse A^..E\n\nCiao,\nDscho\n"},{"id":"85064","messageId":"alpine.DEB.1.00.0807261652050.26810@eeepc-johanness","threadId":"14685","inReplyTo":"1217049644-8874-6-git-send-email-s-beyer@gmx.net","subject":"Re: [PATCH 5/5] Migrate rebase-i to sequencer","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2008-07-26T14:52:33Z","receivedAt":"2008-07-26T14:52:33Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Sat, 26 Jul 2008, Stephan Beyer wrote:\n\n> For git-rebase-i -p (preserving merges) merges should be\n> rewritten. For this, the sequencer instructions \"mark\", \"merge\"\n> and \"reset\" are used.\n\nAh, the ugliness returns.\n\nCiao,\nDscho\n"},{"id":"85094","messageId":"bd6139dc0807261001l23e130fu7714f0e1fe773a5@mail.gmail.com","threadId":"14685","inReplyTo":"alpine.DEB.1.00.0807261617010.26810@eeepc-johanness","subject":"Re: git sequencer prototype","fromName":"Sverre Rabbelier","fromEmail":"alturin@gmail.com","sentAt":"2008-07-26T17:01:26Z","receivedAt":"2008-07-26T17:01:26Z","isPatch":false,"sender":{"key":"alturin@gmail.com","avatar":null},"body":"On Sat, Jul 26, 2008 at 16:19, Johannes Schindelin\n<Johannes.Schindelin@gmx.de> wrote:\n> Why is it no issue for the builtin?  Is it so much different from the\n> prototype?\n\nBecause it's blazing fast :P.\n\n-- \nCheers,\n\nSverre Rabbelier\n"},{"id":"85603","messageId":"20080730121454.GA8767@leksak.fem-net","threadId":"14685","inReplyTo":"alpine.DEB.1.00.0807261623530.26810@eeepc-johanness","subject":"Re: [PATCH 2/5] Add git-sequencer documentation","fromName":"Stephan Beyer","fromEmail":"s-beyer@gmx.net","sentAt":"2008-07-30T12:14:54Z","receivedAt":"2008-07-30T12:14:54Z","isPatch":true,"sender":{"key":"s-beyer@gmx.net","avatar":"https://avatars.githubusercontent.com/u/143889?v=4"},"body":"Hi,\n\nJohannes Schindelin wrote:\n> > +-B::\n> > +--batch::\n> > +\tRun in batch mode. If unexpected user intervention is needed\n> > +\t(e.g. a conflict or the need to run an editor), 'git-sequencer' fails.\n> \n> Does it abort, or leave a dirty tree?\n\nIt aborts.\nPerhaps I should make this clear in the docs.\n\n> > +--onto=<base>::\n> > +\tCheckout given commit or branch before sequencing.\n> > +\tIf you provide a branch, sequencer will make the provided\n> > +\tchanges on the branch, i.e. the branch will be changed.\n> \n> Whoa, does that mean that\n> \n> \t$ git checkout my-private-branch\n> \t$ git sequencer --onto=master\n> \n> will change _master_?\n\nExactly.\n\n> > +--continue::\n> > +\tRestart the sequencing process after having resolved a merge conflict.\n> \n> What about 'edit'?  Does it restart the sequencing process after editing a \n> file or commit message, too?\n\nYes. Thanks.\n\n> > +If you nonetheless noticed that you made a mistake, you can\n> > +overwrite `.git/sequencer/todo` with `.git/sequencer/todo.old` and\n> > +rerun `git sequencer --edit`.\n> \n> Speaking of \"todo\": there was an explicit request to change that to \n> \"git-rebase-todo\" for rebase -i, so that syntax highlighting could be \n> switched on.\n\nI'd not have a problem with that, though the name \"rebase\" is not\nnecessarily correct and the syntax files had to be extended\nnevertheless.\n\n> > +-v::\n> > +--verbose::\n> > +\tBe more verbose.\n> \n> More?\n\nHehe, the note that \"more\" has to be defined more accurately, has been\nremoved. But it is still true. ;)\n\n> > +a branch in a way that can cause problems for anyone who already has\n> > +a copy of the branch in their repository and tries to pull updates from\n> > +you.  You should understand the implications of using 'git-sequencer' on\n> > +a repository that you share.\n> \n> How about this instead?\n> \n> \tNote that sequencing will rewrite the history of the branch.  \n\nIt will not necessarily rewrite history of a branch. In case of the\nrebase user command, it does, of course.\n\n> \tThis will cause problems if you published the branch prior to\n> \trewriting the history, as the former tip is no longer an \n> \tancestor of the new tip.\n> \n> \tIn other words, if you rewrite an already published branch, users \n> \tthat pull from you _will_ get a bogus merge.\n\nYes, I can take that.\n\nWell, I wanted only a short note and the user command that really\nrewrites branches could have a more detailed warning.\n\n> > +'git-sequencer' will usually be called by another git porcelain, like\n> \n> s/another git procelain/other git programs/\n\nOk, I use \"other git commands\", since this wording seems to be the leading\none in other documentation.\n\n> > +TODO FILE FORMAT\n> > +----------------\n> > +\n> > +The TODO file contains basically one instruction per line.\n> \n> s/basically //\n\nOh, this is from the times where we included some possible extensions,\nlike a trailing backslash.\n\n> > +edit <commit>::\n> > +\tPick a commit and pause the sequencer process to let you\n> > +\tmake changes.\n> > ++\n> > +This is a short form for `pick <commit> and `pause` on separate lines.\n> \n> It might make sense to explain 'pick' before 'edit', then.\n\nThis is kept alphabetically.\n\nWhen first writing that, I wondered if this makes sense:\na reference-like list should be sorted alphabetically, a tutorial-like\nlist should have some kind of logical structure.\nI do not really care if we prefer this or that one. So I take your\nreordering suggestion until somebody complains again :)\n\n> > +\t--mainline=<n>;;\n> > +\t\tAllow you to pick merge commits by specifying the\n> > +\t\tparent number (beginning from 1) to let sequencer\n> > +\t\treplay the changes relative to the specified parent.\n> \n> Why is this called \"mainline\", and not \"parent\"?\n\nBecause git-cherry-pick/git-revert has \"--mainline\" and I did not want\nto rename this.\n\n> > [talking about 'squash']\n> >\n> > +\t--collect-signoffs;;\n> > +\t\tCollect the Signed-off-by: lines of each commit and\n> > +\t\tadd them to the squashed commit message.\n> > +\t\t(Not yet implemented.)\n> \n> I really have to wonder how useful that is.  Or how correct, for that \n> matter.\n\nThis is just some kind of squashing Signed-off-by: lines.\nIt was requested by someone (Paolo?) in the RFC git-sequencer.txt thread.\n\nThe behavior is planned like this:\n\nInstead of...\n\n\tMessage of commit 1\n\t\n\tSigned-off-by: A\n\t\n\tMessage of commit 2\n\t\n\tSigned-off-by: B\n\t\n\tMessage of commit 3\n\t\n\tSigned-off-by: A\n\tSigned-off-by: C\n\n...the user gets...\n\n\tMessage of commit 1\n\t\n\tMessage of commit 2\n\t\n\tMessage of commit 3\n\t\n\tSigned-off-by: A\n\tSigned-off-by: B\n\tSigned-off-by: C\n\nusing --collect-signoffs and no commit-message-changing options.\n\nWith --message=\"Foo\" this will be:\n\n\tFoo\n\t\n\tSigned-off-by: A\n\tSigned-off-by: B\n\tSigned-off-by: C\n\nFor me this sounds like making sense and being useful, but I have not yet\ndigged so deep into the rules of signing off :)\n\n> > +\t--include-merges;;\n> > +\t\tSanity check does not fail if you have merges\n> > +\t\tbetween HEAD and <mark>.\n> \n> It may be a commit, too, right?  And why does it make sense to check that \n> there are no merges?  I mean, it is just as if I did two cherry-picks, the \n> second with -n, and then commit --amend it.  Can make tons of sense...\n\nI think I mean something different. With \"merges\" I am talking about\ncommits having more than one parent.\nBy this check I want to make sure, that the user really knows what he\ndoes when he wants to squash the ones marked with ~ into one commit.\n\n         ~~~~~~~~~~~~~\n  ..-A---B---C---D---E---F\n            /\n  ..-X---Y--\n\nYet I didn't really care what happens then and perhaps it should be:\n\n ..--A---S--F\n        /\n ..-X-Y-\n\nIn the prototype the squashing is done by soft-resetting to the\nsquash base and then commit. As I said, I did not really care if\nmy painted result really happens.  In the builtin it will happen :)\n\n> > +Here are some examples that shall ease the start with the TODO\n> > +file format.\n> > +Make sure you have understood the `pick` and perhaps the `patch` command.\n> > +Those will not be explained further.\n> \n> This sentence is insulting.  Strike it.\n\nThe \"Make sure ...\" sentence?  It really is insulting?\nDo you think it implies the assumption that the user will not grasp\npatch/pick easily?\n\n\nThanks for your reply and your other notes. (The ones I didn't comment\nare just ACKed.)\n\nRegards,\n  Stephan\n\n-- \nStephan Beyer <s-beyer@gmx.net>, PGP 0x6EDDD207FCC5040F\n"},{"id":"85604","messageId":"20080730121458.GB8767@leksak.fem-net","threadId":"14685","inReplyTo":"alpine.DEB.1.00.0807261617010.26810@eeepc-johanness","subject":"Re: git sequencer prototype","fromName":"Stephan Beyer","fromEmail":"s-beyer@gmx.net","sentAt":"2008-07-30T12:14:58Z","receivedAt":"2008-07-30T12:14:58Z","isPatch":false,"sender":{"key":"s-beyer@gmx.net","avatar":"https://avatars.githubusercontent.com/u/143889?v=4"},"body":"Hi,\n\nJohannes Schindelin wrote:\n> > In the last patchset I mentioned the issue, that the prototype is slow\n> > as hell.  I know some bottlenecks, but I have not even tried to change\n> > that, because this is no issue for the builtin.\n> \n> Why is it no issue for the builtin?  Is it so much different from the \n> prototype?\n\nAs Sverre pointed out and as my \"experiments\" tried to show: the builtin\nis just fast ;-)\n\n> Personally, I think if the prototype is so much slower, there is no sense \n> applying it into git.git,\n\nRight.\n\nRegards,\n  Stephan\n\n-- \nStephan Beyer <s-beyer@gmx.net>, PGP 0x6EDDD207FCC5040F\n"},{"id":"85606","messageId":"20080730121810.GC8767@leksak.fem-net","threadId":"14685","inReplyTo":"alpine.DEB.1.00.0807261652050.26810@eeepc-johanness","subject":"Re: [PATCH 5/5] Migrate rebase-i to sequencer","fromName":"Stephan Beyer","fromEmail":"s-beyer@gmx.net","sentAt":"2008-07-30T12:18:10Z","receivedAt":"2008-07-30T12:18:10Z","isPatch":true,"sender":{"key":"s-beyer@gmx.net","avatar":"https://avatars.githubusercontent.com/u/143889?v=4"},"body":"Hi,\n\nJohannes Schindelin wrote:\n> Hi,\n> \n> On Sat, 26 Jul 2008, Stephan Beyer wrote:\n> \n> > For git-rebase-i -p (preserving merges) merges should be\n> > rewritten. For this, the sequencer instructions \"mark\", \"merge\"\n> > and \"reset\" are used.\n> \n> Ah, the ugliness returns.\n\nYet I have not seen a way that is as flexible and clean as using\nmark/merge/reset and imho this is not ugly.\n(I know the discussion of the Joerg Sommer patches that introduced mark,\nmerge and reset.)\n\nRegards.\n\n-- \nStephan Beyer <s-beyer@gmx.net>, PGP 0x6EDDD207FCC5040F\n"},{"id":"85626","messageId":"alpine.LSU.1.00.0807301556140.3486@wbgn129.biozentrum.uni-wuerzburg.de","threadId":"14685","inReplyTo":"20080730121454.GA8767@leksak.fem-net","subject":"Re: [PATCH 2/5] Add git-sequencer documentation","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2008-07-30T14:06:42Z","receivedAt":"2008-07-30T14:06:42Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Wed, 30 Jul 2008, Stephan Beyer wrote:\n\n> Johannes Schindelin wrote:\n> > > +-B::\n> > > +--batch::\n> > > +\tRun in batch mode. If unexpected user intervention is needed\n> > > +\t(e.g. a conflict or the need to run an editor), 'git-sequencer' fails.\n> > \n> > Does it abort, or leave a dirty tree?\n> \n> It aborts.\n> Perhaps I should make this clear in the docs.\n\nNo, just leave it as is.  The users can always ask you on the mailing \nlist.  So my comment was totally unfounded.\n\n> > > +--onto=<base>::\n> > > +\tCheckout given commit or branch before sequencing.\n> > > +\tIf you provide a branch, sequencer will make the provided\n> > > +\tchanges on the branch, i.e. the branch will be changed.\n> > \n> > Whoa, does that mean that\n> > \n> > \t$ git checkout my-private-branch\n> > \t$ git sequencer --onto=master\n> > \n> > will change _master_?\n> \n> Exactly.\n\n/me does not like that.  I could see a new porcelain doing that, but not \nthe thing that will be called by rebase.\n\n> > > +\t--include-merges;;\n> > > +\t\tSanity check does not fail if you have merges\n> > > +\t\tbetween HEAD and <mark>.\n> > \n> > It may be a commit, too, right?  And why does it make sense to check that \n> > there are no merges?  I mean, it is just as if I did two cherry-picks, the \n> > second with -n, and then commit --amend it.  Can make tons of sense...\n> \n> I think I mean something different. With \"merges\" I am talking about\n> commits having more than one parent.\n\nYes, I read \"merges\" the same way.  My comment still stands.\n\n> Thanks for your reply and your other notes. (The ones I didn't comment \n> are just ACKed.)\n\nThe ones that _I_ did not comment on I do not necessarily agree with, but \nthen, I do not have the time to argue about them.\n\nCiao,\nDscho\n"},{"id":"85627","messageId":"alpine.LSU.1.00.0807301607070.3486@wbgn129.biozentrum.uni-wuerzburg.de","threadId":"14685","inReplyTo":"20080730121458.GB8767@leksak.fem-net","subject":"Re: git sequencer prototype","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2008-07-30T14:07:49Z","receivedAt":"2008-07-30T14:07:49Z","isPatch":false,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Wed, 30 Jul 2008, Stephan Beyer wrote:\n\n> Johannes Schindelin wrote:\n> >\n> > > In the last patchset I mentioned the issue, that the prototype is \n> > > slow as hell.  I know some bottlenecks, but I have not even tried to \n> > > change that, because this is no issue for the builtin.\n> > \n> > Why is it no issue for the builtin?  Is it so much different from the \n> > prototype?\n> \n> As Sverre pointed out and as my \"experiments\" tried to show: the builtin\n> is just fast ;-)\n\nSo why is it just so fast?  Does it do things completely different than \nthe shell prototype you presented?\n\nStill puzzled,\nDscho\n"},{"id":"85639","messageId":"alpine.LNX.1.00.0807301121270.19665@iabervon.org","threadId":"14685","inReplyTo":"alpine.LSU.1.00.0807301556140.3486@wbgn129.biozentrum.uni-wuerzburg.de","subject":"Re: [PATCH 2/5] Add git-sequencer documentation","fromName":"Daniel Barkalow","fromEmail":"barkalow@iabervon.org","sentAt":"2008-07-30T15:32:40Z","receivedAt":"2008-07-30T15:32:40Z","isPatch":true,"sender":{"key":"barkalow@iabervon.org","avatar":"https://avatars.githubusercontent.com/u/55364219?v=4"},"body":"On Wed, 30 Jul 2008, Johannes Schindelin wrote:\n\n> On Wed, 30 Jul 2008, Stephan Beyer wrote:\n> \n> > Johannes Schindelin wrote:\n> >\n> > > Whoa, does that mean that\n> > > \n> > > \t$ git checkout my-private-branch\n> > > \t$ git sequencer --onto=master\n> > > \n> > > will change _master_?\n> > \n> > Exactly.\n> \n> /me does not like that.  I could see a new porcelain doing that, but not \n> the thing that will be called by rebase.\n\nYeah, an option to change which branch is current should be called \nsomething different. --onto is an initial reset --hard, not an initial \ncheckout; it specifies the branch (or commit) that the sequence of changes \nare done on top of, not the branch that will contain them. \"Onto\" (as an \nenglish preposition) specifies a destination, not a location, so it \ndoesn't make sense as the location that stuff is done.\n\n\t-Daniel\n*This .sig left intentionally blank*\n"},{"id":"85769","messageId":"20080731124000.GA18106@leksak.fem-net","threadId":"14685","inReplyTo":"alpine.LSU.1.00.0807301607070.3486@wbgn129.biozentrum.uni-wuerzburg.de","subject":"Re: git sequencer prototype","fromName":"Stephan Beyer","fromEmail":"s-beyer@gmx.net","sentAt":"2008-07-31T12:40:00Z","receivedAt":"2008-07-31T12:40:00Z","isPatch":false,"sender":{"key":"s-beyer@gmx.net","avatar":"https://avatars.githubusercontent.com/u/143889?v=4"},"body":"Johannes Schindelin wrote:\n> On Wed, 30 Jul 2008, Stephan Beyer wrote:\n> > Johannes Schindelin wrote:\n> > >\n> > > > In the last patchset I mentioned the issue, that the prototype is \n> > > > slow as hell.  I know some bottlenecks, but I have not even tried to \n> > > > change that, because this is no issue for the builtin.\n> > > \n> > > Why is it no issue for the builtin?  Is it so much different from the \n> > > prototype?\n> > \n> > As Sverre pointed out and as my \"experiments\" tried to show: the builtin\n> > is just fast ;-)\n> \n> So why is it just so fast?  Does it do things completely different than \n> the shell prototype you presented?\n\nAh, that's the point of your question ;)\n\nNo, it's different in some minor parts, of course, but the important thing\nis: it is C, not sh.  That's what makes it faster.\n\nRegards.\n\n-- \nStephan Beyer <s-beyer@gmx.net>, PGP 0x6EDDD207FCC5040F\n"},{"id":"85775","messageId":"20080731125302.GB18106@leksak.fem-net","threadId":"14685","inReplyTo":"alpine.LSU.1.00.0807301556140.3486@wbgn129.biozentrum.uni-wuerzburg.de","subject":"Re: [PATCH 2/5] Add git-sequencer documentation","fromName":"Stephan Beyer","fromEmail":"s-beyer@gmx.net","sentAt":"2008-07-31T12:53:02Z","receivedAt":"2008-07-31T12:53:02Z","isPatch":true,"sender":{"key":"s-beyer@gmx.net","avatar":"https://avatars.githubusercontent.com/u/143889?v=4"},"body":"Hi,\n\nJohannes Schindelin wrote:\n> > > > +--onto=<base>::\n> > > > +\tCheckout given commit or branch before sequencing.\n> > > > +\tIf you provide a branch, sequencer will make the provided\n> > > > +\tchanges on the branch, i.e. the branch will be changed.\n> > > \n> > > Whoa, does that mean that\n> > > \n> > > \t$ git checkout my-private-branch\n> > > \t$ git sequencer --onto=master\n> > > \n> > > will change _master_?\n> > \n> > Exactly.\n> \n> /me does not like that.  I could see a new porcelain doing that, but not \n> the thing that will be called by rebase.\n\n$ git sequencer --onto=master todofile\n\nis equal to:\n\n$ git checkout $(git rev-parse master)          # detached HEAD\n$ git sequencer todofile\nAnd when successfully finished:\n\t$ git update-ref refs/heads/master HEAD # reattach branch\n\nYet this seemed to be useful.\n(But perhaps the name --onto is wrong...)\n\n> > > > +\t--include-merges;;\n> > > > +\t\tSanity check does not fail if you have merges\n> > > > +\t\tbetween HEAD and <mark>.\n> > > \n> > > It may be a commit, too, right?  And why does it make sense to check that \n> > > there are no merges?  I mean, it is just as if I did two cherry-picks, the \n> > > second with -n, and then commit --amend it.  Can make tons of sense...\n> > \n> > I think I mean something different. With \"merges\" I am talking about\n> > commits having more than one parent.\n> \n> Yes, I read \"merges\" the same way.  My comment still stands.\n\nIf you really mean that it's the same as doing two cherry-picks and\nsquashing the second into the first, I don't get what your comment has\nin common with merges.\n\nIf you mean squashing a merge and some cherry-picks on top of that merge\ninto one merge commit: that is possible. It's only checked that no merges\nare *in between* currently.\n\nIn graphics: squashing\n\n           ..--M--X--Y-                   ..-A--M--X--Y\n              /                                /\n           ..-                              ..-\n\n            is allowed                 is only allowed with\n                                       --include-merges\n\nRegards.\n\n-- \nStephan Beyer <s-beyer@gmx.net>, PGP 0x6EDDD207FCC5040F\n"}]}