{"thread":{"id":"12825","subject":"[PATCH 3/4] Add a function for get the parents of a commit","startedAt":"2008-03-23T21:42:39Z","lastAt":"2008-05-04T12:52:58Z","messageCount":104,"participants":["Jörg Sommer","Johannes Schindelin","Junio C Hamano","Mike Ralphson","Shawn O. Pearce","Tarmigan","Johannes Sixt","Dmitry Potapov"],"isPatch":true,"patchVersion":1,"patchTotal":4},"messages":[{"id":"72818","messageId":"1206308562-31489-1-git-send-email-joerg@alea.gnuu.de","threadId":"12825","inReplyTo":null,"subject":"[PATCH 1/4] Move redo merge code in a function","fromName":"Jörg Sommer","fromEmail":"joerg@alea.gnuu.de","sentAt":"2008-03-23T21:42:39Z","receivedAt":"2008-03-23T21:42:39Z","isPatch":true,"sender":{"key":"joerg@alea.gnuu.de","avatar":null},"body":"\nSigned-off-by: Jörg Sommer <joerg@alea.gnuu.de>\n---\n git-rebase--interactive.sh |   31 +++++++++++++++++--------------\n 1 files changed, 17 insertions(+), 14 deletions(-)\n\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex 8aa7371..1b2381e 100755\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -113,6 +113,22 @@ has_action () {\n \tgrep '^[^#]' \"$1\" >/dev/null\n }\n \n+redo_merge() {\n+\tauthor_script=$(get_author_ident_from_commit $sha1)\n+\teval \"$author_script\"\n+\tmsg=\"$(git cat-file commit $sha1 | sed -e '1,/^$/d')\"\n+\tif ! GIT_AUTHOR_NAME=\"$GIT_AUTHOR_NAME\" \\\n+\t\tGIT_AUTHOR_EMAIL=\"$GIT_AUTHOR_EMAIL\" \\\n+\t\tGIT_AUTHOR_DATE=\"$GIT_AUTHOR_DATE\" \\\n+\t\toutput git merge $STRATEGY -m \"$msg\" \\\n+\t\t\t$new_parents\n+\tthen\n+\t\tgit rerere\n+\t\tprintf \"%s\\n\" \"$msg\" > \"$GIT_DIR\"/MERGE_MSG\n+\t\tdie Error redoing merge $sha1\n+\tfi\n+}\n+\n pick_one () {\n \tno_ff=\n \tcase \"$1\" in -n) sha1=$2; no_ff=t ;; *) sha1=$1 ;; esac\n@@ -180,22 +196,9 @@ pick_one_preserving_merges () {\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\tredo_merge\n \t\t\t;;\n \t\t*)\n \t\t\toutput git cherry-pick \"$@\" ||\n-- \n1.5.4.4\n"},{"id":"72816","messageId":"1206308562-31489-2-git-send-email-joerg@alea.gnuu.de","threadId":"12825","inReplyTo":"1206308562-31489-1-git-send-email-joerg@alea.gnuu.de","subject":"[PATCH 2/4] Rework redo_merge","fromName":"Jörg Sommer","fromEmail":"joerg@alea.gnuu.de","sentAt":"2008-03-23T21:42:40Z","receivedAt":"2008-03-23T21:42:40Z","isPatch":true,"sender":{"key":"joerg@alea.gnuu.de","avatar":null},"body":"\nSigned-off-by: Jörg Sommer <joerg@alea.gnuu.de>\n---\n git-rebase--interactive.sh |   13 +++++++------\n 1 files changed, 7 insertions(+), 6 deletions(-)\n\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex 1b2381e..ffd4823 100755\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -114,14 +114,16 @@ has_action () {\n }\n \n redo_merge() {\n-\tauthor_script=$(get_author_ident_from_commit $sha1)\n-\teval \"$author_script\"\n+\tsha1=$1\n+\tshift\n+\n+\teval \"$(get_author_ident_from_commit $sha1)\"\n \tmsg=\"$(git cat-file commit $sha1 | sed -e '1,/^$/d')\"\n+\n \tif ! GIT_AUTHOR_NAME=\"$GIT_AUTHOR_NAME\" \\\n \t\tGIT_AUTHOR_EMAIL=\"$GIT_AUTHOR_EMAIL\" \\\n \t\tGIT_AUTHOR_DATE=\"$GIT_AUTHOR_DATE\" \\\n-\t\toutput git merge $STRATEGY -m \"$msg\" \\\n-\t\t\t$new_parents\n+\t\toutput git merge $STRATEGY -m \"$msg\" \"$@\"\n \tthen\n \t\tgit rerere\n \t\tprintf \"%s\\n\" \"$msg\" > \"$GIT_DIR\"/MERGE_MSG\n@@ -197,8 +199,7 @@ pick_one_preserving_merges () {\n \t\tcase \"$new_parents\" in\n \t\t' '*' '*)\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\tredo_merge\n+\t\t\tredo_merge $sha1 ${new_parents# $first_parent}\n \t\t\t;;\n \t\t*)\n \t\t\toutput git cherry-pick \"$@\" ||\n-- \n1.5.4.4\n"},{"id":"72815","messageId":"1206308562-31489-3-git-send-email-joerg@alea.gnuu.de","threadId":"12825","inReplyTo":"1206308562-31489-2-git-send-email-joerg@alea.gnuu.de","subject":"[PATCH 3/4] Add a function for get the parents of a commit","fromName":"Jörg Sommer","fromEmail":"joerg@alea.gnuu.de","sentAt":"2008-03-23T21:42:41Z","receivedAt":"2008-03-23T21:42:41Z","isPatch":true,"sender":{"key":"joerg@alea.gnuu.de","avatar":null},"body":"\nSigned-off-by: Jörg Sommer <joerg@alea.gnuu.de>\n---\n git-rebase--interactive.sh |    6 +++++-\n 1 files changed, 5 insertions(+), 1 deletions(-)\n\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex ffd4823..94c6827 100755\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -131,6 +131,10 @@ redo_merge() {\n \tfi\n }\n \n+parents_of_commit() {\n+\tgit rev-list --parents -1 \"$1\" | cut -d' ' -f2-\n+}\n+\n pick_one () {\n \tno_ff=\n \tcase \"$1\" in -n) sha1=$2; no_ff=t ;; *) sha1=$1 ;; esac\n@@ -166,7 +170,7 @@ pick_one_preserving_merges () {\n \tfast_forward=t\n \tpreserve=t\n \tnew_parents=\n-\tfor p in $(git rev-list --parents -1 $sha1 | cut -d' ' -f2-)\n+\tfor p in $(parents_of_commit $sha1)\n \tdo\n \t\tif test -f \"$REWRITTEN\"/$p\n \t\tthen\n-- \n1.5.4.4\n"},{"id":"72817","messageId":"1206308562-31489-4-git-send-email-joerg@alea.gnuu.de","threadId":"12825","inReplyTo":"1206308562-31489-3-git-send-email-joerg@alea.gnuu.de","subject":"[PATCH 4/4] git-rebase -i: New option to support rebase with merges","fromName":"Jörg Sommer","fromEmail":"joerg@alea.gnuu.de","sentAt":"2008-03-23T21:42:42Z","receivedAt":"2008-03-23T21:42:42Z","isPatch":true,"sender":{"key":"joerg@alea.gnuu.de","avatar":null},"body":"The option --preserve-merges does not allow to change the order of\ncommits or squash them. The new option --linear-history does support\nthis, but doing so it can only look at the commits reachable with through\nthe first parent of each merge.\n\nJoining merge commits with other commits leads to problems, because git\nmerge fails with a dirty index (the case “COMMIT squash MERGE”) and\nsquashing a merge leads to the lost of the parents (case “MERGE squash\nCOMMIT”). Therefore, I've prohibited these cases.\n\nSigned-off-by: Jörg Sommer <joerg@alea.gnuu.de>\n---\n Documentation/git-rebase.txt  |    8 ++++\n git-rebase--interactive.sh    |   27 +++++++++++++++-\n t/t3404-rebase-interactive.sh |   72 +++++++++++++++++++++++++++++++++++++++++\n 3 files changed, 106 insertions(+), 1 deletions(-)\n\nI had no better idea for a name of this new option. Propositions are\nwelcome.\n\ndiff --git a/Documentation/git-rebase.txt b/Documentation/git-rebase.txt\nindex e0412e0..354b6f0 100644\n--- a/Documentation/git-rebase.txt\n+++ b/Documentation/git-rebase.txt\n@@ -11,6 +11,7 @@ SYNOPSIS\n 'git-rebase' [-i | --interactive] [-v | --verbose] [-m | --merge]\n \t[-s <strategy> | --strategy=<strategy>]\n \t[-C<n>] [ --whitespace=<option>] [-p | --preserve-merges]\n+\t[-l | --linear-history]\n \t[--onto <newbase>] <upstream> [<branch>]\n 'git-rebase' --continue | --skip | --abort\n \n@@ -247,6 +248,13 @@ OPTIONS\n \tInstead of ignoring merges, try to recreate them.  This option\n \tonly works in interactive mode.\n \n+-l, \\--linear-history::\n+\tUse only commits of the branch they are not merged in, i.e.\n+\tfollow only the first parent of a merge. Merges are part of this\n+\tlist and they will be redone. It's possible to move merges in the\n+\thistory forward and backward, but they can't take part on a join\n+\t(squash). This option only works in interactive mode.\n+\n include::merge-strategies.txt[]\n \n NOTES\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex 94c6827..a2a61f8 100755\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -26,9 +26,11 @@ REWRITTEN=\"$DOTEST\"/rewritten\n PRESERVE_MERGES=\n STRATEGY=\n VERBOSE=\n+LINEAR_HISTORY=\n test -d \"$REWRITTEN\" && PRESERVE_MERGES=t\n test -f \"$DOTEST\"/strategy && STRATEGY=\"$(cat \"$DOTEST\"/strategy)\"\n test -f \"$DOTEST\"/verbose && VERBOSE=t\n+test -f \"$DOTEST\"/linear_history && LINEAR_HISTORY=t\n \n GIT_CHERRY_PICK_HELP=\"  After resolving the conflicts,\n mark the corrected paths with 'git add <paths>', and\n@@ -150,7 +152,18 @@ pick_one () {\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+\t\tif test t = \"$LINEAR_HISTORY\" &&\n+\t\t\tother_parents=\"$(parents_of_commit $sha1 | cut -s -d' ' -f2-)\" &&\n+\t\t\ttest -n \"$other_parents\"\n+\t\tthen\n+\t\t\tif test a\"$1\" = a-n\n+\t\t\tthen\n+\t\t\t\tmerge_opt=--no-commit\n+\t\t\tfi\n+\t\t\tredo_merge $sha1 $no_commit $other_parents\n+\t\telse\n+\t\t\toutput git cherry-pick \"$@\"\n+\t\tfi\n \tfi\n }\n \n@@ -288,6 +301,11 @@ do_next () {\n \t\thas_action \"$DONE\" ||\n \t\t\tdie \"Cannot 'squash' without a previous commit\"\n \n+\t\ttest t = \"$LINEAR_HISTORY\" &&\n+\t\t\t( test \"$(parents_of_commit HEAD |wc -w)\" -gt 1 ||\n+\t\t\t\t test \"$(parents_of_commit $sha1 |wc -w)\" -gt 1) &&\n+\t\t\tdie \"Joining a merge with a commit is not supported\"\n+\n \t\tmark_action_done\n \t\tmake_squash_message $sha1 > \"$MSG\"\n \t\tcase \"$(peek_next_command)\" in\n@@ -459,6 +477,9 @@ do\n \t-i|--interactive)\n \t\t# yeah, we know\n \t\t;;\n+\t-l|--linear-history)\n+\t\tLINEAR_HISTORY=t\n+\t\t;;\n \t''|-h)\n \t\tusage\n \t\t;;\n@@ -522,6 +543,10 @@ do\n \t\t\t\t\tdie \"Could not init rewritten commits\"\n \t\t\tdone\n \t\t\tMERGES_OPTION=\n+\t\telif test t = \"$LINEAR_HISTORY\"\n+\t\tthen\n+\t\t\t: > \"$DOTEST\"/linear_history\n+\t\t\tMERGES_OPTION=--first-parent\n \t\telse\n \t\t\tMERGES_OPTION=--no-merges\n \t\tfi\ndiff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh\nindex 9cf873f..0476f6a 100755\n--- a/t/t3404-rebase-interactive.sh\n+++ b/t/t3404-rebase-interactive.sh\n@@ -361,4 +361,76 @@ test_expect_success 'rebase with a file named HEAD in worktree' '\n \n '\n \n+test_expect_success 'rebase linear history preserves merges' '\n+\tgit tag linear-history-base to-be-preserved~2\n+\tgit checkout -b linear-history linear-history-base &&\n+\tfor i in 1 2 3\n+\tdo\n+\t\ttest $? -eq 0 &&\n+\t\techo linear history test > lin-h-$i &&\n+\t\tgit add lin-h-$i &&\n+\t\ttest_tick &&\n+\t       \tgit commit -m \"rebase linear history commit $i\"\n+\tdone\n+\ttest_tick &&\n+\tgit merge to-be-preserved &&\n+\told_head=$(git rev-parse HEAD) &&\n+\ttest_tick &&\n+\tEXPECT_COUNT=4 FAKE_LINES=\"2 4 edit 1 3\" \\\n+\t\tgit rebase -v -i -l linear-history-base &&\n+\tEXPECT_COUNT=invalid git rebase --continue &&\n+\ttest \"$(git rev-list --parents -1 HEAD~2 | cut -d\" \" -f3-)\" = \\\n+\t\t\"$(git rev-parse to-be-preserved)\" &&\n+\ttest \"$(git show HEAD~2: | grep ^lin-h- | cut -c7- | tr -d \\\\012)\" = 2 &&\n+\ttest \"$(git show HEAD~1: | grep ^lin-h- | cut -c7- | tr -d \\\\012)\" = 12 &&\n+\ttest \"$(git cat-file commit HEAD | sed -n \"/^tree/{p;q;}\")\" = \\\n+\t\t\"$(git cat-file commit $old_head | sed -n \"/^tree/{p;q;}\")\"\n+'\n+\n+test_expect_success 'rebase linear history is noop, if base = base' '\n+\told_head=$(git rev-parse HEAD) &&\n+\ttest_tick &&\n+\tEXPECT_COUNT=4 git rebase -v -i -l linear-history-base &&\n+\ttest \"$(git rev-parse HEAD)\" = $old_head\n+'\n+\n+test_expect_success 'ensure rebase linear history persits across edits' '\n+\told_head=$(git rev-parse HEAD) &&\n+\ttest_tick &&\n+\tEXPECT_COUNT=4 FAKE_LINES=\"edit 1 2 3 4\" \\\n+\t\tgit rebase -v -i -l linear-history-base &&\n+\tEXPECT_COUNT=invalid git rebase --continue &&\n+\ttest \"$(git rev-parse HEAD)\" = $old_head\n+'\n+\n+test_str='test_tick &&\n+\t(\n+\t\toutp=$(test_must_fail git rebase -v -i -l HEAD~3 2>&1)\n+\t\trc=$?\n+\t\techo \"$outp\"\n+        \techo \"$outp\" | grep \"^Joining .* not supported\\$\" >/dev/null &&\n+\t\treturn $rc\n+\t) &&\n+\tgit rebase --abort'\n+\n+test_expect_success 'rebase linear with squashing a merge fails' \"\n+\texport EXPECT_COUNT=3 FAKE_LINES='1 squash 2 3' &&\n+\t$test_str &&\n+\tFAKE_LINES='2 squash 1 3' &&\n+\t$test_str\n+\"\n+\n+test_expect_success 'rebase linear history does a fast forward' '\n+\told_head=$(git rev-parse HEAD) &&\n+\ttest_tick &&\n+\tEXPECT_COUNT=4 FAKE_LINES=\"2 3 4 1\" \\\n+\t\tgit rebase -v -i -l linear-history-base &&\n+\ttest \"$(git rev-parse HEAD~3)\" = \"$(git rev-parse to-be-preserved)\" &&\n+\ttest \"$(git show HEAD~2: | grep ^lin-h- | cut -c7- | tr -d \\\\012)\" = 1 &&\n+\ttest \"$(git show HEAD~1: | grep ^lin-h- | cut -c7- | tr -d \\\\012)\" = 13 &&\n+\ttest -z \"$(git rev-list --parents -1 HEAD~3 | cut -d\" \" -f3-)\" &&\n+\ttest \"$(git cat-file commit HEAD | sed -n \"/^tree/{p;q;}\")\" = \\\n+\t\t\"$(git cat-file commit $old_head | sed -n \"/^tree/{p;q;}\")\"\n+'\n+\n test_done\n-- \n1.5.4.4\n"},{"id":"72820","messageId":"alpine.LSU.1.00.0803232322310.4353@racer.site","threadId":"12825","inReplyTo":"1206308562-31489-1-git-send-email-joerg@alea.gnuu.de","subject":"Re: [PATCH 1/4] Move redo merge code in a function","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2008-03-23T22:26:38Z","receivedAt":"2008-03-23T22:26:38Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Sun, 23 Mar 2008, Jörg Sommer wrote:\n\n> \n> Signed-off-by: Jörg Sommer <joerg@alea.gnuu.de>\n\nI like the patch, but the commit message is not really meaningful if you \ndo not read the patch.  Maybe you want to prefix it with \"rebase -i:\"?  \nAnd _just_ maybe you want to give an explanation what you want to do with \nit?\n\n(For reference, I think the recent patch series by Linus is a _wonderful_ \nexample how to do it: it has a very informative cover letter, and each \npatch tells you more about what and why, leaving the how mostly to the \npatch.  Basically, it is a pleasure to read (and understand):\n\nhttp://article.gmane.org/gmane.comp.version-control.git/77827)\n\nCiao,\nDscho"},{"id":"72821","messageId":"alpine.LSU.1.00.0803232327330.4353@racer.site","threadId":"12825","inReplyTo":"1206308562-31489-2-git-send-email-joerg@alea.gnuu.de","subject":"Re: [PATCH 2/4] Rework redo_merge","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2008-03-23T22:29:25Z","receivedAt":"2008-03-23T22:29:25Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Sun, 23 Mar 2008, Jörg Sommer wrote:\n\n> \n> Signed-off-by: Jörg Sommer <joerg@alea.gnuu.de>\n\n\"Rework\" is not really informative.\n\n> -\t\toutput git merge $STRATEGY -m \"$msg\" \\\n> -\t\t\t$new_parents\n> +\t\toutput git merge $STRATEGY -m \"$msg\" \"$@\"\n\nThis should rather go into 1/4.\n\n> @@ -197,8 +199,7 @@ pick_one_preserving_merges () {\n>  \t\tcase \"$new_parents\" in\n>  \t\t' '*' '*)\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\tredo_merge\n> +\t\t\tredo_merge $sha1 ${new_parents# $first_parent}\n\nLikewise.\n\nSidenote: it is a bit of cheating to set sha1=$1 in redo_merge(), since it \nis _not_ a local variable there, but the code _relies_ on sha1 being the \nsame after calling redo_merge().\n\nCiao,\nDscho\n"},{"id":"72823","messageId":"alpine.LSU.1.00.0803232332150.4353@racer.site","threadId":"12825","inReplyTo":"1206308562-31489-3-git-send-email-joerg@alea.gnuu.de","subject":"Re: [PATCH 3/4] Add a function for get the parents of a commit","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2008-03-23T22:33:56Z","receivedAt":"2008-03-23T22:33:56Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Sun, 23 Mar 2008, Jörg Sommer wrote:\n\n> \n> Signed-off-by: Jörg Sommer <joerg@alea.gnuu.de>\n\n\"for get\"?  You mean \"to get\".\n\n> +parents_of_commit() {\n> +\tgit rev-list --parents -1 \"$1\" | cut -d' ' -f2-\n> +}\n\n>From the rest of Git's source code, I would have expected this to be \ncalled \"get_parents\", and to have a space before the parens.  In general, \nit is always good to imitate the style around the code you are writing.\n\nCiao,\nDscho"},{"id":"72825","messageId":"alpine.LSU.1.00.0803232334130.4353@racer.site","threadId":"12825","inReplyTo":"1206308562-31489-4-git-send-email-joerg@alea.gnuu.de","subject":"Re: [PATCH 4/4] git-rebase -i: New option to support rebase with merges","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2008-03-23T22:41:11Z","receivedAt":"2008-03-23T22:41:11Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Sun, 23 Mar 2008, Jörg Sommer wrote:\n\n> The option --preserve-merges does not allow to change the order of \n> commits or squash them. The new option --linear-history does support \n> this, but doing so it can only look at the commits reachable with \n> through the first parent of each merge.\n\nWhy do you call it \"linear-history\"?  That name is pretty ambiguous.  Why \nnot calling it \"--first-parents\"?\n\n> Joining merge commits with other commits leads to problems, because git\n> merge fails with a dirty index (the case “COMMIT squash MERGE”) and\n> squashing a merge leads to the lost of the parents (case “MERGE squash\n> COMMIT”).\n\nPlease use the term \"to squash\" not \"to join\".  And say \"to the loss\" \ninstead of \"to the lost\".\n\nAnd I still think that it would be better to fix the bug that squashing \nmerges fails.\n\n> @@ -247,6 +248,13 @@ OPTIONS\n>  \tInstead of ignoring merges, try to recreate them.  This option\n>  \tonly works in interactive mode.\n>  \n> +-l, \\--linear-history::\n> +\tUse only commits of the branch they are not merged in, i.e.\n\ns/they are/that are/\n\n> +\tfollow only the first parent of a merge. Merges are part of this\n\ns/first parent of a merge/first parents of the encountered merge commits/\n\n> @@ -150,7 +152,18 @@ pick_one () {\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> +\t\tif test t = \"$LINEAR_HISTORY\" &&\n> +\t\t\tother_parents=\"$(parents_of_commit $sha1 | cut -s -d' ' -f2-)\" &&\n> +\t\t\ttest -n \"$other_parents\"\n> +\t\tthen\n> +\t\t\tif test a\"$1\" = a-n\n> +\t\t\tthen\n> +\t\t\t\tmerge_opt=--no-commit\n> +\t\t\tfi\n> +\t\t\tredo_merge $sha1 $no_commit $other_parents\n> +\t\telse\n> +\t\t\toutput git cherry-pick \"$@\"\n> +\t\tfi\n\nNow, that is funny.  In case of --preserve-merges, I would have expected \nyou to touch pick_one_preserving_merges(), not pick_one().\n\nI would find it highly illogical to try to redo merges _without_ -p.\n\nAnd again, I have to stress that fixing -p for the cases you mentioned \nshould be a higher priority than to introduce new options to work around \nthe bugs.  Seems like I am repeating myself, but hopefully I don't have to \ndo that many more times.\n\nCiao,\nDscho\n"},{"id":"72877","messageId":"20080324111413.GA18488@alea.gnuu.de","threadId":"12825","inReplyTo":"alpine.LSU.1.00.0803232334130.4353@racer.site","subject":"Re: [PATCH 4/4] git-rebase -i: New option to support rebase with merges","fromName":"Jörg Sommer","fromEmail":"joerg@alea.gnuu.de","sentAt":"2008-03-24T11:14:13Z","receivedAt":"2008-03-24T11:14:13Z","isPatch":true,"sender":{"key":"joerg@alea.gnuu.de","avatar":null},"body":"Hi Johannes,\n\nJohannes Schindelin schrieb am Sun 23. Mar, 23:41 (+0100):\n> On Sun, 23 Mar 2008, Jörg Sommer wrote:\n> \n> > @@ -150,7 +152,18 @@ pick_one () {\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> > +\t\tif test t = \"$LINEAR_HISTORY\" &&\n> > +\t\t\tother_parents=\"$(parents_of_commit $sha1 | cut -s -d' ' -f2-)\" &&\n> > +\t\t\ttest -n \"$other_parents\"\n> > +\t\tthen\n> > +\t\t\tif test a\"$1\" = a-n\n> > +\t\t\tthen\n> > +\t\t\t\tmerge_opt=--no-commit\n> > +\t\t\tfi\n> > +\t\t\tredo_merge $sha1 $no_commit $other_parents\n> > +\t\telse\n> > +\t\t\toutput git cherry-pick \"$@\"\n> > +\t\tfi\n> \n> Now, that is funny.  In case of --preserve-merges, I would have expected \n> you to touch pick_one_preserving_merges(), not pick_one().\n> \n> I would find it highly illogical to try to redo merges _without_ -p.\n\nMe too, but I think it's not possible to do what I want with -p. -p\nmisses a definition of the (new) parent of a commit. It tries to preserve\nall commits from all branches. But going through the _list_ of commands\ncouldn't preserve this structure.\n\no--A--B\n \\     \\\n  C--D--M--E\n\nHow should the graph look like after these commands:\n\npick A\npick C\nsquash E\n# pick D\npick B\npick M\n\nShould\n\npick A\npick B\npick C\npick D\npick M\npick E\n\ngive a same graph like\n\npick C\npick A\npick D\npick B\npick M\npick E\n\nBye, Jörg.\n-- \n< Mr X.> jo: contact an admin to mount it for you\n< jo> The admin is not, well how should I say it, he isn't very familiar with\n      the system. What should I tell my admin, what he should do?\n< Mr X.> taking a sun solaris administration course.\n"},{"id":"72882","messageId":"alpine.LSU.1.00.0803241406530.4353@racer.site","threadId":"12825","inReplyTo":"20080324111413.GA18488@alea.gnuu.de","subject":"Re: [PATCH 4/4] git-rebase -i: New option to support rebase with merges","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2008-03-24T13:08:20Z","receivedAt":"2008-03-24T13:08:20Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Mon, 24 Mar 2008, Jörg Sommer wrote:\n\n> Johannes Schindelin schrieb am Sun 23. Mar, 23:41 (+0100):\n> > On Sun, 23 Mar 2008, Jörg Sommer wrote:\n> > \n> > > @@ -150,7 +152,18 @@ pick_one () {\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> > > +\t\tif test t = \"$LINEAR_HISTORY\" &&\n> > > +\t\t\tother_parents=\"$(parents_of_commit $sha1 | cut -s -d' ' -f2-)\" &&\n> > > +\t\t\ttest -n \"$other_parents\"\n> > > +\t\tthen\n> > > +\t\t\tif test a\"$1\" = a-n\n> > > +\t\t\tthen\n> > > +\t\t\t\tmerge_opt=--no-commit\n> > > +\t\t\tfi\n> > > +\t\t\tredo_merge $sha1 $no_commit $other_parents\n> > > +\t\telse\n> > > +\t\t\toutput git cherry-pick \"$@\"\n> > > +\t\tfi\n> > \n> > Now, that is funny.  In case of --preserve-merges, I would have \n> > expected you to touch pick_one_preserving_merges(), not pick_one().\n> > \n> > I would find it highly illogical to try to redo merges _without_ -p.\n> \n> Me too, but I think it's not possible to do what I want with -p.\n\nBut that is not a reason to mess up the source code.  If you do a thing as \n--linear-history (or --first-parents, as I would prefer it), that should \nbe in the code path of --preserve-merges (and actually _imply_ that \noption).\n\n--linear-history makes no sense at all without --preserve-merges.\n\nCiao,\nDscho"},{"id":"72927","messageId":"7vabkoufzq.fsf@gitster.siamese.dyndns.org","threadId":"12825","inReplyTo":"20080324111413.GA18488@alea.gnuu.de","subject":"Re: [PATCH 4/4] git-rebase -i: New option to support rebase with merges","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2008-03-24T18:35:53Z","receivedAt":"2008-03-24T18:35:53Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jörg Sommer <joerg@alea.gnuu.de> writes:\n\n> Me too, but I think it's not possible to do what I want with -p. -p\n> misses a definition of the (new) parent of a commit. It tries to preserve\n> all commits from all branches. But going through the _list_ of commands\n> couldn't preserve this structure.\n>\n> o--A--B\n>  \\     \\\n>   C--D--M--E\n>\n> How should the graph look like after these commands:\n>\n> pick A\n> pick C\n> squash E\n> # pick D\n> pick B\n> pick M\n\nI am beginning to suspect that the root cause of this is that the todo\nlanguage is not expressive enough to reproduce a merge _and_ allow end\nuser editing.\n\nLet's step back a bit.\n\nIf you have this history:\n\n      o---o---o---o---o---Z\n     /\n    X---Y---A---B\n         \\       \\\n          C---D---M---E\n\nand you want to transplant the history  between X..E on top of Z, from the\ncommand line you would say:\n\n\t$ git rebase --interactive -p --onto Z X E\n\nFirst let's think what you would do if you want to do this by hand.  The\nsequence would be:\n\n\t$ git checkout Z^0 ;# detach at Z\n\n        $ git cherry-pick Y\n        $ git tag new-Y ;# remember it\n        $ git cherry-pick A\n        $ git cherry-pick B\n        $ git tag new-B ;# remember it\n        $ git checkout new-Y\n        $ git cherry-pick C\n        $ git cherry-pick D\n        $ git merge new-B ;# this reproduces M\n        $ git cherry-pick E\n\n\t$ git branch -f $the_branch && git checkout $the_branch\n\n\nNow how does the todo file before you edit look like?\n\n\tpick Y\n        pick A\n        pick B\n        pick C\n        pick D\n        pick M\n        pick E\n\nThe todo file expects the initial detaching and the final switching back\noutside of its control, so it is Ok that the first \"checkout Z^0\" and the\nlast \"branch && checkout\" do not appear, but it should be able to express\nthe remainder and let you tweak.  Is it expressive enough to do so?  \n\nMost of the \"pick\" from the above list literally translate to the\n\"cherry-pick\", and if you change any of them to \"edit\", that is\n\"cherry-pick --no-edit\" followed by a return of control to you with insn\nto \"rebase --continue\" to resume.  There appears nothing magical.\n\nNot really.  There already are two gotchas even without talking about\nend-user editing.\n\nFirst, \"pick M\" is not \"cherry-pick M\".  You do not want to end up with\nmerging an old parent before rewriting.  It has to be something like\n\"merge rewritten-Y\".\n\nSecond, before you start picking C, if you want to preserve merges, you\nhave to switch to rewritten Y.  The original sequence left in todo does\nnot have that information to begin with.  We need, before the \"pick C\", to\nsay the equivalent of \"git checkout new-Y\" in the manual sequence\nillustrated above.  The lack of \"checkout new-Y\" is perfectly fine if\nrebase is meant to linearlize the history, but if you want to preserve the\nshape of the history, you would need to give a clue that the sequence that\nbegins with the \"pick C\" starts from somewhere else.\n\nYou also need to make sure that \"pick M\" moved elsewhere still merges the\ntips of two forked histories.  Moving \"pick M\" before \"pick C\" or \"pick A\"\nwould not make much sense.  So you would need some kind of \"barrier\" that\nsays \"do not move this 'pick M' beyond this point\".\n\nPerhaps we can make it clearer by introducing a few more primitives to the\ntodo language: mark, reset and merge.  The above illustrated history would\nthen become:\n\n\tpick Y\n        mark #0\n\tpick A\n        pick B\n        mark #1\n        reset #0\n        pick C\n        pick D\n\tmark #2\n        merge #1 #2\n        pick E\n\nYou can change any of the \"pick\" to \"edit, or drop it, and you can reorder\n\"pick\" in a sequence of \"pick\", but you cannot change \"mark\", \"reset\",\n\"merge\", or move \"pick\" across insn that was not originally \"pick\".\n"},{"id":"72979","messageId":"7v7ifrsnri.fsf@gitster.siamese.dyndns.org","threadId":"12825","inReplyTo":"7vabkoufzq.fsf@gitster.siamese.dyndns.org","subject":"Re: [PATCH 4/4] git-rebase -i: New option to support rebase with merges","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2008-03-24T23:30:57Z","receivedAt":"2008-03-24T23:30:57Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"I'll extend this topic a bit for the last time, but first a word of\ncaution.  What I am going to draw is probably not what the current -p\nimplementation does.  They illustrate what I think should happen.\n\nAgain, starting from this topology:\n\n       o---o---o---o---o---Z\n      /\n     X---Y---A---B\n          \\       \\\n           C---D---M---E\n\nand the goal is to rebase your development leading to E on top of the\nupdated mainline Z.\n\nThe earlier example was when you want to end up with this topology:\n\n       o---o---o---o---o---Z---Y'--A'--B'      \n      /                         \\       \\      \n     X---Y---A---B               C'--D'--M'--E'\n          \\       \\\n           C---D---M---E\n\nIn this case, \"pick M\" cannot be \"merge B after pick D\".  It needs to\nmerge in the rewritten B (which is B').\n\nBut if you want to end up with this topology:\n\n       o---o---o---o---o---Z---Y'--A'--B'\n      /                                 \\     \n     X---Y---A---B                       M'--E'\n          \\       \\                     /\n           C---D---M---E               /\n                \\                     /\n                 `-------------------'\n\nredoing the merge from D when reproducing M' is the right thing to do.\n\nUnfortunately, you cannot express that you would want to rewrite only the\nY--A--B--M--E ancestry from the command line.  We would need a syntax to\ndo this cleanly first if we want to pursue this.\n\nThe \"first parent\" hack can be used in this case (--first-parent X..E),\nbut it will probably meet with the same resistance at the philosophical\nlevel (i.e. \"merge parents are equal\") as the --first-parent option was\ncriticised for.  But other than that, a sequence to pick Y A B M E in this\norder can be presented in the todo list to be edited, and swapping A and M\n(for example) should result in this:\n\n       o---o---o---o---o---Z---Y'\n      /                         \\\n     X---Y---A---B               M'--A'--B'\n          \\       \\             /\n           C---D---M---E       /\n                \\             /\n                 `-----------'\n\nThe existing revision range arithmetic can only come close with \"E ^Z ^D\"\n(or \"^D Z..E\"), but that would exclude Y as \"uninteresting\" (because Y is\nreachable from D).  You would end up with A--B--M--E.  So even though I am\nsympathetic to poeple who complained that the command line parameter to\nrebase is different from the log family, using revision range syntax is\nnot a solution to this.\n\nJust for completeness of the illustration, linealizing form aims to\nproduce the history like this:\n\n       o---o---o---o---o---Z---Y'--A'--B'--C'--D'--E'\n      /\n     X---Y---A---B\n          \\       \\\n           C---D---M---E\n\nYou can freely to reorder anything in the \"todo\" list without additional\nconstraints in this form (sequence of \"pick\" Y, A, B, C, D and E).\n"},{"id":"73026","messageId":"20080324234027.GA26905@alea.gnuu.de","threadId":"12825","inReplyTo":"alpine.LSU.1.00.0803241406530.4353@racer.site","subject":"Re: [PATCH 4/4] git-rebase -i: New option to support rebase with merges","fromName":"Jörg Sommer","fromEmail":"joerg@alea.gnuu.de","sentAt":"2008-03-24T23:40:27Z","receivedAt":"2008-03-24T23:40:27Z","isPatch":true,"sender":{"key":"joerg@alea.gnuu.de","avatar":null},"body":"Hallo Johannes,\n\nJohannes Schindelin schrieb am Mon 24. Mar, 14:08 (+0100):\n> On Mon, 24 Mar 2008, Jörg Sommer wrote:\n> \n> > Johannes Schindelin schrieb am Sun 23. Mar, 23:41 (+0100):\n> > > Now, that is funny.  In case of --preserve-merges, I would have \n> > > expected you to touch pick_one_preserving_merges(), not pick_one().\n> > > \n> > > I would find it highly illogical to try to redo merges _without_ -p.\n> > \n> > Me too, but I think it's not possible to do what I want with -p.\n> \n> But that is not a reason to mess up the source code.  If you do a thing as \n> --linear-history (or --first-parents, as I would prefer it), that should \n> be in the code path of --preserve-merges (and actually _imply_ that \n> option).\n\nThanks for answering my question. You are really cooperatively.\n\nBye, Jörg.\n-- \nIRC: Der [Prof. Andreas Pfitzmann, TU Dresden] hat gerade vorgeschlagen, sie\n  sollen doch statt Trojanern die elektromagnetische Abstrahlung nutzen. Das\n  sei nicht massenfähig, ginge ohne Eingriff ins System, sei zielgerichtet,\n  und, der Hammer, das funktioniere ja bei Wahlcomputern schon sehr gut.\n"},{"id":"73024","messageId":"20080325101345.GA990@alea.gnuu.de","threadId":"12825","inReplyTo":"7vabkoufzq.fsf@gitster.siamese.dyndns.org","subject":"Re: [PATCH 4/4] git-rebase -i: New option to support rebase with merges","fromName":"Jörg Sommer","fromEmail":"joerg@alea.gnuu.de","sentAt":"2008-03-25T10:13:45Z","receivedAt":"2008-03-25T10:13:45Z","isPatch":true,"sender":{"key":"joerg@alea.gnuu.de","avatar":null},"body":"Hi Junio,\n\nJunio C Hamano schrieb am Mon 24. Mar, 11:35 (-0700):\n> If you have this history:\n>\n>       o---o---o---o---o---Z\n>      /\n>     X---Y---A---B\n>          \\       \\\n>           C---D---M---E\n\n\nI would like to extend this example:\n\n      o---o---o---o---o---Z\n     /\n    X---Y---A-------B\n         \\           \\\n          C---D---N---M---E\n                 /\n                V\n\n> and you want to transplant the history  between X..E on top of Z, from the\n> command line you would say:\n> \n> \t$ git rebase --interactive -p --onto Z X E\n> \n> First let's think what you would do if you want to do this by hand.  The\n> sequence would be:\n> \n> \t$ git checkout Z^0 ;# detach at Z\n> \n>         $ git cherry-pick Y\n>         $ git tag new-Y ;# remember it\n>         $ git cherry-pick A\n>         $ git cherry-pick B\n>         $ git tag new-B ;# remember it\n>         $ git checkout new-Y\n>         $ git cherry-pick C\n>         $ git cherry-pick D\n% git merge V\n>         $ git merge new-B ;# this reproduces M\n>         $ git cherry-pick E\n> \n> \t$ git branch -f $the_branch && git checkout $the_branch\n\n\n> Perhaps we can make it clearer by introducing a few more primitives to the\n> todo language: mark, reset and merge.  The above illustrated history would\n> then become:\n> \n> \tpick Y\n>         mark #0\n> \tpick A\n>         pick B\n>         mark #1\n>         reset #0\n>         pick C\n>         pick D\nmerge V\n\nV is not a mark.\n\n> \tmark #2\n>         merge #1 #2\n>         pick E\n> \n> You can change any of the \"pick\" to \"edit, or drop it, and you can reorder\n> \"pick\" in a sequence of \"pick\", but you cannot change \"mark\", \"reset\",\n> \"merge\", or move \"pick\" across insn that was not originally \"pick\".\n\nThis way we can also merge more than two branches. Your idea sounds good.\n\nBye, Jörg.\n-- \nNichts ist so langweilig, wie die Wiederholung seinerselbst.\n                                        (Marcel Reich‐Ranicki)\n"},{"id":"73124","messageId":"7vej9xgbg5.fsf@gitster.siamese.dyndns.org","threadId":"12825","inReplyTo":"20080325101345.GA990@alea.gnuu.de","subject":"Re: [PATCH 4/4] git-rebase -i: New option to support rebase with merges","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2008-03-26T08:02:18Z","receivedAt":"2008-03-26T08:02:18Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jörg Sommer <joerg@alea.gnuu.de> writes:\n\n> I would like to extend this example:\n>\n>       o---o---o---o---o---Z\n>      /\n>     X---Y---A-------B\n>          \\           \\\n>           C---D---N---M---E\n>                  /\n>                 V\n> ...\n> merge V\n>\n> V is not a mark.\n\nThat's essentially the same as what I drew in a follow-up to the message\nyou are responding to, using --first-parents to mark D as \"not subject to\nrewrite but still interesting\".\n\nAs I explained there, a bigger issue is how you would express the set of\ncommits that you would want to rewrite and use intact.  In your\nillustration, you would want to rewrite N but you want to reuse V.\n\"rebase Z E\" or \"rebase --onto Z X E\" would include V (and all of its\nancestors that cannot be reached from Z or X that you did not draw) in the\nset to be rewritten.  Extending the input to the rebase command to use\nrevision range syntax and saying it as Z..E (or X..E) would not help\neither.\n"},{"id":"74003","messageId":"1207785521-27742-1-git-send-email-joerg@alea.gnuu.de","threadId":"12825","inReplyTo":"7vabkoufzq.fsf@gitster.siamese.dyndns.org","subject":"Teach rebase interactive more commands to do better preserve merges","fromName":"Jörg Sommer","fromEmail":"joerg@alea.gnuu.de","sentAt":"2008-04-09T23:58:31Z","receivedAt":"2008-04-09T23:58:31Z","isPatch":false,"sender":{"key":"joerg@alea.gnuu.de","avatar":null},"body":"\nJunio proposed to add the commands mark, merge and reset to rebase\ninteractive for a better support of rebase with preserve merges. The\ncurrent format can only cope with flat lineare lists of commits and not\nwith the nonâlinear structure of branches with merges.\n\nThis patch series is not intended for inclusion. It's a RFC and meant for\ngathering ideas.\n\nCurrently it misses:\nÂ· commit messages\nÂ· documentation of the new commands\nÂ· update of the documentation of preserve merges\nÂ· tests for the merge command\n\nI've included the patch to change the behaviour of git-merge from Junio,\nbecause I don't know how to use the second syntax of git merge and pass\nthe merge strategies -s to git merge. Without this patch, a new merge\nmessage gets appended to the commit message of a rebased merge commit.\nThis patch should not be part of the final commit series.\n\nOpen questions:\nÂ· Is it possible to get a list of all commits iterating the parents from\n  the last to the first and going to the child of a node before the\n  neighbors?\n\nÂ· How to get a symbolic name (branch or tag) for a commit? Not something\n  like git describe. I want to know if 0123 refers to the tip of a\n  branch.\n\nJÃ¶rg.\n"},{"id":"74006","messageId":"1207785521-27742-2-git-send-email-joerg@alea.gnuu.de","threadId":"12825","inReplyTo":"1207785521-27742-1-git-send-email-joerg@alea.gnuu.de","subject":"[PATCH/RFC 01/10] Teach rebase interactive the mark command","fromName":"Jörg Sommer","fromEmail":"joerg@alea.gnuu.de","sentAt":"2008-04-09T23:58:32Z","receivedAt":"2008-04-09T23:58:32Z","isPatch":true,"sender":{"key":"joerg@alea.gnuu.de","avatar":null},"body":"This new command can be used to set symbolic marks for an commit while\ndoing a rebase. This symbolic name can later be used for merges or\nresets.\n---\n git-rebase--interactive.sh    |   36 ++++++++++++++++++++++++++++++++++++\n t/t3404-rebase-interactive.sh |   21 +++++++++++++++++++++\n 2 files changed, 57 insertions(+), 0 deletions(-)\n\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex 8aa7371..b001ddf 100755\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -23,6 +23,7 @@ DONE=\"$DOTEST\"/done\n MSG=\"$DOTEST\"/message\n SQUASH_MSG=\"$DOTEST\"/message-squash\n REWRITTEN=\"$DOTEST\"/rewritten\n+MARKS=\"$DOTEST\"/marks\n PRESERVE_MERGES=\n STRATEGY=\n VERBOSE=\n@@ -240,6 +241,23 @@ peek_next_command () {\n \tsed -n \"1s/ .*$//p\" < \"$TODO\"\n }\n \n+parse_mark() {\n+\tlocal tmp\n+\ttmp=\"$*\"\n+\n+\tcase \"$tmp\" in\n+\t'#'[0-9]*)\n+\t\ttmp=\"${tmp#\\#}\"\n+\t\tif test \"$tmp\" = $(printf %d \"$tmp\")\n+\t\tthen\n+\t\t\techo $tmp\n+\t\t\treturn 0\n+\t\tfi\n+\t\t;;\n+\tesac\n+\treturn 1\n+}\n+\n do_next () {\n \trm -f \"$DOTEST\"/message \"$DOTEST\"/author-script \\\n \t\t\"$DOTEST\"/amend || exit\n@@ -317,6 +335,23 @@ do_next () {\n \t\t\tdie_with_patch $sha1 \"\"\n \t\tfi\n \t\t;;\n+\tmark|a)\n+\t\tif ! mark=$(parse_mark $sha1)\n+\t\tthen\n+\t\t\twarn \"Invalid mark given: $command $sha1 $rest\"\n+\t\t\tdie_with_patch $sha1 \\\n+\t\t\t\t\"Please fix this in the file $TODO.\"\n+\t\tfi\n+\t\tmark_action_done\n+\n+\t\ttest -d \"$MARKS\" || mkdir \"$MARKS\"\n+\n+\t\ttest -e \"$MARKS\"/$mark && \\\n+\t\t\twarn \"mark $mark already exist; overwriting it\"\n+\n+\t\tgit rev-parse --verify HEAD > \"$MARKS\"/$mark || \\\n+\t\t\tdie \"HEAD is invalid\"\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@@ -533,6 +568,7 @@ do\n #  pick = use commit\n #  edit = use commit, but stop for amending\n #  squash = use commit, but meld into previous commit\n+#  mark #NUM = mark the current HEAD for later reference\n #\n # If you remove a line here THAT COMMIT WILL BE LOST.\n # However, if you remove everything, the rebase will be aborted.\ndiff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh\nindex 9cf873f..4461674 100755\n--- a/t/t3404-rebase-interactive.sh\n+++ b/t/t3404-rebase-interactive.sh\n@@ -82,6 +82,9 @@ for line in $FAKE_LINES; do\n \tcase $line in\n \tsquash|edit)\n \t\taction=\"$line\";;\n+\tmark*)\n+\t\techo \"mark ${line#mark}\"\n+\t\techo \"mark ${line#mark}\" >> \"$1\";;\n \t*)\n \t\techo sed -n \"${line}s/^pick/$action/p\"\n \t\tsed -n \"${line}p\" < \"$1\".tmp\n@@ -189,6 +192,24 @@ test_expect_success '-p handles \"no changes\" gracefully' '\n \ttest $HEAD = $(git rev-parse HEAD)\n '\n \n+test_expect_success 'setting an invalid mark fails' '\n+\texport FAKE_LINES=\"mark12 1\" && \\\n+\ttest_must_fail git rebase -i HEAD~1 &&\n+\tunset FAKE_LINES &&\n+\tgit rebase --abort\n+'\n+\n+test_expect_success 'setting marks works' '\n+\tgit checkout master &&\n+\tFAKE_LINES=\"mark#0 2 1 mark#42 3 edit 4\" git rebase -i HEAD~4 &&\n+\tmarks_dir=.git/.dotest-merge/marks\n+\ttest -d $marks_dir &&\n+\ttest $(ls $marks_dir | wc -l) -eq 2 &&\n+\ttest \"$(git rev-parse HEAD~4)\" = \"$(cat $marks_dir/0)\" &&\n+\ttest \"$(git rev-parse HEAD~2)\" = \"$(cat $marks_dir/42)\" &&\n+\tgit rebase --abort\n+'\n+\n test_expect_success 'preserve merges with -p' '\n \tgit checkout -b to-be-preserved master^ &&\n \t: > unrelated-file &&\n-- \n1.5.4.5\n"},{"id":"74000","messageId":"1207785521-27742-3-git-send-email-joerg@alea.gnuu.de","threadId":"12825","inReplyTo":"1207785521-27742-2-git-send-email-joerg@alea.gnuu.de","subject":"[PATCH/RFC 02/10] Teach rebase interactive the reset command","fromName":"Jörg Sommer","fromEmail":"joerg@alea.gnuu.de","sentAt":"2008-04-09T23:58:33Z","receivedAt":"2008-04-09T23:58:33Z","isPatch":true,"sender":{"key":"joerg@alea.gnuu.de","avatar":null},"body":"---\n git-rebase--interactive.sh    |   20 ++++++++++++++++++++\n t/t3404-rebase-interactive.sh |   10 ++++++++++\n 2 files changed, 30 insertions(+), 0 deletions(-)\n\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex b001ddf..7dac51b 100755\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -258,6 +258,16 @@ parse_mark() {\n \treturn 1\n }\n \n+mark_to_sha1() {\n+\tlocal mark\n+\tif mark=$(parse_mark $1)\n+\tthen\n+\t\tcat \"$MARKS\"/$mark\n+\telse\n+\t\treturn 1\n+\tfi\n+}\n+\n do_next () {\n \trm -f \"$DOTEST\"/message \"$DOTEST\"/author-script \\\n \t\t\"$DOTEST\"/amend || exit\n@@ -352,6 +362,15 @@ do_next () {\n \t\tgit rev-parse --verify HEAD > \"$MARKS\"/$mark || \\\n \t\t\tdie \"HEAD is invalid\"\n \t\t;;\n+\treset|r)\n+\t\tcomment_for_reflog reset\n+\n+\t\tmark_action_done\n+\t\ttmp=$(mark_to_sha1 $sha1) || \\\n+\t\t\ttmp=$(git rev-parse --verify $sha1) ||\n+\t\t\tdie \"Invalid parent '$sha1' in $command $sha1 $rest\"\n+\t\toutput git reset --hard $tmp\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@@ -569,6 +588,7 @@ do\n #  edit = use commit, but stop for amending\n #  squash = use commit, but meld into previous commit\n #  mark #NUM = mark the current HEAD for later reference\n+#  reset #NUM|commit = reset HEAD to a previous set mark or a commit\n #\n # If you remove a line here THAT COMMIT WILL BE LOST.\n # However, if you remove everything, the rebase will be aborted.\ndiff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh\nindex 4461674..521206f 100755\n--- a/t/t3404-rebase-interactive.sh\n+++ b/t/t3404-rebase-interactive.sh\n@@ -85,6 +85,9 @@ for line in $FAKE_LINES; do\n \tmark*)\n \t\techo \"mark ${line#mark}\"\n \t\techo \"mark ${line#mark}\" >> \"$1\";;\n+\treset*)\n+\t\techo \"reset ${line#reset}\"\n+\t\techo \"reset ${line#reset}\" >> \"$1\";;\n \t*)\n \t\techo sed -n \"${line}s/^pick/$action/p\"\n \t\tsed -n \"${line}p\" < \"$1\".tmp\n@@ -210,6 +213,13 @@ test_expect_success 'setting marks works' '\n \tgit rebase --abort\n '\n \n+test_expect_success 'reset with nonexistent mark fails' '\n+\texport FAKE_LINES=\"reset#0 1\" &&\n+\ttest_must_fail git rebase -i HEAD~1 &&\n+\tunset FAKE_LINES &&\n+\tgit rebase --abort\n+'\n+\n test_expect_success 'preserve merges with -p' '\n \tgit checkout -b to-be-preserved master^ &&\n \t: > unrelated-file &&\n-- \n1.5.4.5\n"},{"id":"74005","messageId":"1207785521-27742-4-git-send-email-joerg@alea.gnuu.de","threadId":"12825","inReplyTo":"1207785521-27742-3-git-send-email-joerg@alea.gnuu.de","subject":"[PATCH/RFC 03/10] Teach rebase interactive the merge command","fromName":"Jörg Sommer","fromEmail":"joerg@alea.gnuu.de","sentAt":"2008-04-09T23:58:34Z","receivedAt":"2008-04-09T23:58:34Z","isPatch":true,"sender":{"key":"joerg@alea.gnuu.de","avatar":null},"body":"This command redoes merges. It's useful if you rebase a branch that\ncontains merges and you want to preserve these merges. You can also use\nit to add new merges.\n---\n git-rebase--interactive.sh    |   25 +++++++++++++++++++++++++\n t/t3404-rebase-interactive.sh |    3 +++\n 2 files changed, 28 insertions(+), 0 deletions(-)\n\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex 7dac51b..18cdf3d 100755\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -362,6 +362,29 @@ do_next () {\n \t\tgit rev-parse --verify HEAD > \"$MARKS\"/$mark || \\\n \t\t\tdie \"HEAD is invalid\"\n \t\t;;\n+\tmerge|m)\n+\t\tcomment_for_reflog merge\n+\n+\t\tif ! git rev-parse --verify $sha1\n+\t\tthen\n+\t\t\tdie \"Invalid reference merge '$sha1' in $command $sha1 $rest\"\n+\t\tfi\n+\n+\t\tnew_parents=\n+\t\tfor p in $rest\n+\t\tdo\n+\t\t\ttmp=$(mark_to_sha1 $p) || \\\n+\t\t\t\ttmp=$(git rev-parse --verify $p) ||\n+\t\t\t\tdie \"Invalid parent '$sha1' in $command $sha1 $rest\"\n+\t\t\tnew_parents=\"$new_parents $tmp\"\n+\t\tdone\n+\t\tnew_parents=\"${new_parents# }\"\n+\t\ttest -n \"$new_parents\" || \\\n+\t\t\tdie \"You forgot to give the parents for the merge\"\n+\n+\t\tmark_action_done\n+\t\tredo_merge $sha1 $new_parents\n+\t\t;;\n \treset|r)\n \t\tcomment_for_reflog reset\n \n@@ -589,6 +612,8 @@ do\n #  squash = use commit, but meld into previous commit\n #  mark #NUM = mark the current HEAD for later reference\n #  reset #NUM|commit = reset HEAD to a previous set mark or a commit\n+#  merge commit-M #NUM|commit-P ... = redo merge commit-M with the\n+#         current HEAD and the parents marked with #NUM or the commit-P\n #\n # If you remove a line here THAT COMMIT WILL BE LOST.\n # However, if you remove everything, the rebase will be aborted.\ndiff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh\nindex 521206f..892fd5d 100755\n--- a/t/t3404-rebase-interactive.sh\n+++ b/t/t3404-rebase-interactive.sh\n@@ -88,6 +88,9 @@ for line in $FAKE_LINES; do\n \treset*)\n \t\techo \"reset ${line#reset}\"\n \t\techo \"reset ${line#reset}\" >> \"$1\";;\n+\tmerge*)\n+\t\techo \"merge ${line#merge}\" | tr / ' '\n+\t\techo \"merge ${line#merge}\" | tr / ' ' >> \"$1\";;\n \t*)\n \t\techo sed -n \"${line}s/^pick/$action/p\"\n \t\tsed -n \"${line}p\" < \"$1\".tmp\n-- \n1.5.4.5\n"},{"id":"73998","messageId":"1207785521-27742-5-git-send-email-joerg@alea.gnuu.de","threadId":"12825","inReplyTo":"1207785521-27742-4-git-send-email-joerg@alea.gnuu.de","subject":"[PATCH/RFC 04/10] Move redo merge code in a function","fromName":"Jörg Sommer","fromEmail":"joerg@alea.gnuu.de","sentAt":"2008-04-09T23:58:35Z","receivedAt":"2008-04-09T23:58:35Z","isPatch":true,"sender":{"key":"joerg@alea.gnuu.de","avatar":null},"body":"---\n git-rebase--interactive.sh |   31 +++++++++++++++++--------------\n 1 files changed, 17 insertions(+), 14 deletions(-)\n\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex 18cdf3d..973770e 100755\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -114,6 +114,22 @@ has_action () {\n \tgrep '^[^#]' \"$1\" >/dev/null\n }\n \n+redo_merge() {\n+\tauthor_script=$(get_author_ident_from_commit $sha1)\n+\teval \"$author_script\"\n+\tmsg=\"$(git cat-file commit $sha1 | sed -e '1,/^$/d')\"\n+\tif ! GIT_AUTHOR_NAME=\"$GIT_AUTHOR_NAME\" \\\n+\t\tGIT_AUTHOR_EMAIL=\"$GIT_AUTHOR_EMAIL\" \\\n+\t\tGIT_AUTHOR_DATE=\"$GIT_AUTHOR_DATE\" \\\n+\t\toutput git merge $STRATEGY -m \"$msg\" \\\n+\t\t\t$new_parents\n+\tthen\n+\t\tgit rerere\n+\t\tprintf \"%s\\n\" \"$msg\" > \"$GIT_DIR\"/MERGE_MSG\n+\t\tdie Error redoing merge $sha1\n+\tfi\n+}\n+\n pick_one () {\n \tno_ff=\n \tcase \"$1\" in -n) sha1=$2; no_ff=t ;; *) sha1=$1 ;; esac\n@@ -181,22 +197,9 @@ pick_one_preserving_merges () {\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\tredo_merge\n \t\t\t;;\n \t\t*)\n \t\t\toutput git cherry-pick \"$@\" ||\n-- \n1.5.4.5\n"},{"id":"74002","messageId":"1207785521-27742-6-git-send-email-joerg@alea.gnuu.de","threadId":"12825","inReplyTo":"1207785521-27742-5-git-send-email-joerg@alea.gnuu.de","subject":"[PATCH/RFC 05/10] Rework redo_merge","fromName":"Jörg Sommer","fromEmail":"joerg@alea.gnuu.de","sentAt":"2008-04-09T23:58:36Z","receivedAt":"2008-04-09T23:58:36Z","isPatch":true,"sender":{"key":"joerg@alea.gnuu.de","avatar":null},"body":"---\n git-rebase--interactive.sh |   14 ++++++++------\n 1 files changed, 8 insertions(+), 6 deletions(-)\n\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex 973770e..1698c3e 100755\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -115,14 +115,17 @@ has_action () {\n }\n \n redo_merge() {\n-\tauthor_script=$(get_author_ident_from_commit $sha1)\n-\teval \"$author_script\"\n+\tlocal sha1\n+\tsha1=$1\n+\tshift\n+\n+\teval \"$(get_author_ident_from_commit $sha1)\"\n \tmsg=\"$(git cat-file commit $sha1 | sed -e '1,/^$/d')\"\n+\n \tif ! GIT_AUTHOR_NAME=\"$GIT_AUTHOR_NAME\" \\\n \t\tGIT_AUTHOR_EMAIL=\"$GIT_AUTHOR_EMAIL\" \\\n \t\tGIT_AUTHOR_DATE=\"$GIT_AUTHOR_DATE\" \\\n-\t\toutput git merge $STRATEGY -m \"$msg\" \\\n-\t\t\t$new_parents\n+\t\toutput git merge $STRATEGY -m \"$msg\" \"$@\"\n \tthen\n \t\tgit rerere\n \t\tprintf \"%s\\n\" \"$msg\" > \"$GIT_DIR\"/MERGE_MSG\n@@ -198,8 +201,7 @@ pick_one_preserving_merges () {\n \t\tcase \"$new_parents\" in\n \t\t' '*' '*)\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\tredo_merge\n+\t\t\tredo_merge $sha1 ${new_parents# $first_parent}\n \t\t\t;;\n \t\t*)\n \t\t\toutput git cherry-pick \"$@\" ||\n-- \n1.5.4.5\n"},{"id":"74004","messageId":"1207785521-27742-7-git-send-email-joerg@alea.gnuu.de","threadId":"12825","inReplyTo":"1207785521-27742-6-git-send-email-joerg@alea.gnuu.de","subject":"[PATCH/RFC 06/10] Unify the lenght of $SHORT* and the commits in the TODO list","fromName":"Jörg Sommer","fromEmail":"joerg@alea.gnuu.de","sentAt":"2008-04-09T23:58:37Z","receivedAt":"2008-04-09T23:58:37Z","isPatch":true,"sender":{"key":"joerg@alea.gnuu.de","avatar":null},"body":"---\n git-rebase--interactive.sh |    6 +++---\n 1 files changed, 3 insertions(+), 3 deletions(-)\n\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex 1698c3e..060b40f 100755\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -600,9 +600,9 @@ do\n \t\t\tMERGES_OPTION=--no-merges\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\tSHORTUPSTREAM=$(git rev-parse --short=7 $UPSTREAM)\n+\t\tSHORTHEAD=$(git rev-parse --short=7 $HEAD)\n+\t\tSHORTONTO=$(git rev-parse --short=7 $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-- \n1.5.4.5\n"},{"id":"73999","messageId":"1207785521-27742-8-git-send-email-joerg@alea.gnuu.de","threadId":"12825","inReplyTo":"1207785521-27742-7-git-send-email-joerg@alea.gnuu.de","subject":"[PATCH/RFC 07/10] fake-editor: output TODO list if unchanged","fromName":"Jörg Sommer","fromEmail":"joerg@alea.gnuu.de","sentAt":"2008-04-09T23:58:38Z","receivedAt":"2008-04-09T23:58:38Z","isPatch":true,"sender":{"key":"joerg@alea.gnuu.de","avatar":null},"body":"It's much helpful to see the TODO list generated by rebase in the verbose\noutput. This makes it easier to check, if the list was not broken by\ndesign.\n---\n t/t3404-rebase-interactive.sh |    2 +-\n 1 files changed, 1 insertions(+), 1 deletions(-)\n\ndiff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh\nindex 892fd5d..aa4bb8d 100755\n--- a/t/t3404-rebase-interactive.sh\n+++ b/t/t3404-rebase-interactive.sh\n@@ -73,7 +73,7 @@ esac\n test -z \"$EXPECT_COUNT\" ||\n \ttest \"$EXPECT_COUNT\" = $(sed -e '/^#/d' -e '/^$/d' < \"$1\" | wc -l) ||\n \texit\n-test -z \"$FAKE_LINES\" && exit\n+test -z \"$FAKE_LINES\" && { grep -v '^#' \"$1\"; exit; }\n grep -v '^#' < \"$1\" > \"$1\".tmp\n rm -f \"$1\"\n cat \"$1\".tmp\n-- \n1.5.4.5\n"},{"id":"74001","messageId":"1207785521-27742-9-git-send-email-joerg@alea.gnuu.de","threadId":"12825","inReplyTo":"1207785521-27742-8-git-send-email-joerg@alea.gnuu.de","subject":"[PATCH/RFC 08/10] Don't append default merge message to -m message","fromName":"Jörg Sommer","fromEmail":"joerg@alea.gnuu.de","sentAt":"2008-04-09T23:58:39Z","receivedAt":"2008-04-09T23:58:39Z","isPatch":true,"sender":{"key":"joerg@alea.gnuu.de","avatar":null},"body":"Picked from <7vabko3dm2.fsf@gitster.siamese.dyndns.org>\nFrom: gitster@pobox.com (Junio C Hamano)\nDate: Sun, 23 Mar 2008 22:17:09 -0700\n---\n git-merge.sh |   24 +++++++++++++-----------\n 1 files changed, 13 insertions(+), 11 deletions(-)\n\ndiff --git a/git-merge.sh b/git-merge.sh\nindex 7dbbb1d..bd9699d 100755\n--- a/git-merge.sh\n+++ b/git-merge.sh\n@@ -250,17 +250,19 @@ else\n \t# We are invoked directly as the first-class UI.\n \thead_arg=HEAD\n \n-\t# All the rest are the commits being merged; prepare\n-\t# the standard merge summary message to be appended to\n-\t# the given message.  If remote is invalid we will die\n-\t# later in the common codepath so we discard the error\n-\t# in this loop.\n-\tmerge_name=$(for remote\n-\t\tdo\n-\t\t\tmerge_name \"$remote\"\n-\t\tdone | git fmt-merge-msg\n-\t)\n-\tmerge_msg=\"${merge_msg:+$merge_msg$LF$LF}$merge_name\"\n+\tif test -z \"$merge_msg\"\n+\tthen\n+\t\t# All the rest are the commits being merged; prepare\n+\t\t# the standard merge summary message to be appended to\n+\t\t# the given message.  If remote is invalid we will die\n+\t\t# later in the common codepath so we discard the error\n+\t\t# in this loop.\n+\t\tmerge_msg=$(for remote\n+\t\t\tdo\n+\t\t\t\tmerge_name \"$remote\"\n+\t\t\tdone | git fmt-merge-msg\n+\t\t)\n+\tfi\n fi\n head=$(git rev-parse --verify \"$head_arg\"^0) || usage\n \n-- \n1.5.4.5\n"},{"id":"74049","messageId":"1207785521-27742-10-git-send-email-joerg@alea.gnuu.de","threadId":"12825","inReplyTo":"1207785521-27742-9-git-send-email-joerg@alea.gnuu.de","subject":"[PATCH/RFC 09/10] Select all lines with fake-editor","fromName":"Jörg Sommer","fromEmail":"joerg@alea.gnuu.de","sentAt":"2008-04-09T23:58:40Z","receivedAt":"2008-04-09T23:58:40Z","isPatch":true,"sender":{"key":"joerg@alea.gnuu.de","avatar":null},"body":"The old fake-editor selects only lines they start with pick, if you give\nthe number of a line. With the new commands mark, merge and reset it was\nnot possible to select such lines for the new TODO list. The new\nfake-editor selects all kinds of lines, but replaces only the command\n“pick” with a different action.\n---\n t/t3404-rebase-interactive.sh |    5 ++---\n 1 files changed, 2 insertions(+), 3 deletions(-)\n\ndiff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh\nindex aa4bb8d..be26a78 100755\n--- a/t/t3404-rebase-interactive.sh\n+++ b/t/t3404-rebase-interactive.sh\n@@ -92,9 +92,8 @@ for line in $FAKE_LINES; do\n \t\techo \"merge ${line#merge}\" | tr / ' '\n \t\techo \"merge ${line#merge}\" | tr / ' ' >> \"$1\";;\n \t*)\n-\t\techo sed -n \"${line}s/^pick/$action/p\"\n-\t\tsed -n \"${line}p\" < \"$1\".tmp\n-\t\tsed -n \"${line}s/^pick/$action/p\" < \"$1\".tmp >> \"$1\"\n+\t\tsed -n \"${line}{s/^pick/$action/; p;}\" < \"$1\".tmp\n+\t\tsed -n \"${line}{s/^pick/$action/; p;}\" < \"$1\".tmp >> \"$1\"\n \t\taction=pick;;\n \tesac\n done\n-- \n1.5.4.5\n"},{"id":"73997","messageId":"1207785521-27742-11-git-send-email-joerg@alea.gnuu.de","threadId":"12825","inReplyTo":"1207785521-27742-10-git-send-email-joerg@alea.gnuu.de","subject":"[PATCH/RFC 10/10] Do rebase with preserve merges with advanced TODO list","fromName":"Jörg Sommer","fromEmail":"joerg@alea.gnuu.de","sentAt":"2008-04-09T23:58:41Z","receivedAt":"2008-04-09T23:58:41Z","isPatch":true,"sender":{"key":"joerg@alea.gnuu.de","avatar":null},"body":"---\n git-rebase--interactive.sh    |  248 ++++++++++++++++++++++++-----------------\n t/t3404-rebase-interactive.sh |   34 ++++++\n 2 files changed, 181 insertions(+), 101 deletions(-)\n\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex 060b40f..27bd87e 100755\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -22,12 +22,10 @@ TODO=\"$DOTEST\"/git-rebase-todo\n DONE=\"$DOTEST\"/done\n MSG=\"$DOTEST\"/message\n SQUASH_MSG=\"$DOTEST\"/message-squash\n-REWRITTEN=\"$DOTEST\"/rewritten\n MARKS=\"$DOTEST\"/marks\n PRESERVE_MERGES=\n STRATEGY=\n VERBOSE=\n-test -d \"$REWRITTEN\" && PRESERVE_MERGES=t\n test -f \"$DOTEST\"/strategy && STRATEGY=\"$(cat \"$DOTEST\"/strategy)\"\n test -f \"$DOTEST\"/verbose && VERBOSE=t\n \n@@ -137,8 +135,6 @@ 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@@ -152,66 +148,6 @@ pick_one () {\n \tfi\n }\n \n-pick_one_preserving_merges () {\n-\tcase \"$1\" in -n) sha1=$2 ;; *) sha1=$1 ;; esac\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-\tfor p in $(git rev-list --parents -1 $sha1 | cut -d' ' -f2-)\n-\tdo\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-\t\t\t*)\n-\t\t\t\tnew_parents=\"$new_parents $new_p\"\n-\t\t\t\t;;\n-\t\t\tesac\n-\t\tfi\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# No point in merging the first parent, that's HEAD\n-\t\t\tredo_merge $sha1 ${new_parents# $first_parent}\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-\n nth_string () {\n \tcase \"$1\" in\n \t*1[0-9]|*[04-9]) echo \"$1\"th;;\n@@ -410,20 +346,7 @@ do_next () {\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@@ -448,6 +371,138 @@ do_rest () {\n \tdone\n }\n \n+sha1_to_mark() {\n+\t# args: \"sha1\" \" sha1#mark sha1#mark\"\n+\tlocal tmp\n+\tcase \"$2\" in\n+\t*\" $1#\"*)\n+\t\ttmp=\"${2#* $1#}\"\n+\t\techo \"${tmp%% *}\"\n+\t\t;;\n+\t*)\n+\t\treturn 1\n+\t\t;;\n+\tesac\n+}\n+\n+insert_sha1_with_mark_in_list() {\n+\t# args: \"sha1\" \"mark\" \" sha1#mark sha1#mark\"\n+\tcase \"$3\" in\n+\t*\" $1#\"*)\n+\t\techo \"$3\"\n+\t\treturn 1\n+\t\t;;\n+\t*)\n+\t\techo \"$3 $1#$2\"\n+\t\t;;\n+\tesac\n+}\n+\n+create_extended_todo_list() {\n+\t(\n+\twhile IFS=_ read commit parents subject\n+\tdo\n+\t\tif test \"${last_parent:-$commit}\" != \"$commit\"\n+\t\tthen\n+\t\t\tif test t = \"${delayed_mark:-f}\"\n+\t\t\tthen\n+\t\t\t\tcase \"${marked_commits:-} \" in\n+\t\t\t\t*\" $last_parent \")\n+\t\t\t\t\t;;\n+\t\t\t\t*)\n+\t\t\t\t\tmarked_commits=\"${marked_commits:-} $last_parent\"\n+\t\t\t\t\t;;\n+\t\t\t\tesac\n+\t\t\t\tdelayed_mark=f\n+\t\t\tfi\n+\t\t\ttest \"$last_parent\" = $SHORTUPSTREAM && \\\n+\t\t\t\tlast_parent=$SHORTONTO\n+\t\t\techo \"reset $last_parent\"\n+\t\tfi\n+\t\tlast_parent=\"${parents%% *}\"\n+\n+\t\tcase \"${marked_commits:-} \" in\n+\t\t*\" $commit \"*)\n+\t\t\techo mark\n+\t\t\t;;\n+\t\tesac\n+\n+\t\tcase \"$parents\" in\n+\t\t*' '*)\n+\t\t\tdelayed_mark=t\n+\t\t\tnew_parents=\n+\t\t\tfor p in ${parents#* }\n+\t\t\tdo\n+\t\t\t\tcase \"${marked_commits:-} \" in\n+\t\t\t\t*\" $p \")\n+\t\t\t\t\t;;\n+\t\t\t\t*)\n+\t\t\t\t\tmarked_commits=\"${marked_commits:-} $p\"\n+\t\t\t\t\t;;\n+\t\t\t\tesac\n+\t\t\t\tif test \"$p\" = $SHORTUPSTREAM\n+\t\t\t\tthen\n+\t\t\t\t\tnew_parents=\"$new_parents $SHORTONTO\"\n+\t\t\t\telse\n+\t\t\t\t\tnew_parents=\"$new_parents $p\"\n+\t\t\t\tfi\n+\t\t\tdone\n+\t\t\tunset p\n+\t\t\techo merge $commit $new_parents\n+\t\t\tunset new_parents\n+\t\t\t;;\n+\t\t*)\n+\t\t\techo \"pick $commit $subject\"\n+\t\t\t;;\n+\t\tesac\n+\tdone\n+\ttest -n \"${last_parent:-}\" -a \"${last_parent:-}\" != $SHORTUPSTREAM && \\\n+\t\techo reset $last_parent\n+\t) | \\\n+\ttac | \\\n+\twhile read cmd args\n+\tdo\n+\t\t: ${commit_mark_list:=} ${last_commit:=000}\n+\t\tcase \"$cmd\" in\n+\t\tpick)\n+\t\t\tlast_commit=\"${args%% *}\"\n+\t\t\t;;\n+\t\tmark)\n+\t\t\t: ${next_mark:=0}\n+\t\t\tif commit_mark_list=$(insert_sha1_with_mark_in_list \\\n+\t\t\t\t$last_commit $next_mark \"$commit_mark_list\")\n+\t\t\tthen\n+\t\t\t\targs=\"#$next_mark\"\n+\t\t\t\tnext_mark=$(($next_mark + 1))\n+\t\t\telse\n+\t\t\t\tdie \"Internal error: two marks for the same commit\"\n+\t\t\tfi\n+\t\t\t;;\n+\t\treset)\n+\t\t\tif tmp=$(sha1_to_mark $args \"$commit_mark_list\")\n+\t\t\tthen\n+\t\t\t\targs=\"#$tmp\"\n+\t\t\tfi\n+\t\t\t;;\n+\t\tmerge)\n+\t\t\tnew_args=\n+\t\t\tfor i in ${args#* }\n+\t\t\tdo\n+\t\t\t\tif tmp=$(sha1_to_mark $i \"$commit_mark_list\")\n+\t\t\t\tthen\n+\t\t\t\t\tnew_args=\"$new_args #$tmp\"\n+\t\t\t\telse\n+\t\t\t\t\tnew_args=\"$new_args $i\"\n+\t\t\t\tfi\n+\t\t\tdone\n+\t\t\tlast_commit=\"${args%% *}\"\n+\t\t\targs=\"$last_commit ${new_args# }\"\n+\t\t\t;;\n+\t\tesac\n+\t\techo \"$cmd $args\"\n+\tdone\n+}\n+\n while test $# != 0\n do\n \tcase \"$1\" in\n@@ -580,33 +635,24 @@ do\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\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\tmkdir \"$REWRITTEN\" &&\n-\t\t\tfor c in $(git merge-base --all $HEAD $UPSTREAM)\n-\t\t\tdo\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\tfi\n \n \t\tSHORTUPSTREAM=$(git rev-parse --short=7 $UPSTREAM)\n \t\tSHORTHEAD=$(git rev-parse --short=7 $HEAD)\n \t\tSHORTONTO=$(git rev-parse --short=7 $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\tcommon_rev_parse_opts=\"--abbrev-commit\n+\t\t\t--abbrev=7 --left-right --cherry-pick\n+\t\t\t$UPSTREAM...$HEAD\"\n+\t\tif test t = \"$PRESERVE_MERGES\"\n+\t\tthen\n+\t\t\tgit rev-list --pretty='format:%h_%p_%s' \\\n+\t\t\t\t--topo-order $common_rev_parse_opts | \\\n+\t\t\t\tgrep -v ^commit | \\\n+\t\t\t\tcreate_extended_todo_list\n+\t\telse\n+\t\t\tgit rev-list --no-merges --reverse --pretty=oneline \\\n+\t\t\t\t$common_rev_parse_opts | sed -n \"s/^>/pick /p\"\n+\t\tfi > \"$TODO\"\n+\n \t\tcat >> \"$TODO\" << EOF\n \n # Rebase $SHORTUPSTREAM..$SHORTHEAD onto $SHORTONTO\ndiff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh\nindex be26a78..af7d818 100755\n--- a/t/t3404-rebase-interactive.sh\n+++ b/t/t3404-rebase-interactive.sh\n@@ -245,7 +245,41 @@ test_expect_success 'preserve merges with -p' '\n \ttest $(git show HEAD~2:file1) = B\n '\n \n+test_expect_success 'rebase with preserve merge forth and back is a noop' '\n+\tgit checkout -b big-branch-1 master &&\n+\t: > bb1a &&\n+\tgit add bb1a &&\n+\tgit commit -m \"big branch commit 1\" &&\n+\t: > bb1b &&\n+\tgit add bb1b &&\n+\tgit commit -m \"big branch commit 2\" &&\n+\t: > bb1c &&\n+\tgit add bb1c &&\n+\tgit commit -m \"big branch commit 3\" &&\n+\tgit checkout -b big-branch-2 master &&\n+\t: > bb2a &&\n+\tgit add bb2a &&\n+\tgit commit -m \"big branch commit 4\" &&\n+\t: > bb2b &&\n+\tgit add bb2b &&\n+\tgit commit -m \"big branch commit 5\" &&\n+\tgit merge big-branch-1~1 &&\n+\tgit merge to-be-preserved &&\n+\ttbp_merge=$(git rev-parse HEAD) &&\n+\t: > bb2c &&\n+\tgit add bb2c &&\n+\tgit commit -m \"big branch commit 6\" &&\n+\tgit merge big-branch-1 &&\n+\thead=$(git rev-parse HEAD) &&\n+\tFAKE_LINES=\"16 6 19 20 4 1 2 5 22\" \\\n+\t\tgit rebase -i -p --onto dead-end master &&\n+\tFAKE_LINES=\"3 7 mark#10 8 9 5 1 2 merge$tbp_merge~1/#10 merge$tbp_merge/to-be-preserved 6 11\" \\\n+\tgit rebase -i -p --onto master dead-end &&\n+\ttest \"$head\" = \"$(git rev-parse HEAD)\"\n+'\n+\n test_expect_success '--continue tries to commit' '\n+\tgit checkout to-be-rebased &&\n \ttest_tick &&\n \t! git rebase -i --onto new-branch1 HEAD^ &&\n \techo resolved > file1 &&\n-- \n1.5.4.5\n"},{"id":"74050","messageId":"e2b179460804100233v7b8a2feare353cb4e5f718e7@mail.gmail.com","threadId":"12825","inReplyTo":"1207785521-27742-2-git-send-email-joerg@alea.gnuu.de","subject":"Re: [PATCH/RFC 01/10] Teach rebase interactive the mark command","fromName":"Mike Ralphson","fromEmail":"mike.ralphson@gmail.com","sentAt":"2008-04-10T09:33:01Z","receivedAt":"2008-04-10T09:33:01Z","isPatch":true,"sender":{"key":"mike.ralphson@gmail.com","avatar":"https://avatars.githubusercontent.com/u/21603?v=4"},"body":"On 10/04/2008, Jörg Sommer <joerg@alea.gnuu.de> wrote:\n> This new command can be used to set symbolic marks for an commit while\n>  doing a rebase. This symbolic name can later be used for merges or\n>  resets.\n\nWhat would be wrong with using the existing tag machinery for this instead?\n\nMike\n\nPS: Apologies to anyone who got an html version of this mail.\n"},{"id":"74163","messageId":"7vskxsneau.fsf@gitster.siamese.dyndns.org","threadId":"12825","inReplyTo":"1207785521-27742-2-git-send-email-joerg@alea.gnuu.de","subject":"Re: [PATCH/RFC 01/10] Teach rebase interactive the mark command","fromName":"Junio C Hamano","fromEmail":"junio@pobox.com","sentAt":"2008-04-11T23:48:41Z","receivedAt":"2008-04-11T23:48:41Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jörg Sommer <joerg@alea.gnuu.de> writes:\n\n> This new command can be used to set symbolic marks for an commit while\n> doing a rebase. This symbolic name can later be used for merges or\n> resets.\n> ---\n\nComments as requested...\n\n> diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\n> index 8aa7371..b001ddf 100755\n> --- a/git-rebase--interactive.sh\n> +++ b/git-rebase--interactive.sh\n> @@ -23,6 +23,7 @@ DONE=\"$DOTEST\"/done\n>  MSG=\"$DOTEST\"/message\n>  SQUASH_MSG=\"$DOTEST\"/message-squash\n>  REWRITTEN=\"$DOTEST\"/rewritten\n> +MARKS=\"$DOTEST\"/marks\n\nI wonder if this should live somewhere inside $GIT_DIR/refs namespace, so\nthat if any object pruning is triggered ever while rebasing interactively\nthe objects that marks require will be protected.\n\n> @@ -240,6 +241,23 @@ peek_next_command () {\n>  \tsed -n \"1s/ .*$//p\" < \"$TODO\"\n>  }\n>  \n> +parse_mark() {\n> +\tlocal tmp\n\nBashism is not appreciated here.\n\n> +\tcase \"$tmp\" in\n> +\t'#'[0-9]*)\n> +\t\ttmp=\"${tmp#\\#}\"\n> +\t\tif test \"$tmp\" = $(printf %d \"$tmp\")\n> +\t\tthen\n> +\t\t\techo $tmp\n> +\t\t\treturn 0\n> +\t\tfi\n> +\t\t;;\n> +\tesac\n\nWouldn't\n\n\tpick 5cc8f37 (init: show \"Reinit\" message even in ...)\n\tmark 1\n\tpick 18d077c (quiltimport: fix misquoting of parse...)\n\tmark 2\n\treset 1\n        merge #2\n\nbe easier for people?\n\nWhen you reference a commit with mark name, it is reasonable to require it\nto be prefixed with '#', which is a character that cannot be either in\nrefname nor hex representation of a commit object.  I think it is Ok to\naccept an optional prefix when defining one, e.g. \"mark #47\", but I do not\nthink requiring '#' prefix when defining one is needed.\n\n> @@ -317,6 +335,23 @@ do_next () {\n>  \t\t\tdie_with_patch $sha1 \"\"\n>  \t\tfi\n>  \t\t;;\n> +\tmark|a)\n\nI understand that the reason why you did not pick a more obvious 'm' is\nbecause you would want to add 'merge' later and give it 'm', but we do not\nhave to give a single-letter equivalent to all commands especially when\nthere is not an appropriate one.\n"},{"id":"74164","messageId":"7viqyondyn.fsf@gitster.siamese.dyndns.org","threadId":"12825","inReplyTo":"1207785521-27742-3-git-send-email-joerg@alea.gnuu.de","subject":"Re: [PATCH/RFC 02/10] Teach rebase interactive the reset command","fromName":"Junio C Hamano","fromEmail":"junio@pobox.com","sentAt":"2008-04-11T23:56:00Z","receivedAt":"2008-04-11T23:56:00Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jörg Sommer <joerg@alea.gnuu.de> writes:\n\n> ---\n>  git-rebase--interactive.sh    |   20 ++++++++++++++++++++\n>  t/t3404-rebase-interactive.sh |   10 ++++++++++\n>  2 files changed, 30 insertions(+), 0 deletions(-)\n>\n> diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\n> index b001ddf..7dac51b 100755\n> --- a/git-rebase--interactive.sh\n> +++ b/git-rebase--interactive.sh\n> @@ -258,6 +258,16 @@ parse_mark() {\n>  \treturn 1\n>  }\n>  \n> +mark_to_sha1() {\n> +\tlocal mark\n\nBashism.\n\n> +\tif mark=$(parse_mark $1)\n> +\tthen\n> +\t\tcat \"$MARKS\"/$mark\n\nThis cat may become \"rev-parse --verify\" if we decide to move $MARKS\nunderneath refs/ namespace somewhere.\n\n> +\treset|r)\n> +\t\tcomment_for_reflog reset\n> +\n> +\t\tmark_action_done\n> +\t\ttmp=$(mark_to_sha1 $sha1) || \\\n> +\t\t\ttmp=$(git rev-parse --verify $sha1) ||\n\nand you then would not need to do the verify twice.\n\n> +\t\t\tdie \"Invalid parent '$sha1' in $command $sha1 $rest\"\n> +\t\toutput git reset --hard $tmp\n\nCould this step fail, and if it does what should happen?\n\n> @@ -569,6 +588,7 @@ do\n>  #  edit = use commit, but stop for amending\n>  #  squash = use commit, but meld into previous commit\n>  #  mark #NUM = mark the current HEAD for later reference\n> +#  reset #NUM|commit = reset HEAD to a previous set mark or a commit\n\n\"to a previously set mark\".  But I would say upfront \"in the todo insn\nwhenever you need to refer to a commit, in addition to\nthe usual commit object name, you can use '#num' syntax to refer to a\ncommit previously marked with the 'mark' insn.\" and make this line just\nread:\n\n    #  reset commit = reset HEAD to the commit\n"},{"id":"74165","messageId":"7vej9cndqp.fsf@gitster.siamese.dyndns.org","threadId":"12825","inReplyTo":"1207785521-27742-7-git-send-email-joerg@alea.gnuu.de","subject":"Re: [PATCH/RFC 06/10] Unify the lenght of $SHORT* and the commits in the TODO list","fromName":"Junio C Hamano","fromEmail":"junio@pobox.com","sentAt":"2008-04-12T00:00:46Z","receivedAt":"2008-04-12T00:00:46Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jörg Sommer <joerg@alea.gnuu.de> writes:\n\n> ---\n>  git-rebase--interactive.sh |    6 +++---\n>  1 files changed, 3 insertions(+), 3 deletions(-)\n>\n> diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\n> index 1698c3e..060b40f 100755\n> --- a/git-rebase--interactive.sh\n> +++ b/git-rebase--interactive.sh\n> @@ -600,9 +600,9 @@ do\n>  \t\t\tMERGES_OPTION=--no-merges\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\tSHORTUPSTREAM=$(git rev-parse --short=7 $UPSTREAM)\n> +\t\tSHORTHEAD=$(git rev-parse --short=7 $HEAD)\n> +\t\tSHORTONTO=$(git rev-parse --short=7 $ONTO)\n\nLacking is a better justification as to why this is a good change and 7 is\na good number.\n"},{"id":"74191","messageId":"20080412091345.GA31356@alea.gnuu.de","threadId":"12825","inReplyTo":"7vej9cndqp.fsf@gitster.siamese.dyndns.org","subject":"Re: [PATCH/RFC 06/10] Unify the lenght of $SHORT* and the commits in the TODO list","fromName":"Jörg Sommer","fromEmail":"joerg@alea.gnuu.de","sentAt":"2008-04-12T09:13:45Z","receivedAt":"2008-04-12T09:13:45Z","isPatch":true,"sender":{"key":"joerg@alea.gnuu.de","avatar":null},"body":"Hi Junio,\n\nJunio C Hamano schrieb am Fri 11. Apr, 17:00 (-0700):\n> Jörg Sommer <joerg@alea.gnuu.de> writes:\n> \n> > ---\n> >  git-rebase--interactive.sh |    6 +++---\n> >  1 files changed, 3 insertions(+), 3 deletions(-)\n> >\n> > diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\n> > index 1698c3e..060b40f 100755\n> > --- a/git-rebase--interactive.sh\n> > +++ b/git-rebase--interactive.sh\n> > @@ -600,9 +600,9 @@ do\n> >  \t\t\tMERGES_OPTION=--no-merges\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\tSHORTUPSTREAM=$(git rev-parse --short=7 $UPSTREAM)\n> > +\t\tSHORTHEAD=$(git rev-parse --short=7 $HEAD)\n> > +\t\tSHORTONTO=$(git rev-parse --short=7 $ONTO)\n> \n> Lacking is a better justification as to why this is a good change\n\n“This makes it easier to test for equality of a commit in the TODO list\nand one of SHORTUPSTREAM, SHORTHEAD or SHORTONTO.”\n\n> and 7 is a good number.\n\nI don't know why 7 is a good number. It was there from the beginning:\n\n% git show 1b1dce4b:git-rebase--interactive.sh G -C1 \\=7\n                git rev-list --no-merges --pretty=oneline --abbrev-commit \\\n                        --abbrev=7 --reverse $UPSTREAM..$HEAD | \\\n                        sed \"s/^/pick /\" >> \"$TODO\"\n\nBye, Jörg.\n-- \nDamit das Mögliche entsteht, muß immer wieder das Unmögliche versucht\nwerden.                                       (Hermann Hesse)\n"},{"id":"74194","messageId":"20080412093744.GC31356@alea.gnuu.de","threadId":"12825","inReplyTo":"7viqyondyn.fsf@gitster.siamese.dyndns.org","subject":"Re: [PATCH/RFC 02/10] Teach rebase interactive the reset command","fromName":"Jörg Sommer","fromEmail":"joerg@alea.gnuu.de","sentAt":"2008-04-12T09:37:44Z","receivedAt":"2008-04-12T09:37:44Z","isPatch":true,"sender":{"key":"joerg@alea.gnuu.de","avatar":null},"body":"Hi Junio,\n\nJunio C Hamano schrieb am Fri 11. Apr, 16:56 (-0700):\n> Jörg Sommer <joerg@alea.gnuu.de> writes:\n> \n> > ---\n> >  git-rebase--interactive.sh    |   20 ++++++++++++++++++++\n> >  t/t3404-rebase-interactive.sh |   10 ++++++++++\n> >  2 files changed, 30 insertions(+), 0 deletions(-)\n> >\n> > diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\n> > index b001ddf..7dac51b 100755\n> > --- a/git-rebase--interactive.sh\n> > +++ b/git-rebase--interactive.sh\n\n> > +\t\t\tdie \"Invalid parent '$sha1' in $command $sha1 $rest\"\n> > +\t\toutput git reset --hard $tmp\n> \n> Could this step fail, and if it does what should happen?\n\nI don't expect it. tmp is a valid sha1 and reset may fail if the working\ndirectory is dirty, but then the previous command should have failed,\ntoo. Do you think different?\n\n> > @@ -569,6 +588,7 @@ do\n> >  #  edit = use commit, but stop for amending\n> >  #  squash = use commit, but meld into previous commit\n> >  #  mark #NUM = mark the current HEAD for later reference\n> > +#  reset #NUM|commit = reset HEAD to a previous set mark or a commit\n> \n> \"to a previously set mark\".  But I would say upfront \"in the todo insn\n> whenever you need to refer to a commit, in addition to\n> the usual commit object name, you can use '#num' syntax to refer to a\n> commit previously marked with the 'mark' insn.\"\n\nDoes this mean pick, edit and squash should understand marks, too? But\nhow useful is this? You can only set a mark if you've picked a commit and\nusing this commit again, e.g. pick it twice, doesn't sound useful.\n\n-- \n$ cat /dev/random\n#!/usr/bin/perl -WT\nprint \"hello world\\n\";\n"},{"id":"74193","messageId":"20080412101110.GD31356@alea.gnuu.de","threadId":"12825","inReplyTo":"7vskxsneau.fsf@gitster.siamese.dyndns.org","subject":"Re: [PATCH/RFC 01/10] Teach rebase interactive the mark command","fromName":"Jörg Sommer","fromEmail":"joerg@alea.gnuu.de","sentAt":"2008-04-12T10:11:11Z","receivedAt":"2008-04-12T10:11:11Z","isPatch":true,"sender":{"key":"joerg@alea.gnuu.de","avatar":null},"body":"Hi Junio,\n\nJunio C Hamano schrieb am Fri 11. Apr, 16:48 (-0700):\n> Jörg Sommer <joerg@alea.gnuu.de> writes:\n> \n> > This new command can be used to set symbolic marks for an commit while\n> > doing a rebase. This symbolic name can later be used for merges or\n> > resets.\n> > ---\n> \n> Comments as requested...\n\nThanks.\n\n> > diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\n> > index 8aa7371..b001ddf 100755\n> > --- a/git-rebase--interactive.sh\n> > +++ b/git-rebase--interactive.sh\n> > @@ -23,6 +23,7 @@ DONE=\"$DOTEST\"/done\n> >  MSG=\"$DOTEST\"/message\n> >  SQUASH_MSG=\"$DOTEST\"/message-squash\n> >  REWRITTEN=\"$DOTEST\"/rewritten\n> > +MARKS=\"$DOTEST\"/marks\n> \n> I wonder if this should live somewhere inside $GIT_DIR/refs namespace, so\n> that if any object pruning is triggered ever while rebasing interactively\n> the objects that marks require will be protected.\n\nWhy wasn't the rewritten directory underneath refs/?\n\n> > @@ -240,6 +241,23 @@ peek_next_command () {\n> >  \tsed -n \"1s/ .*$//p\" < \"$TODO\"\n> >  }\n> >  \n> > +parse_mark() {\n> > +\tlocal tmp\n> \n> Bashism is not appreciated here.\n\n“IEEE P1003.2 Draft 11.2 - September 1991”, page 277:\n\n Local variables within a function were considered and included in Draft\n 9 (controlled by the special built-in local), but were removed because\n they do not fit the simple model developed for the scoping of functions\n and there was some opposition to adding yet another new special built-in\n from outside existing practice.  Implementations should reserve the\n identifier local (as well as typeset, as used in the KornShell) in case\n this local variable mechanism is adopted in a future version of POSIX.2.\n\n… but I didn't found it in “IEEE Std 1003.1, 2004 Edition”.\n\n> > +\tcase \"$tmp\" in\n> > +\t'#'[0-9]*)\n> > +\t\ttmp=\"${tmp#\\#}\"\n> > +\t\tif test \"$tmp\" = $(printf %d \"$tmp\")\n> > +\t\tthen\n> > +\t\t\techo $tmp\n> > +\t\t\treturn 0\n> > +\t\tfi\n> > +\t\t;;\n> > +\tesac\n> \n> Wouldn't\n> \n> \tpick 5cc8f37 (init: show \"Reinit\" message even in ...)\n> \tmark 1\n> \tpick 18d077c (quiltimport: fix misquoting of parse...)\n> \tmark 2\n> \treset 1\n\n“reset 18d077c~2” or “reset some-tag” or “reset my-branch~12”\n\n>         merge #2\n> \n> be easier for people?\n\nI don't know. Using the special sign everywhere a mark is used looks more\nconsistent to me. The only case where it might be omitted is the mark\ncommand, because it only uses marks.\n\n> When you reference a commit with mark name, it is reasonable to require it\n> to be prefixed with '#', which is a character that cannot be either in\n> refname nor hex representation of a commit object.  I think it is Ok to\n> accept an optional prefix when defining one, e.g. \"mark #47\", but I do not\n> think requiring '#' prefix when defining one is needed.\n\nThat sounds useful.\n\nBTW: Should the mark be a number or a string, e.g. 001 == 1 or 001 != 1?\n\n> > @@ -317,6 +335,23 @@ do_next () {\n> >  \t\t\tdie_with_patch $sha1 \"\"\n> >  \t\tfi\n> >  \t\t;;\n> > +\tmark|a)\n> \n> I understand that the reason why you did not pick a more obvious 'm' is\n> because you would want to add 'merge' later and give it 'm', but we do not\n> have to give a single-letter equivalent to all commands especially when\n> there is not an appropriate one.\n\nThat's fine. I thought it's a requirement.\n\nBye, Jörg.\n-- \nWas der Bauer nicht kennt, das frisst er nicht. Würde der Städter kennen,\nwas er frisst, er würde umgehend Bauer werden.\n                                                       Oliver Hassencamp\n"},{"id":"74192","messageId":"20080412101732.GE31356@alea.gnuu.de","threadId":"12825","inReplyTo":"e2b179460804100233v7b8a2feare353cb4e5f718e7@mail.gmail.com","subject":"Re: [PATCH/RFC 01/10] Teach rebase interactive the mark command","fromName":"Jörg Sommer","fromEmail":"joerg@alea.gnuu.de","sentAt":"2008-04-12T10:17:32Z","receivedAt":"2008-04-12T10:17:32Z","isPatch":true,"sender":{"key":"joerg@alea.gnuu.de","avatar":null},"body":"Hallo Mike,\n\nMike Ralphson schrieb am Thu 10. Apr, 10:33 (+0100):\n> On 10/04/2008, Jörg Sommer <joerg@alea.gnuu.de> wrote:\n> > This new command can be used to set symbolic marks for an commit while\n> >  doing a rebase. This symbolic name can later be used for merges or\n> >  resets.\n> \n> What would be wrong with using the existing tag machinery for this instead?\n\nYou may have to deal with conflicts if users named tags 03 or 10. But\nJunio suggested to use a ref, too. I think refs/rebase-marks/ is a good\nprefix.\n\nBye, Jörg.\n-- \nDer Hase läuft schneller als der Fuchs,\ndenn der Hase läuft um sein Leben.\n"},{"id":"74237","messageId":"20080413035648.GY10274@spearce.org","threadId":"12825","inReplyTo":"20080412101110.GD31356@alea.gnuu.de","subject":"Re: [PATCH/RFC 01/10] Teach rebase interactive the mark command","fromName":"Shawn O. Pearce","fromEmail":"spearce@spearce.org","sentAt":"2008-04-13T03:56:48Z","receivedAt":"2008-04-13T03:56:48Z","isPatch":true,"sender":{"key":"spearce@spearce.org","avatar":"https://avatars.githubusercontent.com/u/34844?v=4"},"body":"Jrg Sommer <joerg@alea.gnuu.de> wrote:\n> > Wouldn't\n> > \n> > \tpick 5cc8f37 (init: show \"Reinit\" message even in ...)\n> > \tmark 1\n> > \tpick 18d077c (quiltimport: fix misquoting of parse...)\n> > \tmark 2\n> > \treset 1\n> \n> “reset 18d077c~2” or “reset some-tag” or “reset my-branch~12”\n> \n> >         merge #2\n> > \n> > be easier for people?\n> \n> I don't know. Using the special sign everywhere a mark is used looks more\n> consistent to me. The only case where it might be omitted is the mark\n> command, because it only uses marks.\n\nWhy not use the mark syntax that fast-import uses?  In fast-import\nwe use \":n\" anytime we need to refer to a mark, e.g. \":1\" or \":5\".\nIts the same idea.  We already have a language for it.  Heck, the\ncommands above are bordering on a language not too far from the\none that fast-import accepts.  :-)\n\n-- \nShawn.\n"},{"id":"74239","messageId":"7v63umff7r.fsf@gitster.siamese.dyndns.org","threadId":"12825","inReplyTo":"20080412091345.GA31356@alea.gnuu.de","subject":"Re: [PATCH/RFC 06/10] Unify the lenght of $SHORT* and the commits in the TODO list","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2008-04-13T06:20:40Z","receivedAt":"2008-04-13T06:20:40Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jörg Sommer <joerg@alea.gnuu.de> writes:\n\n> “This makes it easier to test for equality of a commit in the TODO list\n> and one of SHORTUPSTREAM, SHORTHEAD or SHORTONTO.”\n\n\"Equality testing?\" --- that makes me worried.  short=7 does not chomp\nthem at 7 but only tells rev-parse to use at least 7.  You may get 8 or\nmore if there are other objects that share the same prefix when you get\nthem.\n\nPerhaps by forcing \"at least 7\" everywhere you are getting consistent\nresult that makes them easier to compare.\n\nBut considering that this is a candidate for a general mechanism to\neventual grow into the git-sequencer, and that we expect to have richer,\nsmarter, and/or more complex set of tools that feeds you the TODO list,\nI'd feel safer if the internal comparison used to determine which one\ncommit the user meant in his TODO file is robust and does not rely on\nwhere the abbreviated object name was chomped at.\n\nSome of the tools may even do not show the raw TODO list in vi to the user\nbut instead present the list in a GUI, and you may get fed the full\n40-hexdigit object name in the underlying TODO list they generate.\n"},{"id":"74278","messageId":"20080413163950.GA3179@alea.gnuu.de","threadId":"12825","inReplyTo":"7v63umff7r.fsf@gitster.siamese.dyndns.org","subject":"Re: [PATCH/RFC 06/10] Unify the lenght of $SHORT* and the commits in the TODO list","fromName":"Jörg Sommer","fromEmail":"joerg@alea.gnuu.de","sentAt":"2008-04-13T16:39:50Z","receivedAt":"2008-04-13T16:39:50Z","isPatch":true,"sender":{"key":"joerg@alea.gnuu.de","avatar":null},"body":"Hallo,\n\nJunio C Hamano schrieb am Sat 12. Apr, 23:20 (-0700):\n> Jörg Sommer <joerg@alea.gnuu.de> writes:\n> \n> > “This makes it easier to test for equality of a commit in the TODO list\n> > and one of SHORTUPSTREAM, SHORTHEAD or SHORTONTO.”\n> \n> \"Equality testing?\" --- that makes me worried.  short=7 does not chomp\n> them at 7 but only tells rev-parse to use at least 7.  You may get 8 or\n> more if there are other objects that share the same prefix when you get\n> them.\n> \n> Perhaps by forcing \"at least 7\" everywhere you are getting consistent\n> result that makes them easier to compare.\n\nThat's what I want.\n\n> But considering that this is a candidate for a general mechanism to\n> eventual grow into the git-sequencer, and that we expect to have richer,\n> smarter, and/or more complex set of tools that feeds you the TODO list,\n> I'd feel safer if the internal comparison used to determine which one\n> commit the user meant in his TODO file is robust and does not rely on\n> where the abbreviated object name was chomped at.\n\nI use it one time while building the TODO list given to the editor. I've\nto replace $UPSTREAM with $ONTO everywhere $UPSTREAM occures.\n\nDo you still have a bad feeling? I can replace all tests by\n\n  test \"$(git rev-parse $a)\" = \"$(git rev-parse $b)\"\n\nBye, Jörg.\n-- \nWas man mühelos erreichen kann, ist gewöhnlich nicht der Mühe wert,\nerreicht zu werden.\n"},{"id":"74277","messageId":"20080413165011.GB3179@alea.gnuu.de","threadId":"12825","inReplyTo":"20080413035648.GY10274@spearce.org","subject":"Re: [PATCH/RFC 01/10] Teach rebase interactive the mark command","fromName":"Jörg Sommer","fromEmail":"joerg@alea.gnuu.de","sentAt":"2008-04-13T16:50:11Z","receivedAt":"2008-04-13T16:50:11Z","isPatch":true,"sender":{"key":"joerg@alea.gnuu.de","avatar":null},"body":"Hi Shawn,\n\nShawn O. Pearce schrieb am Sat 12. Apr, 23:56 (-0400):\n> Jrg Sommer <joerg@alea.gnuu.de> wrote:\n> > > Wouldn't\n> > > \n> > > \tpick 5cc8f37 (init: show \"Reinit\" message even in ...)\n> > > \tmark 1\n> > > \tpick 18d077c (quiltimport: fix misquoting of parse...)\n> > > \tmark 2\n> > > \treset 1\n> > \n> > “reset 18d077c~2” or “reset some-tag” or “reset my-branch~12”\n> > \n> > >         merge #2\n> > > \n> > > be easier for people?\n> > \n> > I don't know. Using the special sign everywhere a mark is used looks more\n> > consistent to me. The only case where it might be omitted is the mark\n> > command, because it only uses marks.\n> \n> Why not use the mark syntax that fast-import uses?\n\nI didn't know it.\n\n> In fast-import we use \":n\" anytime we need to refer to a mark, e.g.\n> \":1\" or \":5\".\n\nCurrently, I don't restrict the mark to be a number. It can anything that\nis a valid ref. Should I restrict it?\n\nAnd how do you handle the :/ syntax? “reset :/Bla” is than not valid.\nMmm, I'll add an exception for :/.\n\nExcept of this, I prefer to use the colon to be much closer to the syntax\nof fast-import.\n\nBye, Jörg.\n-- \nDer Wunsch, klug zu erscheinen, verhindert oft, es zu werden.\n    \t    \t    \t\t\t      (Francois de la Rochefoucauld)\n"},{"id":"74283","messageId":"1208132469-26471-1-git-send-email-joerg@alea.gnuu.de","threadId":"12825","inReplyTo":"7vabkoufzq.fsf@gitster.siamese.dyndns.org","subject":"[PATCH v2 01/13] fake-editor: output TODO list if unchanged","fromName":"Jörg Sommer","fromEmail":"joerg@alea.gnuu.de","sentAt":"2008-04-14T00:20:57Z","receivedAt":"2008-04-14T00:20:57Z","isPatch":true,"sender":{"key":"joerg@alea.gnuu.de","avatar":null},"body":"It's much helpful to see the TODO list generated by rebase in the verbose\noutput of the test. This makes it easier to check, if the list was not\nbroken from the beginning.\n\nSigned-off-by: Jörg Sommer <joerg@alea.gnuu.de>\n---\n t/t3404-rebase-interactive.sh |    2 +-\n 1 files changed, 1 insertions(+), 1 deletions(-)\n\ndiff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh\nindex 9cf873f..8d29878 100755\n--- a/t/t3404-rebase-interactive.sh\n+++ b/t/t3404-rebase-interactive.sh\n@@ -73,7 +73,7 @@ esac\n test -z \"$EXPECT_COUNT\" ||\n \ttest \"$EXPECT_COUNT\" = $(sed -e '/^#/d' -e '/^$/d' < \"$1\" | wc -l) ||\n \texit\n-test -z \"$FAKE_LINES\" && exit\n+test -z \"$FAKE_LINES\" && { grep -v '^#' \"$1\"; exit; }\n grep -v '^#' < \"$1\" > \"$1\".tmp\n rm -f \"$1\"\n cat \"$1\".tmp\n-- \n1.5.5\n"},{"id":"74284","messageId":"1208132469-26471-2-git-send-email-joerg@alea.gnuu.de","threadId":"12825","inReplyTo":"1208132469-26471-1-git-send-email-joerg@alea.gnuu.de","subject":"[PATCH v2 02/13] Don't append default merge message to -m message","fromName":"Jörg Sommer","fromEmail":"joerg@alea.gnuu.de","sentAt":"2008-04-14T00:20:58Z","receivedAt":"2008-04-14T00:20:58Z","isPatch":true,"sender":{"key":"joerg@alea.gnuu.de","avatar":null},"body":"Picked from <7vabko3dm2.fsf@gitster.siamese.dyndns.org>\nFrom: gitster@pobox.com (Junio C Hamano)\nDate: Sun, 23 Mar 2008 22:17:09 -0700\n\nSigned-off-by: Jörg Sommer <joerg@alea.gnuu.de>\n---\n git-merge.sh |   24 +++++++++++++-----------\n 1 files changed, 13 insertions(+), 11 deletions(-)\n\ndiff --git a/git-merge.sh b/git-merge.sh\nindex 7dbbb1d..bd9699d 100755\n--- a/git-merge.sh\n+++ b/git-merge.sh\n@@ -250,17 +250,19 @@ else\n \t# We are invoked directly as the first-class UI.\n \thead_arg=HEAD\n \n-\t# All the rest are the commits being merged; prepare\n-\t# the standard merge summary message to be appended to\n-\t# the given message.  If remote is invalid we will die\n-\t# later in the common codepath so we discard the error\n-\t# in this loop.\n-\tmerge_name=$(for remote\n-\t\tdo\n-\t\t\tmerge_name \"$remote\"\n-\t\tdone | git fmt-merge-msg\n-\t)\n-\tmerge_msg=\"${merge_msg:+$merge_msg$LF$LF}$merge_name\"\n+\tif test -z \"$merge_msg\"\n+\tthen\n+\t\t# All the rest are the commits being merged; prepare\n+\t\t# the standard merge summary message to be appended to\n+\t\t# the given message.  If remote is invalid we will die\n+\t\t# later in the common codepath so we discard the error\n+\t\t# in this loop.\n+\t\tmerge_msg=$(for remote\n+\t\t\tdo\n+\t\t\t\tmerge_name \"$remote\"\n+\t\t\tdone | git fmt-merge-msg\n+\t\t)\n+\tfi\n fi\n head=$(git rev-parse --verify \"$head_arg\"^0) || usage\n \n-- \n1.5.5\n"},{"id":"74285","messageId":"1208132469-26471-3-git-send-email-joerg@alea.gnuu.de","threadId":"12825","inReplyTo":"1208132469-26471-2-git-send-email-joerg@alea.gnuu.de","subject":"[PATCH v2 03/13] Move cleanup code into it's own function","fromName":"Jörg Sommer","fromEmail":"joerg@alea.gnuu.de","sentAt":"2008-04-14T00:20:59Z","receivedAt":"2008-04-14T00:20:59Z","isPatch":true,"sender":{"key":"joerg@alea.gnuu.de","avatar":null},"body":"\nSigned-off-by: Jörg Sommer <joerg@alea.gnuu.de>\n---\n git-rebase--interactive.sh |   10 +++++++---\n 1 files changed, 7 insertions(+), 3 deletions(-)\n\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex 8aa7371..531ee94 100755\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -104,8 +104,12 @@ die_with_patch () {\n \tdie \"$2\"\n }\n \n-die_abort () {\n+cleanup_before_quit () {\n \trm -rf \"$DOTEST\"\n+}\n+\n+die_abort () {\n+\tcleanup_before_quit\n \tdie \"$1\"\n }\n \n@@ -352,7 +356,7 @@ do_next () {\n \t\ttest ! -f \"$DOTEST\"/verbose ||\n \t\t\tgit diff-tree --stat $(cat \"$DOTEST\"/head)..HEAD\n \t} &&\n-\trm -rf \"$DOTEST\" &&\n+\tcleanup_before_quit &&\n \tgit gc --auto &&\n \twarn \"Successfully rebased and updated $HEADNAME.\"\n \n@@ -414,7 +418,7 @@ do\n \t\t\t;;\n \t\tesac &&\n \t\toutput git reset --hard $HEAD &&\n-\t\trm -rf \"$DOTEST\"\n+\t\tcleanup_before_quit\n \t\texit\n \t\t;;\n \t--skip)\n-- \n1.5.5\n"},{"id":"74289","messageId":"1208132469-26471-4-git-send-email-joerg@alea.gnuu.de","threadId":"12825","inReplyTo":"1208132469-26471-3-git-send-email-joerg@alea.gnuu.de","subject":"[PATCH v2 04/13] Teach rebase interactive the mark command","fromName":"Jörg Sommer","fromEmail":"joerg@alea.gnuu.de","sentAt":"2008-04-14T00:21:00Z","receivedAt":"2008-04-14T00:21:00Z","isPatch":true,"sender":{"key":"joerg@alea.gnuu.de","avatar":null},"body":"This new command can be used to set symbolic marks for an commit while\ndoing a rebase. This symbolic name can later be used for merges or\nresets.\n\nThe decision to use references for the marks and not files like done with\nthe rewritten commits for preserve merges was made to ensure no commit\nobjects get lost if prune is started while (a long term) rebase is\nrunning. This also unifies the checking of the validity of marks and\nreferences by using rev-parse for it.\n\nThe usage of : as the sign for marks conforms with the tag sign of\nfast-export and fast-import.\n\nSigned-off-by: Jörg Sommer <joerg@alea.gnuu.de>\n---\n git-rebase--interactive.sh    |   37 ++++++++++++++++++++++++++++++++++++-\n t/t3404-rebase-interactive.sh |   17 +++++++++++++++++\n 2 files changed, 53 insertions(+), 1 deletions(-)\n\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex 531ee94..6ac316a 100755\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -35,6 +35,8 @@ mark the corrected paths with 'git add <paths>', and\n run 'git rebase --continue'\"\n export GIT_CHERRY_PICK_HELP\n \n+mark_prefix=refs/rebase-marks/\n+\n warn () {\n \techo \"$*\" >&2\n }\n@@ -105,7 +107,13 @@ die_with_patch () {\n }\n \n cleanup_before_quit () {\n-\trm -rf \"$DOTEST\"\n+\trm -rf \"$DOTEST\" &&\n+\tfor ref in \"$GIT_DIR/$mark_prefix\"*\n+\tdo\n+\t\ttest \"$ref\" = \"$GIT_DIR/$mark_prefix*\" && continue\n+\t\tgit update-ref -d \"${ref#$GIT_DIR/}\" \"${ref#$GIT_DIR/}\" || \\\n+\t\t\treturn 1\n+\tdone\n }\n \n die_abort () {\n@@ -244,6 +252,19 @@ peek_next_command () {\n \tsed -n \"1s/ .*$//p\" < \"$TODO\"\n }\n \n+mark_to_ref () {\n+\tcase \"$1\" in\n+\t:[!/]*)\n+\t\t# :/SOMETHING is a reference for the last commit whose\n+                # message starts with SOMETHING\n+\t\techo \"$mark_prefix${1#:}\"\n+\t\t;;\n+\t*)\n+\t\techo \"$1\"\n+\t\t;;\n+\tesac\n+}\n+\n do_next () {\n \trm -f \"$DOTEST\"/message \"$DOTEST\"/author-script \\\n \t\t\"$DOTEST\"/amend || exit\n@@ -321,6 +342,15 @@ do_next () {\n \t\t\tdie_with_patch $sha1 \"\"\n \t\tfi\n \t\t;;\n+\tmark)\n+\t\tmark_action_done\n+\n+\t\tmark=$(mark_to_ref :${sha1#:})\n+\t\tgit rev-parse --verify \"$mark\" > /dev/null 2>&1 && \\\n+\t\t\twarn \"mark $sha1 already exist; overwriting it\"\n+\n+\t\tgit update-ref \"$mark\" HEAD || die \"update-ref failed\"\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@@ -533,10 +563,15 @@ do\n \n # Rebase $SHORTUPSTREAM..$SHORTHEAD onto $SHORTONTO\n #\n+# In the todo insn whenever you need to refer to a commit, in addition\n+# to the usual commit object name, you can use ':mark' syntax to refer\n+# to a commit previously marked with the 'mark' insn.\n+#\n # Commands:\n #  pick = use commit\n #  edit = use commit, but stop for amending\n #  squash = use commit, but meld into previous commit\n+#  mark :mark = mark the current HEAD for later reference\n #\n # If you remove a line here THAT COMMIT WILL BE LOST.\n # However, if you remove everything, the rebase will be aborted.\ndiff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh\nindex 8d29878..fa3560e 100755\n--- a/t/t3404-rebase-interactive.sh\n+++ b/t/t3404-rebase-interactive.sh\n@@ -82,6 +82,9 @@ for line in $FAKE_LINES; do\n \tcase $line in\n \tsquash|edit)\n \t\taction=\"$line\";;\n+\tmark*)\n+\t\techo \"mark ${line#mark}\"\n+\t\techo \"mark ${line#mark}\" >> \"$1\";;\n \t*)\n \t\techo sed -n \"${line}s/^pick/$action/p\"\n \t\tsed -n \"${line}p\" < \"$1\".tmp\n@@ -189,6 +192,20 @@ test_expect_success '-p handles \"no changes\" gracefully' '\n \ttest $HEAD = $(git rev-parse HEAD)\n '\n \n+test_expect_success 'setting marks works' '\n+\tgit checkout master &&\n+\tFAKE_LINES=\"mark:0 2 1 mark:42 3 edit 4\" git rebase -i HEAD~4 &&\n+\tmarks_dir=.git/refs/rebase-marks &&\n+\ttest -d $marks_dir &&\n+\ttest $(ls $marks_dir | wc -l) -eq 2 &&\n+\ttest \"$(git rev-parse HEAD~4)\" = \\\n+\t\t\"$(git rev-parse refs/rebase-marks/0)\" &&\n+\ttest \"$(git rev-parse HEAD~2)\" = \\\n+\t\t\"$(git rev-parse refs/rebase-marks/42)\" &&\n+\tgit rebase --abort &&\n+\tls $marks_dir | wc -l | grep -Fx 0\n+'\n+\n test_expect_success 'preserve merges with -p' '\n \tgit checkout -b to-be-preserved master^ &&\n \t: > unrelated-file &&\n-- \n1.5.5\n"},{"id":"74291","messageId":"1208132469-26471-5-git-send-email-joerg@alea.gnuu.de","threadId":"12825","inReplyTo":"1208132469-26471-4-git-send-email-joerg@alea.gnuu.de","subject":"[PATCH v2 05/13] Teach rebase interactive the reset command","fromName":"Jörg Sommer","fromEmail":"joerg@alea.gnuu.de","sentAt":"2008-04-14T00:21:01Z","receivedAt":"2008-04-14T00:21:01Z","isPatch":true,"sender":{"key":"joerg@alea.gnuu.de","avatar":null},"body":"This command does a hard reset of the HEAD, i.e. the next operation used\nthis commit as parent. This is necessary to redo the commits of different\nbranches they become merged later.\n\nSigned-off-by: Jörg Sommer <joerg@alea.gnuu.de>\n---\n git-rebase--interactive.sh    |   10 ++++++++++\n t/t3404-rebase-interactive.sh |   17 +++++++++++++++++\n 2 files changed, 27 insertions(+), 0 deletions(-)\n\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex 6ac316a..a4b7aad 100755\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -351,6 +351,15 @@ do_next () {\n \n \t\tgit update-ref \"$mark\" HEAD || die \"update-ref failed\"\n \t\t;;\n+\treset|r)\n+\t\tcomment_for_reflog reset\n+\n+\t\ttmp=$(git rev-parse --verify \"$(mark_to_ref $sha1)\") ||\n+\t\t\tdie \"Invalid parent '$sha1' in $command $sha1 $rest\"\n+\n+\t\tmark_action_done\n+\t\toutput git reset --hard $tmp\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@@ -572,6 +581,7 @@ do\n #  edit = use commit, but stop for amending\n #  squash = use commit, but meld into previous commit\n #  mark :mark = mark the current HEAD for later reference\n+#  reset commit = reset HEAD to the commit\n #\n # If you remove a line here THAT COMMIT WILL BE LOST.\n # However, if you remove everything, the rebase will be aborted.\ndiff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh\nindex fa3560e..78673a6 100755\n--- a/t/t3404-rebase-interactive.sh\n+++ b/t/t3404-rebase-interactive.sh\n@@ -85,6 +85,9 @@ for line in $FAKE_LINES; do\n \tmark*)\n \t\techo \"mark ${line#mark}\"\n \t\techo \"mark ${line#mark}\" >> \"$1\";;\n+\treset*)\n+\t\techo \"reset ${line#reset}\"\n+\t\techo \"reset ${line#reset}\" >> \"$1\";;\n \t*)\n \t\techo sed -n \"${line}s/^pick/$action/p\"\n \t\tsed -n \"${line}p\" < \"$1\".tmp\n@@ -206,6 +209,20 @@ test_expect_success 'setting marks works' '\n \tls $marks_dir | wc -l | grep -Fx 0\n '\n \n+test_expect_success 'reset with nonexistent mark fails' '\n+\texport FAKE_LINES=\"reset:0 1\" &&\n+\ttest_must_fail git rebase -i HEAD~1 &&\n+\tunset FAKE_LINES &&\n+\tgit rebase --abort\n+'\n+\n+test_expect_success 'reset to HEAD is a nop' '\n+\ttest_tick &&\n+\thead=$(git rev-parse --short HEAD) &&\n+\tFAKE_LINES=\"reset$head\" git rebase -i HEAD~4 &&\n+\ttest \"$(git rev-parse --short HEAD)\" = \"$head\"\n+'\n+\n test_expect_success 'preserve merges with -p' '\n \tgit checkout -b to-be-preserved master^ &&\n \t: > unrelated-file &&\n-- \n1.5.5\n"},{"id":"74292","messageId":"1208132469-26471-6-git-send-email-joerg@alea.gnuu.de","threadId":"12825","inReplyTo":"1208132469-26471-5-git-send-email-joerg@alea.gnuu.de","subject":"[PATCH v2 06/13] Move redo merge code in a function","fromName":"Jörg Sommer","fromEmail":"joerg@alea.gnuu.de","sentAt":"2008-04-14T00:21:02Z","receivedAt":"2008-04-14T00:21:02Z","isPatch":true,"sender":{"key":"joerg@alea.gnuu.de","avatar":null},"body":"\nSigned-off-by: Jörg Sommer <joerg@alea.gnuu.de>\n---\n git-rebase--interactive.sh |   35 ++++++++++++++++++++---------------\n 1 files changed, 20 insertions(+), 15 deletions(-)\n\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex a4b7aad..19145b1 100755\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -125,6 +125,25 @@ has_action () {\n \tgrep '^[^#]' \"$1\" >/dev/null\n }\n \n+redo_merge () {\n+\trm_sha1=$1\n+\tshift\n+\n+\teval \"$(get_author_ident_from_commit $rm_sha1)\"\n+\tmsg=\"$(git cat-file commit $rm_sha1 | sed -e '1,/^$/d')\"\n+\n+\tif ! GIT_AUTHOR_NAME=\"$GIT_AUTHOR_NAME\" \\\n+\t\tGIT_AUTHOR_EMAIL=\"$GIT_AUTHOR_EMAIL\" \\\n+\t\tGIT_AUTHOR_DATE=\"$GIT_AUTHOR_DATE\" \\\n+\t\toutput git merge $STRATEGY -m \"$msg\" \"$@\"\n+\tthen\n+\t\tgit rerere\n+\t\tprintf \"%s\\n\" \"$msg\" > \"$GIT_DIR\"/MERGE_MSG\n+\t\tdie Error redoing merge $rm_sha1\n+\tfi\n+\tunset rm_sha1\n+}\n+\n pick_one () {\n \tno_ff=\n \tcase \"$1\" in -n) sha1=$2; no_ff=t ;; *) sha1=$1 ;; esac\n@@ -192,22 +211,8 @@ pick_one_preserving_merges () {\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\tredo_merge $sha1 ${new_parents# $first_parent}\n \t\t\t;;\n \t\t*)\n \t\t\toutput git cherry-pick \"$@\" ||\n-- \n1.5.5\n"},{"id":"74287","messageId":"1208132469-26471-7-git-send-email-joerg@alea.gnuu.de","threadId":"12825","inReplyTo":"1208132469-26471-6-git-send-email-joerg@alea.gnuu.de","subject":"[PATCH v2 07/13] Teach rebase interactive the merge command","fromName":"Jörg Sommer","fromEmail":"joerg@alea.gnuu.de","sentAt":"2008-04-14T00:21:03Z","receivedAt":"2008-04-14T00:21:03Z","isPatch":true,"sender":{"key":"joerg@alea.gnuu.de","avatar":null},"body":"This command redoes merges. It's useful if you rebase a branch that\ncontains merges and you want to preserve these merges. You can also use\nit to add new merges.\n\nSigned-off-by: Jörg Sommer <joerg@alea.gnuu.de>\n---\n git-rebase--interactive.sh    |   24 ++++++++++++++++++++++++\n t/t3404-rebase-interactive.sh |   13 +++++++++++++\n 2 files changed, 37 insertions(+), 0 deletions(-)\n\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex 19145b1..fd41ca0 100755\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -356,6 +356,28 @@ do_next () {\n \n \t\tgit update-ref \"$mark\" HEAD || die \"update-ref failed\"\n \t\t;;\n+\tmerge|m)\n+\t\tcomment_for_reflog merge\n+\n+\t\tif ! git rev-parse --verify $sha1 > /dev/null\n+\t\tthen\n+\t\t\tdie \"Invalid reference merge '$sha1' in\"\n+\t\t\t\t\t\"$command $sha1 $rest\"\n+\t\tfi\n+\n+\t\tnew_parents=\n+\t\tfor p in $rest\n+\t\tdo\n+\t\t\tnew_parents=\"$new_parents $(mark_to_ref $p)\"\n+\t\tdone\n+\t\tnew_parents=\"${new_parents# }\"\n+\t\ttest -n \"$new_parents\" || \\\n+\t\t\tdie \"You forgot to give the parents for the\" \\\n+\t\t\t\t\"merge $sha1. Please fix it in $TODO\"\n+\n+\t\tmark_action_done\n+\t\tredo_merge $sha1 $new_parents\n+\t\t;;\n \treset|r)\n \t\tcomment_for_reflog reset\n \n@@ -587,6 +609,8 @@ do\n #  squash = use commit, but meld into previous commit\n #  mark :mark = mark the current HEAD for later reference\n #  reset commit = reset HEAD to the commit\n+#  merge commit-M commit-P ... = redo merge commit-M with the\n+#         current HEAD and the parents commit-P\n #\n # If you remove a line here THAT COMMIT WILL BE LOST.\n # However, if you remove everything, the rebase will be aborted.\ndiff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh\nindex 78673a6..ceb9d74 100755\n--- a/t/t3404-rebase-interactive.sh\n+++ b/t/t3404-rebase-interactive.sh\n@@ -88,6 +88,9 @@ for line in $FAKE_LINES; do\n \treset*)\n \t\techo \"reset ${line#reset}\"\n \t\techo \"reset ${line#reset}\" >> \"$1\";;\n+\tmerge*)\n+\t\techo \"merge ${line#merge}\" | tr / ' '\n+\t\techo \"merge ${line#merge}\" | tr / ' ' >> \"$1\";;\n \t*)\n \t\techo sed -n \"${line}s/^pick/$action/p\"\n \t\tsed -n \"${line}p\" < \"$1\".tmp\n@@ -223,6 +226,16 @@ test_expect_success 'reset to HEAD is a nop' '\n \ttest \"$(git rev-parse --short HEAD)\" = \"$head\"\n '\n \n+test_expect_success 'merge redoes merges' '\n+\ttest_tick &&\n+\tgit merge dead-end &&\n+\tmerge=$(git rev-parse HEAD) &&\n+\tgit reset --hard HEAD~1 &&\n+\tFAKE_LINES=\"1 merge$merge/dead-end\" git rebase -i HEAD~1 &&\n+\ttest $merge = \"$(git rev-parse HEAD)\" &&\n+\tgit reset --hard HEAD~1\n+'\n+\n test_expect_success 'preserve merges with -p' '\n \tgit checkout -b to-be-preserved master^ &&\n \t: > unrelated-file &&\n-- \n1.5.5\n"},{"id":"74282","messageId":"1208132469-26471-8-git-send-email-joerg@alea.gnuu.de","threadId":"12825","inReplyTo":"1208132469-26471-7-git-send-email-joerg@alea.gnuu.de","subject":"[PATCH v2 08/13] Unify the lenght of $SHORT* and the commits in the TODO list","fromName":"Jörg Sommer","fromEmail":"joerg@alea.gnuu.de","sentAt":"2008-04-14T00:21:04Z","receivedAt":"2008-04-14T00:21:04Z","isPatch":true,"sender":{"key":"joerg@alea.gnuu.de","avatar":null},"body":"This makes it easier to test for equality of a commit in the TODO list\nand one of SHORTUPSTREAM, SHORTHEAD or SHORTONTO.\n\nSigned-off-by: Jörg Sommer <joerg@alea.gnuu.de>\n---\n git-rebase--interactive.sh |    6 +++---\n 1 files changed, 3 insertions(+), 3 deletions(-)\n\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex fd41ca0..d0a7e5c 100755\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -588,9 +588,9 @@ do\n \t\t\tMERGES_OPTION=--no-merges\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\tSHORTUPSTREAM=$(git rev-parse --short=7 $UPSTREAM)\n+\t\tSHORTHEAD=$(git rev-parse --short=7 $HEAD)\n+\t\tSHORTONTO=$(git rev-parse --short=7 $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-- \n1.5.5\n"},{"id":"74290","messageId":"1208132469-26471-9-git-send-email-joerg@alea.gnuu.de","threadId":"12825","inReplyTo":"1208132469-26471-8-git-send-email-joerg@alea.gnuu.de","subject":"[PATCH v2 09/13] Select all lines with fake-editor","fromName":"Jörg Sommer","fromEmail":"joerg@alea.gnuu.de","sentAt":"2008-04-14T00:21:05Z","receivedAt":"2008-04-14T00:21:05Z","isPatch":true,"sender":{"key":"joerg@alea.gnuu.de","avatar":null},"body":"The old fake-editor selects only lines they start with pick, if you give\nthe number of a line. With the new commands mark, merge and reset it was\nnot possible to select such lines for the new TODO list. The new\nfake-editor selects all kinds of lines, but replaces only the command\n“pick” with a different action.\n\nSigned-off-by: Jörg Sommer <joerg@alea.gnuu.de>\n---\n t/t3404-rebase-interactive.sh |    5 ++---\n 1 files changed, 2 insertions(+), 3 deletions(-)\n\ndiff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh\nindex ceb9d74..0a8d065 100755\n--- a/t/t3404-rebase-interactive.sh\n+++ b/t/t3404-rebase-interactive.sh\n@@ -92,9 +92,8 @@ for line in $FAKE_LINES; do\n \t\techo \"merge ${line#merge}\" | tr / ' '\n \t\techo \"merge ${line#merge}\" | tr / ' ' >> \"$1\";;\n \t*)\n-\t\techo sed -n \"${line}s/^pick/$action/p\"\n-\t\tsed -n \"${line}p\" < \"$1\".tmp\n-\t\tsed -n \"${line}s/^pick/$action/p\" < \"$1\".tmp >> \"$1\"\n+\t\tsed -n \"${line}{s/^pick/$action/; p;}\" < \"$1\".tmp\n+\t\tsed -n \"${line}{s/^pick/$action/; p;}\" < \"$1\".tmp >> \"$1\"\n \t\taction=pick;;\n \tesac\n done\n-- \n1.5.5\n"},{"id":"74327","messageId":"1208132469-26471-10-git-send-email-joerg@alea.gnuu.de","threadId":"12825","inReplyTo":"1208132469-26471-9-git-send-email-joerg@alea.gnuu.de","subject":"[PATCH v2 10/13] Do rebase with preserve merges with advanced TODO list","fromName":"Jörg Sommer","fromEmail":"joerg@alea.gnuu.de","sentAt":"2008-04-14T00:21:06Z","receivedAt":"2008-04-14T00:21:06Z","isPatch":true,"sender":{"key":"joerg@alea.gnuu.de","avatar":null},"body":"The current algorithmus used to rebase a branch with merges on top of\nanother has some drawbacks: it's not possible to squash commits, it's not\npossible to change the order of commits, particularly the tip of the\nbranch can't change.\n\nThis new algorithmus uses the idea from Junio to create a TODO list with\nthe commands mark, merge and reset to represent the nonlinear structure\nof merges.\n\nSigned-off-by: Jörg Sommer <joerg@alea.gnuu.de>\n---\n git-rebase--interactive.sh    |  239 ++++++++++++++++++++++++-----------------\n t/t3404-rebase-interactive.sh |   37 +++++++\n 2 files changed, 175 insertions(+), 101 deletions(-)\n\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex d0a7e5c..d3327a8 100755\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -22,11 +22,9 @@ TODO=\"$DOTEST\"/git-rebase-todo\n DONE=\"$DOTEST\"/done\n MSG=\"$DOTEST\"/message\n SQUASH_MSG=\"$DOTEST\"/message-squash\n-REWRITTEN=\"$DOTEST\"/rewritten\n PRESERVE_MERGES=\n STRATEGY=\n VERBOSE=\n-test -d \"$REWRITTEN\" && PRESERVE_MERGES=t\n test -f \"$DOTEST\"/strategy && STRATEGY=\"$(cat \"$DOTEST\"/strategy)\"\n test -f \"$DOTEST\"/verbose && VERBOSE=t\n \n@@ -148,8 +146,6 @@ 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@@ -163,66 +159,6 @@ pick_one () {\n \tfi\n }\n \n-pick_one_preserving_merges () {\n-\tcase \"$1\" in -n) sha1=$2 ;; *) sha1=$1 ;; esac\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-\tfor p in $(git rev-list --parents -1 $sha1 | cut -d' ' -f2-)\n-\tdo\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-\t\t\t*)\n-\t\t\t\tnew_parents=\"$new_parents $new_p\"\n-\t\t\t\t;;\n-\t\t\tesac\n-\t\tfi\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# No point in merging the first parent, that's HEAD\n-\t\t\tredo_merge $sha1 ${new_parents# $first_parent}\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-\n nth_string () {\n \tcase \"$1\" in\n \t*1[0-9]|*[04-9]) echo \"$1\"th;;\n@@ -398,20 +334,7 @@ do_next () {\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@@ -436,6 +359,130 @@ do_rest () {\n \tdone\n }\n \n+get_value_from_list () {\n+\t# args: \"key\" \" key1#value1 key2#value2\"\n+\tcase \"$2\" in\n+\t*\" $1#\"*)\n+\t\tstm_tmp=\"${2#* $1#}\"\n+\t\techo \"${stm_tmp%% *}\"\n+\t\tunset stm_tmp\n+\t\t;;\n+\t*)\n+\t\treturn 1\n+\t\t;;\n+\tesac\n+}\n+\n+insert_value_at_key_into_list () {\n+\t# args: \"value\" \"key\" \" key1#value1 key2#value2\"\n+\tcase \"$3 \" in\n+\t*\" $2#$1 \"*)\n+\t\techo \"$3\"\n+\t\t;;\n+\t*\" $2#\"*)\n+\t\techo \"$3\"\n+\t\treturn 1\n+\t\t;;\n+\t*)\n+\t\techo \"$3 $2#$1\"\n+\t\t;;\n+\tesac\n+}\n+\n+create_extended_todo_list () {\n+\t(\n+\twhile IFS=_ read commit parents subject\n+\tdo\n+\t\tif test \"${last_parent:-$commit}\" != \"$commit\"\n+\t\tthen\n+\t\t\tif test t = \"${delayed_mark:-f}\"\n+\t\t\tthen\n+\t\t\t\tmarked_commits=$(insert_value_at_key_into_list \\\n+\t\t\t\t\tdummy $last_parent \"${marked_commits:-}\")\n+\t\t\t\tdelayed_mark=f\n+\t\t\tfi\n+\t\t\ttest \"$last_parent\" = $SHORTUPSTREAM && \\\n+\t\t\t\tlast_parent=$SHORTONTO\n+\t\t\techo \"reset $last_parent\"\n+\t\tfi\n+\t\tlast_parent=\"${parents%% *}\"\n+\n+\t\tget_value_from_list $commit \"${marked_commits:-}\" \\\n+\t\t\t>/dev/null && echo mark\n+\n+\t\tcase \"$parents\" in\n+\t\t*' '*)\n+\t\t\tdelayed_mark=t\n+\t\t\tnew_parents=\n+\t\t\tfor p in ${parents#* }\n+\t\t\tdo\n+\t\t\t\tmarked_commits=$(insert_value_at_key_into_list \\\n+\t\t\t\t\tdummy \"$p\" \"${marked_commits:-}\")\n+\t\t\t\tif test \"$p\" = $SHORTUPSTREAM\n+\t\t\t\tthen\n+\t\t\t\t\tnew_parents=\"$new_parents $SHORTONTO\"\n+\t\t\t\telse\n+\t\t\t\t\tnew_parents=\"$new_parents $p\"\n+\t\t\t\tfi\n+\t\t\tdone\n+\t\t\tunset p\n+\t\t\techo merge $commit $new_parents\n+\t\t\tunset new_parents\n+\t\t\t;;\n+\t\t*)\n+\t\t\techo \"pick $commit $subject\"\n+\t\t\t;;\n+\t\tesac\n+\tdone\n+\ttest -n \"${last_parent:-}\" -a \"${last_parent:-}\" != $SHORTUPSTREAM && \\\n+\t\techo reset $last_parent\n+\t) | \\\n+\ttac | \\\n+\twhile read cmd args\n+\tdo\n+\t\t: ${commit_mark_list:=} ${last_commit:=000}\n+\t\tcase \"$cmd\" in\n+\t\tpick)\n+\t\t\tlast_commit=\"${args%% *}\"\n+\t\t\t;;\n+\t\tmark)\n+\t\t\t: ${next_mark:=0}\n+\t\t\tif commit_mark_list=$(insert_value_at_key_into_list \\\n+\t\t\t\t$next_mark $last_commit \"$commit_mark_list\")\n+\t\t\tthen\n+\t\t\t\targs=\":$next_mark\"\n+\t\t\t\tnext_mark=$(($next_mark + 1))\n+\t\t\telse\n+\t\t\t\tdie \"Internal error: two marks for\" \\\n+\t\t\t\t\t\"the same commit\"\n+\t\t\tfi\n+\t\t\t;;\n+\t\treset)\n+\t\t\tif tmp=$(get_value_from_list $args \"$commit_mark_list\")\n+\t\t\tthen\n+\t\t\t\targs=\":$tmp\"\n+\t\t\tfi\n+\t\t\t;;\n+\t\tmerge)\n+\t\t\tnew_args=\n+\t\t\tfor i in ${args#* }\n+\t\t\tdo\n+\t\t\t\tif tmp=$(get_value_from_list $i \\\n+\t\t\t\t\t\"$commit_mark_list\")\n+\t\t\t\tthen\n+\t\t\t\t\tnew_args=\"$new_args :$tmp\"\n+\t\t\t\telse\n+\t\t\t\t\tnew_args=\"$new_args $i\"\n+\t\t\t\tfi\n+\t\t\tdone\n+\t\t\tlast_commit=\"${args%% *}\"\n+\t\t\targs=\"$last_commit ${new_args# }\"\n+\t\t\t;;\n+\t\tesac\n+\t\techo \"$cmd $args\"\n+\tdone\n+}\n+\n while test $# != 0\n do\n \tcase \"$1\" in\n@@ -568,33 +615,23 @@ do\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\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\tmkdir \"$REWRITTEN\" &&\n-\t\t\tfor c in $(git merge-base --all $HEAD $UPSTREAM)\n-\t\t\tdo\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\tfi\n \n \t\tSHORTUPSTREAM=$(git rev-parse --short=7 $UPSTREAM)\n \t\tSHORTHEAD=$(git rev-parse --short=7 $HEAD)\n \t\tSHORTONTO=$(git rev-parse --short=7 $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\tcommon_rev_list_opts=\"--abbrev-commit --abbrev=7\n+\t\t\t--left-right --cherry-pick $UPSTREAM...$HEAD\"\n+\t\tif test t = \"$PRESERVE_MERGES\"\n+\t\tthen\n+\t\t\tgit rev-list --pretty='format:%h_%p_%s' --topo-order \\\n+\t\t\t\t$common_rev_list_opts | \\\n+\t\t\t\tgrep -v ^commit | \\\n+\t\t\t\tcreate_extended_todo_list\n+\t\telse\n+\t\t\tgit rev-list --no-merges --reverse --pretty=oneline \\\n+\t\t\t\t $common_rev_list_opts | sed -n \"s/^>/pick /p\"\n+\t\tfi > \"$TODO\"\n+\n \t\tcat >> \"$TODO\" << EOF\n \n # Rebase $SHORTUPSTREAM..$SHORTHEAD onto $SHORTONTO\ndiff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh\nindex 0a8d065..f919aaf 100755\n--- a/t/t3404-rebase-interactive.sh\n+++ b/t/t3404-rebase-interactive.sh\n@@ -258,7 +258,44 @@ test_expect_success 'preserve merges with -p' '\n \ttest $(git show HEAD~2:file1) = B\n '\n \n+test_expect_success 'rebase with preserve merge forth and back is a noop' '\n+\tgit checkout -b big-branch-1 master &&\n+\ttest_tick &&\n+\t: > bb1a &&\n+\tgit add bb1a &&\n+\tgit commit -m \"big branch commit 1\" &&\n+\t: > bb1b &&\n+\tgit add bb1b &&\n+\tgit commit -m \"big branch commit 2\" &&\n+\t: > bb1c &&\n+\tgit add bb1c &&\n+\tgit commit -m \"big branch commit 3\" &&\n+\tgit checkout -b big-branch-2 master &&\n+\t: > bb2a &&\n+\tgit add bb2a &&\n+\tgit commit -m \"big branch commit 4\" &&\n+\t: > bb2b &&\n+\tgit add bb2b &&\n+\tgit commit -m \"big branch commit 5\" &&\n+\tgit merge big-branch-1~1 &&\n+\tgit merge to-be-preserved &&\n+\ttbp_merge=$(git rev-parse HEAD) &&\n+\t: > bb2c &&\n+\tgit add bb2c &&\n+\tgit commit -m \"big branch commit 6\" &&\n+\tgit merge big-branch-1 &&\n+\thead=$(git rev-parse HEAD) &&\n+\tFAKE_LINES=\"16 6 19 20 4 1 2 5 22\" \\\n+\t\tgit rebase -i -p --onto dead-end master &&\n+\ttest \"$head\" != \"$(git rev-parse HEAD)\" &&\n+\tFAKE_LINES=\"3 7 mark:10 8 9 5 1 2 merge$tbp_merge~1/:10 \\\n+\t\tmerge$tbp_merge/to-be-preserved 6 11\" \\\n+\t\tgit rebase -i -p --onto master dead-end &&\n+\ttest \"$head\" = \"$(git rev-parse HEAD)\"\n+'\n+\n test_expect_success '--continue tries to commit' '\n+\tgit checkout to-be-rebased &&\n \ttest_tick &&\n \t! git rebase -i --onto new-branch1 HEAD^ &&\n \techo resolved > file1 &&\n-- \n1.5.5\n"},{"id":"74280","messageId":"1208132469-26471-11-git-send-email-joerg@alea.gnuu.de","threadId":"12825","inReplyTo":"1208132469-26471-10-git-send-email-joerg@alea.gnuu.de","subject":"[PATCH v2 11/13] Add option --first-parent","fromName":"Jörg Sommer","fromEmail":"joerg@alea.gnuu.de","sentAt":"2008-04-14T00:21:07Z","receivedAt":"2008-04-14T00:21:07Z","isPatch":true,"sender":{"key":"joerg@alea.gnuu.de","avatar":null},"body":"With this new option it's possible to narrow the list of commits in the\nTODO list to only those commits you get following the first parent of\neach merge, i.e. not those from the merged branches.\n\nSigned-off-by: Jörg Sommer <joerg@alea.gnuu.de>\n---\n Documentation/git-rebase.txt  |    7 ++++++-\n git-rebase--interactive.sh    |   15 +++++++++++----\n t/t3404-rebase-interactive.sh |   12 ++++++++++++\n 3 files changed, 29 insertions(+), 5 deletions(-)\n\ndiff --git a/Documentation/git-rebase.txt b/Documentation/git-rebase.txt\nindex e0412e0..9ebbb90 100644\n--- a/Documentation/git-rebase.txt\n+++ b/Documentation/git-rebase.txt\n@@ -11,7 +11,7 @@ SYNOPSIS\n 'git-rebase' [-i | --interactive] [-v | --verbose] [-m | --merge]\n \t[-s <strategy> | --strategy=<strategy>]\n \t[-C<n>] [ --whitespace=<option>] [-p | --preserve-merges]\n-\t[--onto <newbase>] <upstream> [<branch>]\n+\t[-f | --first-parent] [--onto <newbase>] <upstream> [<branch>]\n 'git-rebase' --continue | --skip | --abort\n \n DESCRIPTION\n@@ -247,6 +247,11 @@ OPTIONS\n \tInstead of ignoring merges, try to recreate them.  This option\n \tonly works in interactive mode.\n \n+-f, \\--first-parent::\n+\tThis option implies the option --preserve-merges, but instead of\n+\tshowing all commits from the merged branches show only the\n+\tcommits and merges following the first parent of each commit.\n+\n include::merge-strategies.txt[]\n \n NOTES\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex d3327a8..ea67942 100755\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -10,8 +10,8 @@\n # The original idea comes from Eric W. Biederman, in\n # http://article.gmane.org/gmane.comp.version-control.git/22407\n \n-USAGE='(--continue | --abort | --skip | [--preserve-merges] [--verbose]\n-\t[--onto <branch>] <upstream> [<branch>])'\n+USAGE='(--continue | --abort | --skip | [--preserve-merges] [--first-parent]\n+\t[--verbose] [--onto <branch>] <upstream> [<branch>])'\n \n OPTIONS_SPEC=\n . git-sh-setup\n@@ -565,6 +565,10 @@ do\n \t-p|--preserve-merges)\n \t\tPRESERVE_MERGES=t\n \t\t;;\n+\t-f|--first-parent)\n+\t\tFIRST_PARENT=t\n+\t\tPRESERVE_MERGES=t\n+\t\t;;\n \t-i|--interactive)\n \t\t# yeah, we know\n \t\t;;\n@@ -621,10 +625,13 @@ do\n \t\tSHORTONTO=$(git rev-parse --short=7 $ONTO)\n \t\tcommon_rev_list_opts=\"--abbrev-commit --abbrev=7\n \t\t\t--left-right --cherry-pick $UPSTREAM...$HEAD\"\n-\t\tif test t = \"$PRESERVE_MERGES\"\n+\t\tif test t = \"$PRESERVE_MERGES\" -o t = \"${FIRST_PARENT:-f}\"\n \t\tthen\n+\t\t\topts=\n+\t\t\ttest t = \"${FIRST_PARENT:-f}\" && \\\n+\t\t\t\topts=\"$opts --first-parent\"\n \t\t\tgit rev-list --pretty='format:%h_%p_%s' --topo-order \\\n-\t\t\t\t$common_rev_list_opts | \\\n+\t\t\t\t$opts $common_rev_list_opts | \\\n \t\t\t\tgrep -v ^commit | \\\n \t\t\t\tcreate_extended_todo_list\n \t\telse\ndiff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh\nindex f919aaf..8da7829 100755\n--- a/t/t3404-rebase-interactive.sh\n+++ b/t/t3404-rebase-interactive.sh\n@@ -294,6 +294,18 @@ test_expect_success 'rebase with preserve merge forth and back is a noop' '\n \ttest \"$head\" = \"$(git rev-parse HEAD)\"\n '\n \n+test_expect_success 'interactive --first-parent gives a linear list' '\n+\thead=$(git rev-parse HEAD) &&\n+\tEXPECT_COUNT=6 FAKE_LINES=\"2 1 4 3 6 5\" \\\n+\t\tgit rebase -i -f --onto dead-end master &&\n+\ttest \"$head\" != \"$(git rev-parse HEAD)\" &&\n+\tgit rev-parse HEAD^^2 &&\n+\ttest \"$(git rev-parse HEAD~6)\" = \"$(git rev-parse dead-end)\" &&\n+\tEXPECT_COUNT=6 FAKE_LINES=\"2 1 4 3 6 5\" \\\n+\t\tgit rebase -i -f --onto master dead-end &&\n+\ttest \"$head\" = \"$(git rev-parse HEAD)\"\n+'\n+\n test_expect_success '--continue tries to commit' '\n \tgit checkout to-be-rebased &&\n \ttest_tick &&\n-- \n1.5.5\n"},{"id":"74288","messageId":"1208132469-26471-12-git-send-email-joerg@alea.gnuu.de","threadId":"12825","inReplyTo":"1208132469-26471-11-git-send-email-joerg@alea.gnuu.de","subject":"[PATCH v2 12/13] Teach rebase interactive the tag command","fromName":"Jörg Sommer","fromEmail":"joerg@alea.gnuu.de","sentAt":"2008-04-14T00:21:08Z","receivedAt":"2008-04-14T00:21:08Z","isPatch":true,"sender":{"key":"joerg@alea.gnuu.de","avatar":null},"body":"The intent of the tag command is to (re)set tags for commits in the TODO\nlist. This way it's possible to rebase a commit together with its tag.\n\nSigned-off-by: Jörg Sommer <joerg@alea.gnuu.de>\n---\n git-rebase--interactive.sh    |    7 +++++++\n t/t3404-rebase-interactive.sh |   13 +++++++++++++\n 2 files changed, 20 insertions(+), 0 deletions(-)\n\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex ea67942..c601655 100755\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -323,6 +323,12 @@ do_next () {\n \t\tmark_action_done\n \t\toutput git reset --hard $tmp\n \t\t;;\n+\ttag|t)\n+\t\tcomment_for_reflog tag\n+\n+\t\tmark_action_done\n+\t\toutput git tag -f \"$sha1\"\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@@ -655,6 +661,7 @@ do\n #  reset commit = reset HEAD to the commit\n #  merge commit-M commit-P ... = redo merge commit-M with the\n #         current HEAD and the parents commit-P\n+#  tag = reset tag to the current HEAD\n #\n # If you remove a line here THAT COMMIT WILL BE LOST.\n # However, if you remove everything, the rebase will be aborted.\ndiff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh\nindex 8da7829..9901555 100755\n--- a/t/t3404-rebase-interactive.sh\n+++ b/t/t3404-rebase-interactive.sh\n@@ -91,6 +91,9 @@ for line in $FAKE_LINES; do\n \tmerge*)\n \t\techo \"merge ${line#merge}\" | tr / ' '\n \t\techo \"merge ${line#merge}\" | tr / ' ' >> \"$1\";;\n+\ttag*)\n+\t\techo \"tag ${line#tag}\"\n+\t\techo \"tag ${line#tag}\" >> \"$1\";;\n \t*)\n \t\tsed -n \"${line}{s/^pick/$action/; p;}\" < \"$1\".tmp\n \t\tsed -n \"${line}{s/^pick/$action/; p;}\" < \"$1\".tmp >> \"$1\"\n@@ -306,6 +309,16 @@ test_expect_success 'interactive --first-parent gives a linear list' '\n \ttest \"$head\" = \"$(git rev-parse HEAD)\"\n '\n \n+test_expect_success 'tag sets tags' '\n+\thead=$(git rev-parse HEAD) &&\n+\tFAKE_LINES=\"1 2 3 4 5 tagbb-tag1 6 7 8 9 10 11 12 13 14 15 \\\n+\t\ttagbb-tag2 16 tagbb-tag3a tagbb-tag3b 17 18 19 20 21 22\" \\\n+\t\tEXPECT_COUNT=22 git rebase -i -p master &&\n+\ttest \"$head\" = \"$(git rev-parse HEAD)\" &&\n+\ttest \"$(git rev-parse bb-tag1 bb-tag2 bb-tag3a bb-tag3b)\" = \\\n+\t\t\"$(git rev-parse HEAD^2~2 HEAD~2 HEAD~1 HEAD~1)\"\n+'\n+\n test_expect_success '--continue tries to commit' '\n \tgit checkout to-be-rebased &&\n \ttest_tick &&\n-- \n1.5.5\n"},{"id":"74281","messageId":"1208132469-26471-13-git-send-email-joerg@alea.gnuu.de","threadId":"12825","inReplyTo":"1208132469-26471-12-git-send-email-joerg@alea.gnuu.de","subject":"[PATCH v2 13/13] Add option --preserve-tags","fromName":"Jörg Sommer","fromEmail":"joerg@alea.gnuu.de","sentAt":"2008-04-14T00:21:09Z","receivedAt":"2008-04-14T00:21:09Z","isPatch":true,"sender":{"key":"joerg@alea.gnuu.de","avatar":null},"body":"With this new option tags set on commits, they are part of a rebase, are\nreset to the rebased commits. This way the tags on a branch are kept\nacross rebases.\n\nSigned-off-by: Jörg Sommer <joerg@alea.gnuu.de>\n---\n Documentation/git-rebase.txt  |    6 ++++-\n git-rebase--interactive.sh    |   42 ++++++++++++++++++++++++++++++++++++++--\n t/t3404-rebase-interactive.sh |   10 +++++++++\n 3 files changed, 54 insertions(+), 4 deletions(-)\n\ndiff --git a/Documentation/git-rebase.txt b/Documentation/git-rebase.txt\nindex 9ebbb90..cc4e94f 100644\n--- a/Documentation/git-rebase.txt\n+++ b/Documentation/git-rebase.txt\n@@ -11,7 +11,8 @@ SYNOPSIS\n 'git-rebase' [-i | --interactive] [-v | --verbose] [-m | --merge]\n \t[-s <strategy> | --strategy=<strategy>]\n \t[-C<n>] [ --whitespace=<option>] [-p | --preserve-merges]\n-\t[-f | --first-parent] [--onto <newbase>] <upstream> [<branch>]\n+\t[-f | --first-parent] [-t | --preserve-tags]\n+\t[--onto <newbase>] <upstream> [<branch>]\n 'git-rebase' --continue | --skip | --abort\n \n DESCRIPTION\n@@ -252,6 +253,9 @@ OPTIONS\n \tshowing all commits from the merged branches show only the\n \tcommits and merges following the first parent of each commit.\n \n+-t, \\--preserve-tags::\n+\tIf one of the commits has a tag, reset it to the new commit object.\n+\n include::merge-strategies.txt[]\n \n NOTES\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex c601655..e874c31 100755\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -11,7 +11,7 @@\n # http://article.gmane.org/gmane.comp.version-control.git/22407\n \n USAGE='(--continue | --abort | --skip | [--preserve-merges] [--first-parent]\n-\t[--verbose] [--onto <branch>] <upstream> [<branch>])'\n+\t[--preserve-tags] [--verbose] [--onto <branch>] <upstream> [<branch>])'\n \n OPTIONS_SPEC=\n . git-sh-setup\n@@ -397,9 +397,31 @@ insert_value_at_key_into_list () {\n \n create_extended_todo_list () {\n \t(\n+\tif test t = \"${PRESERVE_TAGS:-}\"\n+\tthen\n+\t\ttag_list=$(git show-ref --abbrev=7 --tags | \\\n+\t\t\t(\n+\t\t\twhile read sha1 tag\n+\t\t\tdo\n+\t\t\t\ttag=${tag#refs/tags/}\n+\t\t\t\tif test ${last_sha1:-0000} = $sha1\n+\t\t\t\tthen\n+\t\t\t\t\tsaved_tags=\"$saved_tags:$tag\"\n+\t\t\t\telse\n+\t\t\t\t\tprintf \"%s\" \"${last_sha1:+ $last_sha1#$saved_tags}\"\n+\t\t\t\t\tlast_sha1=$sha1\n+\t\t\t\t\tsaved_tags=$tag\n+\t\t\t\tfi\n+\t\t\tdone\n+\t\t\techo \"${last_sha1:+ $last_sha1:$saved_tags}\"\n+\t\t\t) )\n+\telse\n+\t\ttag_list=\n+\tfi\n \twhile IFS=_ read commit parents subject\n \tdo\n-\t\tif test \"${last_parent:-$commit}\" != \"$commit\"\n+\t\tif test t = \"$PRESERVE_MERGES\" -a \\\n+\t\t\t\"${last_parent:-$commit}\" != \"$commit\"\n \t\tthen\n \t\t\tif test t = \"${delayed_mark:-f}\"\n \t\t\tthen\n@@ -416,6 +438,14 @@ create_extended_todo_list () {\n \t\tget_value_from_list $commit \"${marked_commits:-}\" \\\n \t\t\t>/dev/null && echo mark\n \n+\t\tif tmp=$(get_value_from_list $commit \"$tag_list\")\n+\t\tthen\n+\t\t\tfor t in $(echo $tmp | tr : ' ')\n+\t\t\tdo\n+\t\t\t\techo tag $t\n+\t\t\tdone\n+\t\tfi\n+\n \t\tcase \"$parents\" in\n \t\t*' '*)\n \t\t\tdelayed_mark=t\n@@ -575,6 +605,9 @@ do\n \t\tFIRST_PARENT=t\n \t\tPRESERVE_MERGES=t\n \t\t;;\n+\t-t|--preserve-tags)\n+\t\tPRESERVE_TAGS=t\n+\t\t;;\n \t-i|--interactive)\n \t\t# yeah, we know\n \t\t;;\n@@ -631,11 +664,14 @@ do\n \t\tSHORTONTO=$(git rev-parse --short=7 $ONTO)\n \t\tcommon_rev_list_opts=\"--abbrev-commit --abbrev=7\n \t\t\t--left-right --cherry-pick $UPSTREAM...$HEAD\"\n-\t\tif test t = \"$PRESERVE_MERGES\" -o t = \"${FIRST_PARENT:-f}\"\n+\t\tif test t = \"$PRESERVE_MERGES\" -o t = \"${FIRST_PARENT:-f}\" \\\n+\t\t\t-o t = \"${PRESERVE_TAGS:-}\"\n \t\tthen\n \t\t\topts=\n \t\t\ttest t = \"${FIRST_PARENT:-f}\" && \\\n \t\t\t\topts=\"$opts --first-parent\"\n+\t\t\ttest t != \"$PRESERVE_MERGES\" && \\\n+\t\t\t\topts=\"$opts --no-merges\"\n \t\t\tgit rev-list --pretty='format:%h_%p_%s' --topo-order \\\n \t\t\t\t$opts $common_rev_list_opts | \\\n \t\t\t\tgrep -v ^commit | \\\ndiff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh\nindex 9901555..d20ed4f 100755\n--- a/t/t3404-rebase-interactive.sh\n+++ b/t/t3404-rebase-interactive.sh\n@@ -319,6 +319,16 @@ test_expect_success 'tag sets tags' '\n \t\t\"$(git rev-parse HEAD^2~2 HEAD~2 HEAD~1 HEAD~1)\"\n '\n \n+test_expect_success 'interactive -t preserves tags' '\n+\tgit rebase -i -p -t --onto dead-end master &&\n+\ttest \"$(git rev-parse bb-tag1 bb-tag2 bb-tag3a bb-tag3b)\" = \\\n+\t\t\"$(git rev-parse HEAD^2~2 HEAD~2 HEAD~1 HEAD~1)\" &&\n+\thead=$(git rev-parse HEAD) &&\n+\tgit rebase -i -t dead-end &&\n+\ttest \"$(git rev-parse bb-tag1 bb-tag2 bb-tag3a bb-tag3b)\" = \\\n+\t\t\"$(git rev-parse HEAD~7 $head~2 HEAD~1 HEAD~1)\"\n+'\n+\n test_expect_success '--continue tries to commit' '\n \tgit checkout to-be-rebased &&\n \ttest_tick &&\n-- \n1.5.5\n"},{"id":"74295","messageId":"905315640804131806j18d5c223w611725a66b0c420c@mail.gmail.com","threadId":"12825","inReplyTo":"7v63umff7r.fsf@gitster.siamese.dyndns.org","subject":"Re: [PATCH/RFC 06/10] Unify the lenght of $SHORT* and the commits in the TODO list","fromName":"Tarmigan","fromEmail":"tarmigan+git@gmail.com","sentAt":"2008-04-14T01:06:03Z","receivedAt":"2008-04-14T01:06:03Z","isPatch":true,"sender":{"key":"tarmigan+git@gmail.com","avatar":null},"body":"On Sat, Apr 12, 2008 at 11:20 PM, Junio C Hamano <gitster@pobox.com> wrote:\n>  \"Equality testing?\" --- that makes me worried.  short=7 does not chomp\n>  them at 7 but only tells rev-parse to use at least 7.  You may get 8 or\n>  more if there are other objects that share the same prefix when you get\n>  them.\n>\n>  Perhaps by forcing \"at least 7\" everywhere you are getting consistent\n>  result that makes them easier to compare.\n>\n>  But considering that this is a candidate for a general mechanism to\n>  eventual grow into the git-sequencer, and that we expect to have richer,\n>  smarter, and/or more complex set of tools that feeds you the TODO list,\n>  I'd feel safer if the internal comparison used to determine which one\n>  commit the user meant in his TODO file is robust and does not rely on\n>  where the abbreviated object name was chomped at.\n\nSlightly offtopic, but has there ever been any discussion about the\nscenario that the during a rebase operation, a new object might be\ncreated that has the same first 7 abbreviation as another \"pick\" that\ncomes later?  It's unlikely, but it might get more likely as rebasing\ngrows in complexity and number of new objects created.\n\nThanks,\nTarmigan\n"},{"id":"74309","messageId":"20080414062425.GB20979@spearce.org","threadId":"12825","inReplyTo":"20080413165011.GB3179@alea.gnuu.de","subject":"Re: [PATCH/RFC 01/10] Teach rebase interactive the mark command","fromName":"Shawn O. Pearce","fromEmail":"spearce@spearce.org","sentAt":"2008-04-14T06:24:25Z","receivedAt":"2008-04-14T06:24:25Z","isPatch":true,"sender":{"key":"spearce@spearce.org","avatar":"https://avatars.githubusercontent.com/u/34844?v=4"},"body":"Jrg Sommer <joerg@alea.gnuu.de> wrote:\n> Shawn O. Pearce schrieb am Sat 12. Apr, 23:56 (-0400):\n> > \n> > Why not use the mark syntax that fast-import uses?\n> \n> I didn't know it.\n> \n> > In fast-import we use \":n\" anytime we need to refer to a mark, e.g.\n> > \":1\" or \":5\".\n> \n> Currently, I don't restrict the mark to be a number. It can anything that\n> is a valid ref. Should I restrict it?\n\nIn fast-import a mark can *only* be a number.  It cannot be a ref\nstring or anything complex like that.  This reduces the memory load\nof fast-import, but does cause a burden on the import frontend.\n \n> And how do you handle the :/ syntax? “reset :/Bla” is than not valid.\n> Mmm, I'll add an exception for :/.\n\nI think the ':/' syntax came along after fast-import had already started\nto use ':' as the mark syntax.  I forgot to object to this bastard form\nof looking up a commit when it was introduced by Dscho and now we have\na SHA-1 expression syntax that fast-import will confuse with a mark.  I\noriginally had chosen to start a mark off with ':' because it is not an\nallowed character in a ref, due to its use to split src:dst in a fetch\nor push refspec.\n \n> Except of this, I prefer to use the colon to be much closer to the syntax\n> of fast-import.\n\nMe too, but it looks like in a human edited \"TODO\" script we may want\nto be more friendly and allow named marks.  Though I'm not sure that is\nreally all that useful.  If you are merging something because it used to\nbe merged before the rebase I doubt we'd generate a meaningful mark name\nwhen the TODO script is initially formatted.\n\n-- \nShawn.\n"},{"id":"74316","messageId":"7v63ulapu6.fsf@gitster.siamese.dyndns.org","threadId":"12825","inReplyTo":"20080414062425.GB20979@spearce.org","subject":"Re: [PATCH/RFC 01/10] Teach rebase interactive the mark command","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2008-04-14T06:54:41Z","receivedAt":"2008-04-14T06:54:41Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"\"Shawn O. Pearce\" <spearce@spearce.org> writes:\n\n>> Except of this, I prefer to use the colon to be much closer to the syntax\n>> of fast-import.\n>\n> Me too, but it looks like in a human edited \"TODO\" script we may want\n> to be more friendly and allow named marks.  Though I'm not sure that is\n> really all that useful.  If you are merging something because it used to\n> be merged before the rebase I doubt we'd generate a meaningful mark name\n> when the TODO script is initially formatted.\n\nI'd say a small integer is the only thing we would need.  The TODO insn\nsequence would be machine generated then manually tweaked, not the other\nway around.\n\nRegarding colon vs pound, I would say that the 'mark' insn can just say\n\"2\" to set the second mark, and then store it in refs/marks/2; the\ncommands that refer to the commit later can use the usual \"refs/marks/2\"\nor \"marks/2\" syntax without colon nor pound nor any other special syntax\nthat way.\n"},{"id":"74345","messageId":"20080414100633.GB15098@alea.gnuu.de","threadId":"12825","inReplyTo":"20080414062425.GB20979@spearce.org","subject":"Re: [PATCH/RFC 01/10] Teach rebase interactive the mark command","fromName":"Jörg Sommer","fromEmail":"joerg@alea.gnuu.de","sentAt":"2008-04-14T10:06:33Z","receivedAt":"2008-04-14T10:06:33Z","isPatch":true,"sender":{"key":"joerg@alea.gnuu.de","avatar":null},"body":"Hi Shawn,\n\nShawn O. Pearce schrieb am Mon 14. Apr, 02:24 (-0400):\n> Jrg Sommer <joerg@alea.gnuu.de> wrote:\n> > Shawn O. Pearce schrieb am Sat 12. Apr, 23:56 (-0400):\n> > > \n> > > Why not use the mark syntax that fast-import uses?\n> > \n> > I didn't know it.\n> > \n> > > In fast-import we use \":n\" anytime we need to refer to a mark, e.g.\n> > > \":1\" or \":5\".\n> > \n> > Currently, I don't restrict the mark to be a number. It can anything that\n> > is a valid ref. Should I restrict it?\n> \n> In fast-import a mark can *only* be a number.\n\nOnly for the record: fast-import uses numbers and not strings of\ndigits, i.e. 001 == 1, and it ignores stuff following digits, i.e.\n\"12a\" == 12 and \"abc\" == 0.\n\n> > Except of this, I prefer to use the colon to be much closer to the syntax\n> > of fast-import.\n> \n> Me too, but it looks like in a human edited \"TODO\" script we may want\n> to be more friendly and allow named marks.\n\nI don't think so. There shouldn't be so much marks that a user can't\nremember them.\n\nThanks for your comments.\n\nJörg.\n-- \nThe UNIX Guru's View of Sex:\n# unzip ; strip ; touch ; finger ; mount ; fsck ; more ; yes ; umount ; sleep\n"},{"id":"74347","messageId":"1208169584-15931-1-git-send-email-joerg@alea.gnuu.de","threadId":"12825","inReplyTo":"1208132469-26471-3-git-send-email-joerg@alea.gnuu.de","subject":"[PATCH v2.1] Teach rebase interactive the mark command","fromName":"Jörg Sommer","fromEmail":"joerg@alea.gnuu.de","sentAt":"2008-04-14T10:39:44Z","receivedAt":"2008-04-14T10:39:44Z","isPatch":true,"sender":{"key":"joerg@alea.gnuu.de","avatar":null},"body":"This new command can be used to set symbolic marks for an commit while\ndoing a rebase. This symbolic name can later be used for merges or\nresets.\n\nThe decision to use references for the marks and not files like done with\nthe rewritten commits for preserve merges was made to ensure no commit\nobjects get lost if prune is started while (a long term) rebase is\nrunning. This also unifies the checking of the validity of marks and\nreferences by using rev-parse for it.\n\nThe format of the marks is as close as possible to the format of the\nmarks used by fast-export and fast-import, i.e. :001 == :1 and\n“:12a” == :12. It differs from the format of fast-import in that point\nthat it requires a digit after the colon, i.e. “:abc” != :0 and “:-12”\nand “:+12” aren't allowed.\n\nSigned-off-by: Jörg Sommer <joerg@alea.gnuu.de>\n---\n git-rebase--interactive.sh    |   35 ++++++++++++++++++++++++++++++++++-\n t/t3404-rebase-interactive.sh |   17 +++++++++++++++++\n 2 files changed, 51 insertions(+), 1 deletions(-)\n\nThe difference to the v2 patch is the definition of the mark as\ndiscussed with \"Shawn O. Pearce\"\n\n>diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\n>index 6ac316a..05d04da 100755\n>--- a/git-rebase--interactive.sh\n>+++ b/git-rebase--interactive.sh\n>@@ -254,10 +254,8 @@ peek_next_command () {\n> \n> mark_to_ref () {\n>        case \"$1\" in\n>-       :[!/]*)\n>-               # :/SOMETHING is a reference for the last commit whose\n>-                # message starts with SOMETHING\n>-               echo \"$mark_prefix${1#:}\"\n>+       :[0-9]*)\n>+               echo \"$mark_prefix$(printf %d ${1#:} 2>/dev/null)\"\n>                ;;\n>        *)\n>                echo \"$1\"\n>\n\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex 531ee94..05d04da 100755\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -35,6 +35,8 @@ mark the corrected paths with 'git add <paths>', and\n run 'git rebase --continue'\"\n export GIT_CHERRY_PICK_HELP\n \n+mark_prefix=refs/rebase-marks/\n+\n warn () {\n \techo \"$*\" >&2\n }\n@@ -105,7 +107,13 @@ die_with_patch () {\n }\n \n cleanup_before_quit () {\n-\trm -rf \"$DOTEST\"\n+\trm -rf \"$DOTEST\" &&\n+\tfor ref in \"$GIT_DIR/$mark_prefix\"*\n+\tdo\n+\t\ttest \"$ref\" = \"$GIT_DIR/$mark_prefix*\" && continue\n+\t\tgit update-ref -d \"${ref#$GIT_DIR/}\" \"${ref#$GIT_DIR/}\" || \\\n+\t\t\treturn 1\n+\tdone\n }\n \n die_abort () {\n@@ -244,6 +252,17 @@ peek_next_command () {\n \tsed -n \"1s/ .*$//p\" < \"$TODO\"\n }\n \n+mark_to_ref () {\n+\tcase \"$1\" in\n+\t:[0-9]*)\n+\t\techo \"$mark_prefix$(printf %d ${1#:} 2>/dev/null)\"\n+\t\t;;\n+\t*)\n+\t\techo \"$1\"\n+\t\t;;\n+\tesac\n+}\n+\n do_next () {\n \trm -f \"$DOTEST\"/message \"$DOTEST\"/author-script \\\n \t\t\"$DOTEST\"/amend || exit\n@@ -321,6 +340,15 @@ do_next () {\n \t\t\tdie_with_patch $sha1 \"\"\n \t\tfi\n \t\t;;\n+\tmark)\n+\t\tmark_action_done\n+\n+\t\tmark=$(mark_to_ref :${sha1#:})\n+\t\tgit rev-parse --verify \"$mark\" > /dev/null 2>&1 && \\\n+\t\t\twarn \"mark $sha1 already exist; overwriting it\"\n+\n+\t\tgit update-ref \"$mark\" HEAD || die \"update-ref failed\"\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@@ -533,10 +561,15 @@ do\n \n # Rebase $SHORTUPSTREAM..$SHORTHEAD onto $SHORTONTO\n #\n+# In the todo insn whenever you need to refer to a commit, in addition\n+# to the usual commit object name, you can use ':mark' syntax to refer\n+# to a commit previously marked with the 'mark' insn.\n+#\n # Commands:\n #  pick = use commit\n #  edit = use commit, but stop for amending\n #  squash = use commit, but meld into previous commit\n+#  mark :mark = mark the current HEAD for later reference\n #\n # If you remove a line here THAT COMMIT WILL BE LOST.\n # However, if you remove everything, the rebase will be aborted.\ndiff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh\nindex 8d29878..fa3560e 100755\n--- a/t/t3404-rebase-interactive.sh\n+++ b/t/t3404-rebase-interactive.sh\n@@ -82,6 +82,9 @@ for line in $FAKE_LINES; do\n \tcase $line in\n \tsquash|edit)\n \t\taction=\"$line\";;\n+\tmark*)\n+\t\techo \"mark ${line#mark}\"\n+\t\techo \"mark ${line#mark}\" >> \"$1\";;\n \t*)\n \t\techo sed -n \"${line}s/^pick/$action/p\"\n \t\tsed -n \"${line}p\" < \"$1\".tmp\n@@ -189,6 +192,20 @@ test_expect_success '-p handles \"no changes\" gracefully' '\n \ttest $HEAD = $(git rev-parse HEAD)\n '\n \n+test_expect_success 'setting marks works' '\n+\tgit checkout master &&\n+\tFAKE_LINES=\"mark:0 2 1 mark:42 3 edit 4\" git rebase -i HEAD~4 &&\n+\tmarks_dir=.git/refs/rebase-marks &&\n+\ttest -d $marks_dir &&\n+\ttest $(ls $marks_dir | wc -l) -eq 2 &&\n+\ttest \"$(git rev-parse HEAD~4)\" = \\\n+\t\t\"$(git rev-parse refs/rebase-marks/0)\" &&\n+\ttest \"$(git rev-parse HEAD~2)\" = \\\n+\t\t\"$(git rev-parse refs/rebase-marks/42)\" &&\n+\tgit rebase --abort &&\n+\tls $marks_dir | wc -l | grep -Fx 0\n+'\n+\n test_expect_success 'preserve merges with -p' '\n \tgit checkout -b to-be-preserved master^ &&\n \t: > unrelated-file &&\n-- \n1.5.5\n"},{"id":"74387","messageId":"20080414232958.GE20979@spearce.org","threadId":"12825","inReplyTo":"1208169584-15931-1-git-send-email-joerg@alea.gnuu.de","subject":"Re: [PATCH v2.1] Teach rebase interactive the mark command","fromName":"Shawn O. Pearce","fromEmail":"spearce@spearce.org","sentAt":"2008-04-14T23:29:58Z","receivedAt":"2008-04-14T23:29:58Z","isPatch":true,"sender":{"key":"spearce@spearce.org","avatar":"https://avatars.githubusercontent.com/u/34844?v=4"},"body":"Jrg Sommer <joerg@alea.gnuu.de> wrote:\n> The format of the marks is as close as possible to the format of the\n> marks used by fast-export and fast-import,\n\nYay.\n\n> i.e. :001 == :1 and\n> “:12a” == :12. It differs from the format of fast-import in that point\n> that it requires a digit after the colon, i.e. “:abc” != :0 and “:-12”\n> and “:+12” aren't allowed.\n\nUh, that's a bug in fast-import.  \":4abc\" is _not_ a mark if you\nread the language specification.  Only \":4\" is a mark.  So we are\naccepting crap and reading it in odd ways.  Not good.\n\n-- \nShawn.\n"},{"id":"74813","messageId":"7v7iescvu7.fsf@gitster.siamese.dyndns.org","threadId":"12825","inReplyTo":"1208132469-26471-2-git-send-email-joerg@alea.gnuu.de","subject":"Re: [PATCH v2 02/13] Don't append default merge message to -m message","fromName":"Junio C Hamano","fromEmail":"junio@pobox.com","sentAt":"2008-04-20T16:52:32Z","receivedAt":"2008-04-20T16:52:32Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jörg Sommer <joerg@alea.gnuu.de> writes:\n\n> From: gitster@pobox.com (Junio C Hamano)\n> Date: Sun, 23 Mar 2008 22:17:09 -0700\n>\n> Signed-off-by: Jörg Sommer <joerg@alea.gnuu.de>\n\nI'd admit that this was taken from my \"You could do this\" patch, and I am\ninclined to think that the users would probably want this behaviour of\ndropping the default merge summary when giving their own message with -m,\nbut I am not absolutely convinced that doing this unconditionally is the\nright thing to do (iow, some people might have relied on the current\nbehaviour).\n\nList, any objections?\n\n> ---\n>  git-merge.sh |   24 +++++++++++++-----------\n>  1 files changed, 13 insertions(+), 11 deletions(-)\n>\n> diff --git a/git-merge.sh b/git-merge.sh\n> index 7dbbb1d..bd9699d 100755\n> --- a/git-merge.sh\n> +++ b/git-merge.sh\n> @@ -250,17 +250,19 @@ else\n>  \t# We are invoked directly as the first-class UI.\n>  \thead_arg=HEAD\n>  \n> -\t# All the rest are the commits being merged; prepare\n> -\t# the standard merge summary message to be appended to\n> -\t# the given message.  If remote is invalid we will die\n> -\t# later in the common codepath so we discard the error\n> -\t# in this loop.\n> -\tmerge_name=$(for remote\n> -\t\tdo\n> -\t\t\tmerge_name \"$remote\"\n> -\t\tdone | git fmt-merge-msg\n> -\t)\n> -\tmerge_msg=\"${merge_msg:+$merge_msg$LF$LF}$merge_name\"\n> +\tif test -z \"$merge_msg\"\n> +\tthen\n> +\t\t# All the rest are the commits being merged; prepare\n> +\t\t# the standard merge summary message to be appended to\n> +\t\t# the given message.  If remote is invalid we will die\n> +\t\t# later in the common codepath so we discard the error\n> +\t\t# in this loop.\n> +\t\tmerge_msg=$(for remote\n> +\t\t\tdo\n> +\t\t\t\tmerge_name \"$remote\"\n> +\t\t\tdone | git fmt-merge-msg\n> +\t\t)\n> +\tfi\n>  fi\n>  head=$(git rev-parse --verify \"$head_arg\"^0) || usage\n>  \n> -- \n> 1.5.5\n"},{"id":"74851","messageId":"20080420234438.GC12865@alea.gnuu.de","threadId":"12825","inReplyTo":"20080414232958.GE20979@spearce.org","subject":"mark parsing in fast-import","fromName":"Jörg Sommer","fromEmail":"joerg@alea.gnuu.de","sentAt":"2008-04-20T23:44:38Z","receivedAt":"2008-04-20T23:44:38Z","isPatch":false,"sender":{"key":"joerg@alea.gnuu.de","avatar":null},"body":"Hallo Shawn,\n\nShawn O. Pearce schrieb am Mon 14. Apr, 19:29 (-0400):\n> Jrg Sommer <joerg@alea.gnuu.de> wrote:\n> > The format of the marks is as close as possible to the format of the\n> > marks used by fast-export and fast-import,\n> \n> Yay.\n> \n> > i.e. :001 == :1 and\n> > “:12a” == :12. It differs from the format of fast-import in that point\n> > that it requires a digit after the colon, i.e. “:abc” != :0 and “:-12”\n> > and “:+12” aren't allowed.\n> \n> Uh, that's a bug in fast-import.  \":4abc\" is _not_ a mark if you\n> read the language specification.  Only \":4\" is a mark.  So we are\n> accepting crap and reading it in odd ways.  Not good.\n\nWhat about this:\n\ndiff --git a/fast-import.c b/fast-import.c\nindex 73e5439..f60e4ab 100644\n--- a/fast-import.c\n+++ b/fast-import.c\n@@ -1690,10 +1690,31 @@ static void skip_optional_lf(void)\n \t\tungetc(term_char, stdin);\n }\n \n+static inline int parse_mark(const const char *str, uintmax_t* mark,\n+\tchar **after_mark)\n+{\n+\tif (!str || str[0] != ':' || !isdigit(str[1]))\n+\t\treturn 1;\n+\n+\tchar *am;\n+\tconst uintmax_t m = strtoumax(&str[1], &am, 10);\n+\tif (errno == 0) {\n+\t\t*mark = m;\n+\t\t*after_mark = am;\n+\t\treturn 0;\n+\t}\n+\treturn 1;\n+}\n+\n static void cmd_mark(void)\n {\n-\tif (!prefixcmp(command_buf.buf, \"mark :\")) {\n-\t\tnext_mark = strtoumax(command_buf.buf + 6, NULL, 10);\n+\tuintmax_t mark = 0;\n+\tchar *after_mark = NULL;\n+\n+\tif (!prefixcmp(command_buf.buf, \"mark \") &&\n+\t\tparse_mark(&command_buf.buf[5], &mark, &after_mark) &&\n+\t\t*after_mark == '\\0') {\n+\t\tnext_mark = mark;\n \t\tread_next_command();\n \t}\n \telse\n@@ -1878,7 +1899,10 @@ static void file_change_m(struct branch *b)\n \n \tif (*p == ':') {\n \t\tchar *x;\n-\t\toe = find_mark(strtoumax(p + 1, &x, 10));\n+\t\tuintmax_t m;\n+\t\tif (parse_mark(p, &m, &x))\n+\t\t\tdie(\"Invalid mark: %s\", p);\n+\t\toe = find_mark(m);\n \t\thashcpy(sha1, oe->sha1);\n \t\tp = x;\n \t} else if (!prefixcmp(p, \"inline\")) {\n@@ -2045,7 +2069,11 @@ static int cmd_from(struct branch *b)\n \t\thashcpy(b->branch_tree.versions[0].sha1, t);\n \t\thashcpy(b->branch_tree.versions[1].sha1, t);\n \t} else if (*from == ':') {\n-\t\tuintmax_t idnum = strtoumax(from + 1, NULL, 10);\n+\t\tchar *after_mark;\n+\t\tuintmax_t idnum;\n+\t\tif (parse_mark(from, &idnum, &after_mark) ||\n+\t\t\t*after_mark != '\\0')\n+\t\t\tdie(\"Not a valid mark: %s\", from);\n \t\tstruct object_entry *oe = find_mark(idnum);\n \t\tif (oe->type != OBJ_COMMIT)\n \t\t\tdie(\"Mark :%\" PRIuMAX \" not a commit\", idnum);\n@@ -2080,7 +2108,11 @@ static struct hash_list *cmd_merge(unsigned int *count)\n \t\tif (s)\n \t\t\thashcpy(n->sha1, s->sha1);\n \t\telse if (*from == ':') {\n-\t\t\tuintmax_t idnum = strtoumax(from + 1, NULL, 10);\n+\t\t\tchar *after_mark;\n+\t\t\tuintmax_t idnum;\n+\t\t\tif (parse_mark(from, &idnum, &after_mark) ||\n+\t\t\t\t*after_mark != '\\0')\n+\t\t\t\tdie(\"Not a valid mark: %s\", from);\n \t\t\tstruct object_entry *oe = find_mark(idnum);\n \t\t\tif (oe->type != OBJ_COMMIT)\n \t\t\t\tdie(\"Mark :%\" PRIuMAX \" not a commit\", idnum);\n@@ -2228,7 +2260,10 @@ static void cmd_new_tag(void)\n \t\thashcpy(sha1, s->sha1);\n \t} else if (*from == ':') {\n \t\tstruct object_entry *oe;\n-\t\tfrom_mark = strtoumax(from + 1, NULL, 10);\n+\t\tchar *after_mark;\n+\t\tif (parse_mark(from, &from_mark, &after_mark) ||\n+\t\t\t*after_mark != '\\0')\n+\t\t\tdie(\"Not a valid mark: %s\", from);\n \t\toe = find_mark(from_mark);\n \t\tif (oe->type != OBJ_COMMIT)\n \t\t\tdie(\"Mark :%\" PRIuMAX \" not a commit\", from_mark);\n@@ -2333,9 +2368,8 @@ static void import_marks(const char *input_file)\n \t\tif (line[0] != ':' || !end)\n \t\t\tdie(\"corrupt mark line: %s\", line);\n \t\t*end = 0;\n-\t\tmark = strtoumax(line + 1, &end, 10);\n-\t\tif (!mark || end == line + 1\n-\t\t\t|| *end != ' ' || get_sha1(end + 1, sha1))\n+\t\tif (parse_mark(line, &mark, &end) || !mark ||\n+\t\t\t*end != ' ' || get_sha1(end + 1, sha1))\n \t\t\tdie(\"corrupt mark line: %s\", line);\n \t\te = find_object(sha1);\n \t\tif (!e) {\n\nBye, Jörg.\n-- \nWer eher stirbt ist länger tot.\n    \t \t    \t       \t\t\t(Un B. Kant)\n"},{"id":"74859","messageId":"20080421001726.GA13639@alea.gnuu.de","threadId":"12825","inReplyTo":"7v7iescvu7.fsf@gitster.siamese.dyndns.org","subject":"Re: [PATCH v2 02/13] Don't append default merge message to -m message","fromName":"Jörg Sommer","fromEmail":"joerg@alea.gnuu.de","sentAt":"2008-04-21T00:17:26Z","receivedAt":"2008-04-21T00:17:26Z","isPatch":true,"sender":{"key":"joerg@alea.gnuu.de","avatar":null},"body":"Hello Junio,\n\nJunio C Hamano schrieb am Sun 20. Apr, 09:52 (-0700):\n> Jörg Sommer <joerg@alea.gnuu.de> writes:\n> \n> > From: gitster@pobox.com (Junio C Hamano)\n> > Date: Sun, 23 Mar 2008 22:17:09 -0700\n> >\n> > Signed-off-by: Jörg Sommer <joerg@alea.gnuu.de>\n> \n> I'd admit that this was taken from my \"You could do this\" patch, and I am\n> inclined to think that the users would probably want this behaviour of\n> dropping the default merge summary when giving their own message with -m,\n> but I am not absolutely convinced that doing this unconditionally is the\n> right thing to do (iow, some people might have relied on the current\n> behaviour).\n> \n> List, any objections?\n\nWhat about a new option -M? But I doubt someone expects this behaviour\nbecause the manpage says:\n\n  The second syntax (<msg> HEAD <remote>) is supported for historical\n  reasons. Do not use it from the command line or in new scripts. It is\n  the same as git merge -m <msg> <remote>.\n      ^^^^              ^^\n\nCurrently, it's not the same, but someone might expect it.\n\nBye, Jörg.\n-- \nDie Erde ist das einzigste Irrenhaus, das von seinen eigenen Insassen\nverwaltet wird.\n                                                (U. Schmidt)\n"},{"id":"74852","messageId":"20080421002626.GJ29771@spearce.org","threadId":"12825","inReplyTo":"20080420234438.GC12865@alea.gnuu.de","subject":"Re: mark parsing in fast-import","fromName":"Shawn O. Pearce","fromEmail":"spearce@spearce.org","sentAt":"2008-04-21T00:26:27Z","receivedAt":"2008-04-21T00:26:27Z","isPatch":false,"sender":{"key":"spearce@spearce.org","avatar":"https://avatars.githubusercontent.com/u/34844?v=4"},"body":"Jrg Sommer <joerg@alea.gnuu.de> wrote:\n> > \n> > Uh, that's a bug in fast-import.  \":4abc\" is _not_ a mark if you\n> > read the language specification.  Only \":4\" is a mark.  So we are\n> > accepting crap and reading it in odd ways.  Not good.\n> \n> What about this:\n> \n> diff --git a/fast-import.c b/fast-import.c\n> index 73e5439..f60e4ab 100644\n> --- a/fast-import.c\n> +++ b/fast-import.c\n> @@ -1690,10 +1690,31 @@ static void skip_optional_lf(void)\n>  \t\tungetc(term_char, stdin);\n>  }\n>  \n> +static inline int parse_mark(const const char *str, uintmax_t* mark,\n> +\tchar **after_mark)\n> +{\n> +\tif (!str || str[0] != ':' || !isdigit(str[1]))\n> +\t\treturn 1;\n> +\n> +\tchar *am;\n\nAlthough we conform to mostly C99 style, variables should be\ndeclared at the top of the scope and not after a statement.\n\n> +\tconst uintmax_t m = strtoumax(&str[1], &am, 10);\n> +\tif (errno == 0) {\n> +\t\t*mark = m;\n> +\t\t*after_mark = am;\n> +\t\treturn 0;\n> +\t}\n> +\treturn 1;\n> +}\n> +\n>  static void cmd_mark(void)\n>  {\n> -\tif (!prefixcmp(command_buf.buf, \"mark :\")) {\n> -\t\tnext_mark = strtoumax(command_buf.buf + 6, NULL, 10);\n> +\tuintmax_t mark = 0;\n> +\tchar *after_mark = NULL;\n> +\n> +\tif (!prefixcmp(command_buf.buf, \"mark \") &&\n> +\t\tparse_mark(&command_buf.buf[5], &mark, &after_mark) &&\n\nHmm.  Shouldn't this be ! parse_mark given that it returns 0\non success and 1 on failure?\n\n\n-- \nShawn.\n"},{"id":"74863","messageId":"20080421084151.GA31344@alea.gnuu.de","threadId":"12825","inReplyTo":"20080421002626.GJ29771@spearce.org","subject":"Re: mark parsing in fast-import","fromName":"Jörg Sommer","fromEmail":"joerg@alea.gnuu.de","sentAt":"2008-04-21T08:41:51Z","receivedAt":"2008-04-21T08:41:51Z","isPatch":false,"sender":{"key":"joerg@alea.gnuu.de","avatar":null},"body":"Hi Shawn,\n\nShawn O. Pearce schrieb am Sun 20. Apr, 20:26 (-0400):\n> Jrg Sommer <joerg@alea.gnuu.de> wrote:\n> > +static inline int parse_mark(const const char *str, uintmax_t* mark,\n\nIs inline okay?\n\n> > +\tchar **after_mark)\n> > +{\n> > +\tif (!str || str[0] != ':' || !isdigit(str[1]))\n> > +\t\treturn 1;\n> > +\n> > +\tchar *am;\n> \n> Although we conform to mostly C99 style, variables should be\n> declared at the top of the scope and not after a statement.\n\nChanged.\n\n> >  static void cmd_mark(void)\n> >  {\n> > -\tif (!prefixcmp(command_buf.buf, \"mark :\")) {\n> > -\t\tnext_mark = strtoumax(command_buf.buf + 6, NULL, 10);\n> > +\tuintmax_t mark = 0;\n> > +\tchar *after_mark = NULL;\n> > +\n> > +\tif (!prefixcmp(command_buf.buf, \"mark \") &&\n> > +\t\tparse_mark(&command_buf.buf[5], &mark, &after_mark) &&\n> \n> Hmm.  Shouldn't this be ! parse_mark given that it returns 0\n> on success and 1 on failure?\n\nYes, you're right. I've checked some other functions and found this\nbehaviour. Can I use a different behabiour, i.e. return 0 on failure and\n!0 on success?\n\nBye, Jörg.\n-- \n„Wer im Usenet gelesen werden will, sollte leserorientiert schreiben. Wer nur\n für sich schreiben will, dem ist mit einem Tagebuch vielleicht besser\n geholfen. Gelesen zu werden ist kein Recht, sondern ein Privileg.“\n     Thore Tams in <90tfv8$49b$1@keks.kruemel.dyndns.org>\n"},{"id":"74890","messageId":"20080421235940.GQ29771@spearce.org","threadId":"12825","inReplyTo":"20080421084151.GA31344@alea.gnuu.de","subject":"Re: mark parsing in fast-import","fromName":"Shawn O. Pearce","fromEmail":"spearce@spearce.org","sentAt":"2008-04-21T23:59:40Z","receivedAt":"2008-04-21T23:59:40Z","isPatch":false,"sender":{"key":"spearce@spearce.org","avatar":"https://avatars.githubusercontent.com/u/34844?v=4"},"body":"Jrg Sommer <joerg@alea.gnuu.de> wrote:\n> Shawn O. Pearce schrieb am Sun 20. Apr, 20:26 (-0400):\n> > Jrg Sommer <joerg@alea.gnuu.de> wrote:\n> > > +static inline int parse_mark(const const char *str, uintmax_t* mark,\n> \n> Is inline okay?\n\nYea, inline is fine.  We use \"static inline\" often in Git when it\nis a good idea.\n \n> > >  static void cmd_mark(void)\n> > >  {\n> > > -\tif (!prefixcmp(command_buf.buf, \"mark :\")) {\n> > > -\t\tnext_mark = strtoumax(command_buf.buf + 6, NULL, 10);\n> > > +\tuintmax_t mark = 0;\n> > > +\tchar *after_mark = NULL;\n> > > +\n> > > +\tif (!prefixcmp(command_buf.buf, \"mark \") &&\n> > > +\t\tparse_mark(&command_buf.buf[5], &mark, &after_mark) &&\n> > \n> > Hmm.  Shouldn't this be ! parse_mark given that it returns 0\n> > on success and 1 on failure?\n> \n> Yes, you're right. I've checked some other functions and found this\n> behaviour. Can I use a different behabiour, i.e. return 0 on failure and\n> !0 on success?\n\nI wasn't objected to the return values as written, but more to the\nfact that it seemed like a logic error to me.  We use both patterns\nin Git.  Perhaps the best example to follow is get_sha1_hex();\nit returns -1 on error and 0 on success.  So a common pattern is\n\"!get_sha1_hex()\" to ensure a successful conversion of a hex string\nto an unsigned char array.\n\n-- \nShawn.\n"},{"id":"74905","messageId":"7vej8y792z.fsf@gitster.siamese.dyndns.org","threadId":"12825","inReplyTo":"20080421001726.GA13639@alea.gnuu.de","subject":"Re: [PATCH v2 02/13] Don't append default merge message to -m message","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2008-04-22T05:27:32Z","receivedAt":"2008-04-22T05:27:32Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jörg Sommer <joerg@alea.gnuu.de> writes:\n\n> ... But I doubt someone expects this behaviour\n> because the manpage says:\n>\n>   The second syntax (<msg> HEAD <remote>) is supported for historical\n>   reasons. Do not use it from the command line or in new scripts. It is\n>   the same as git merge -m <msg> <remote>.\n>       ^^^^              ^^\n>\n> Currently, it's not the same, but someone might expect it.\n\nYeah, the manpage is loosely written and does not reflect the reality.  I\nam _VERY_ tempted to apply your change as-is and see if anybody screams.\nBecause git is designed to be very scriptable, people who want the current\nbehaviour can still call fmt-merge-msg themselves.\n"},{"id":"74906","messageId":"7vabjm78v2.fsf@gitster.siamese.dyndns.org","threadId":"12825","inReplyTo":"1208132469-26471-4-git-send-email-joerg@alea.gnuu.de","subject":"Re: [PATCH v2 04/13] Teach rebase interactive the mark command","fromName":"Junio C Hamano","fromEmail":"junio@pobox.com","sentAt":"2008-04-22T05:32:17Z","receivedAt":"2008-04-22T05:32:17Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jörg Sommer <joerg@alea.gnuu.de> writes:\n\n> This new command can be used to set symbolic marks for an commit while\n> doing a rebase. This symbolic name can later be used for merges or\n> resets.\n>\n> The decision to use references for the marks and not files like done with\n> the rewritten commits for preserve merges was made to ensure no commit\n> objects get lost if prune is started while (a long term) rebase is\n> running. This also unifies the checking of the validity of marks and\n> references by using rev-parse for it.\n>\n> The usage of : as the sign for marks conforms with the tag sign of\n> fast-export and fast-import.\n>\n> Signed-off-by: Jörg Sommer <joerg@alea.gnuu.de>\n> ---\n>  git-rebase--interactive.sh    |   37 ++++++++++++++++++++++++++++++++++++-\n>  t/t3404-rebase-interactive.sh |   17 +++++++++++++++++\n>  2 files changed, 53 insertions(+), 1 deletions(-)\n>\n> diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\n> index 531ee94..6ac316a 100755\n> --- a/git-rebase--interactive.sh\n> +++ b/git-rebase--interactive.sh\n> @@ -35,6 +35,8 @@ mark the corrected paths with 'git add <paths>', and\n>  run 'git rebase --continue'\"\n>  export GIT_CHERRY_PICK_HELP\n>  \n> +mark_prefix=refs/rebase-marks/\n> +\n>  warn () {\n>  \techo \"$*\" >&2\n>  }\n> @@ -105,7 +107,13 @@ die_with_patch () {\n>  }\n>  \n>  cleanup_before_quit () {\n> -\trm -rf \"$DOTEST\"\n> +\trm -rf \"$DOTEST\" &&\n> +\tfor ref in \"$GIT_DIR/$mark_prefix\"*\n> +\tdo\n> +\t\ttest \"$ref\" = \"$GIT_DIR/$mark_prefix*\" && continue\n> +\t\tgit update-ref -d \"${ref#$GIT_DIR/}\" \"${ref#$GIT_DIR/}\" || \\\n> +\t\t\treturn 1\n> +\tdone\n\nIn practice nobody would \"run\" pack-refs during the rebase session, but I\nhave to wonder if it can be triggered to run as part of automated gc or\nsomething, in which case this loop does not work as intended. It needs to\nbe rewritten using for-each-ref.\n\n> @@ -244,6 +252,19 @@ peek_next_command () {\n>  \tsed -n \"1s/ .*$//p\" < \"$TODO\"\n>  }\n>  \n> +mark_to_ref () {\n> +\tcase \"$1\" in\n> +\t:[!/]*)\n> +\t\t# :/SOMETHING is a reference for the last commit whose\n> +                # message starts with SOMETHING\n> +\t\techo \"$mark_prefix${1#:}\"\n> +\t\t;;\n\nWhat was the conclusion of the mark-syntax discussion?\n\nWhile I know the bang in \":[!negated]\" is POSIX, I wonder if everybody's\nshell we care about groks it.\n\nCould people run this with the shell they care about being supported\n(Solaris /bin/sh does not count) try this and yell loudly if you get\n\"matches\" please?  I know bash and dash are Ok, but I do not have easy\naccess to various flabours of BSDs (OSX included).\n\n\tcase \":/foo\" in\n        :[!/]*)\techo matches ;;\n\t*)\techo does not ;;\n\tesac\n"},{"id":"74924","messageId":"7vhcdu1f4w.fsf@gitster.siamese.dyndns.org","threadId":"12825","inReplyTo":"7vabjm78v2.fsf@gitster.siamese.dyndns.org","subject":"Re: [PATCH v2 04/13] Teach rebase interactive the mark command","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2008-04-22T08:13:19Z","receivedAt":"2008-04-22T08:13:19Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Junio C Hamano <junio@pobox.com> writes:\n\n>> +mark_prefix=refs/rebase-marks/\n>> +\n>>  warn () {\n>>  \techo \"$*\" >&2\n>>  }\n>> @@ -105,7 +107,13 @@ die_with_patch () {\n>>  }\n>>  \n>>  cleanup_before_quit () {\n>> -\trm -rf \"$DOTEST\"\n>> +\trm -rf \"$DOTEST\" &&\n>> +\tfor ref in \"$GIT_DIR/$mark_prefix\"*\n>> +\tdo\n>> +\t\ttest \"$ref\" = \"$GIT_DIR/$mark_prefix*\" && continue\n>> +\t\tgit update-ref -d \"${ref#$GIT_DIR/}\" \"${ref#$GIT_DIR/}\" || \\\n>> +\t\t\treturn 1\n>> +\tdone\n>\n> In practice nobody would \"run\" pack-refs during the rebase session, but I\n> have to wonder if it can be triggered to run as part of automated gc or\n> something, in which case this loop does not work as intended. It needs to\n> be rewritten using for-each-ref.\n>\n>> @@ -244,6 +252,19 @@ peek_next_command () {\n>>  \tsed -n \"1s/ .*$//p\" < \"$TODO\"\n>>  }\n>>  \n>> +mark_to_ref () {\n>> +\tcase \"$1\" in\n>> +\t:[!/]*)\n>> +\t\t# :/SOMETHING is a reference for the last commit whose\n>> +                # message starts with SOMETHING\n>> +\t\techo \"$mark_prefix${1#:}\"\n>> +\t\t;;\n>\n> What was the conclusion of the mark-syntax discussion?\n\nEh, sorry, I was commenting on a stale one.  Disregard this part please.\n\nBut the \"$GIT_DIR/$mark_prefix/*\" comment still stands.  I've applied the\nseries as is to 'next' so let's fix them up in-tree as needed.\n"},{"id":"74927","messageId":"alpine.DEB.1.00.0804220949590.4460@eeepc-johanness","threadId":"12825","inReplyTo":"7vabjm78v2.fsf@gitster.siamese.dyndns.org","subject":"Re: [PATCH v2 04/13] Teach rebase interactive the mark command","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2008-04-22T08:52:41Z","receivedAt":"2008-04-22T08:52:41Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Mon, 21 Apr 2008, Junio C Hamano wrote:\n\n> Jörg Sommer <joerg@alea.gnuu.de> writes:\n> \n> > @@ -244,6 +252,19 @@ peek_next_command () {\n> >  \tsed -n \"1s/ .*$//p\" < \"$TODO\"\n> >  }\n> >  \n> > +mark_to_ref () {\n> > +\tcase \"$1\" in\n> > +\t:[!/]*)\n> > +\t\t# :/SOMETHING is a reference for the last commit whose\n> > +                # message starts with SOMETHING\n> > +\t\techo \"$mark_prefix${1#:}\"\n> > +\t\t;;\n> \n> What was the conclusion of the mark-syntax discussion?\n\nWell, I will probably work on something that is not as intrusive and \nsyntax-changing this week.\n\n> While I know the bang in \":[!negated]\" is POSIX, I wonder if everybody's\n> shell we care about groks it.\n\nThe common way to do that in the git sources is\n\n\tswitch \"$x\" in\n\t/*)\n\t\t# do nothing\n\t\t;;\n\t*)\n\t\t<bla>\n\t\t;;\n\tesac\n\nand frankly, I do not see a reason to move away from that practice.  \nEspecially since consistency in source code is better than inconsistency.\n\nCiao,\nDscho"},{"id":"74936","messageId":"20080422093942.GA3752@alea.gnuu.de","threadId":"12825","inReplyTo":"20080421235940.GQ29771@spearce.org","subject":"Re: mark parsing in fast-import","fromName":"Jörg Sommer","fromEmail":"joerg@alea.gnuu.de","sentAt":"2008-04-22T09:39:42Z","receivedAt":"2008-04-22T09:39:42Z","isPatch":false,"sender":{"key":"joerg@alea.gnuu.de","avatar":null},"body":"Hallo Shawn,\n\nShawn O. Pearce schrieb am Mon 21. Apr, 19:59 (-0400):\n> Jrg Sommer <joerg@alea.gnuu.de> wrote:\n> > Yes, you're right. I've checked some other functions and found this\n> > behaviour. Can I use a different behabiour, i.e. return 0 on failure and\n> > !0 on success?\n> \n> I wasn't objected to the return values as written, but more to the\n> fact that it seemed like a logic error to me.  We use both patterns\n> in Git.  Perhaps the best example to follow is get_sha1_hex();\n> it returns -1 on error and 0 on success.  So a common pattern is\n> \"!get_sha1_hex()\" to ensure a successful conversion of a hex string\n> to an unsigned char array.\n\nThanks for this explanation. This was what I was looking for.\n\nAnother question: Is :0 a valid mark? In import_marks() is a check for\n!mark, but I haven't seen it anywhere else.\n\nBye, Jörg.\n-- \nDu hast keine Chance – also nutze sie.\n"},{"id":"74937","messageId":"20080422095549.GB3752@alea.gnuu.de","threadId":"12825","inReplyTo":"7vabjm78v2.fsf@gitster.siamese.dyndns.org","subject":"Re: [PATCH v2 04/13] Teach rebase interactive the mark command","fromName":"Jörg Sommer","fromEmail":"joerg@alea.gnuu.de","sentAt":"2008-04-22T09:55:49Z","receivedAt":"2008-04-22T09:55:49Z","isPatch":true,"sender":{"key":"joerg@alea.gnuu.de","avatar":null},"body":"Hi Junio,\n\nJunio C Hamano schrieb am Mon 21. Apr, 22:32 (-0700):\n> Jörg Sommer <joerg@alea.gnuu.de> writes:\n> \n> >  cleanup_before_quit () {\n> > -\trm -rf \"$DOTEST\"\n> > +\trm -rf \"$DOTEST\" &&\n> > +\tfor ref in \"$GIT_DIR/$mark_prefix\"*\n> > +\tdo\n> > +\t\ttest \"$ref\" = \"$GIT_DIR/$mark_prefix*\" && continue\n> > +\t\tgit update-ref -d \"${ref#$GIT_DIR/}\" \"${ref#$GIT_DIR/}\" || \\\n> > +\t\t\treturn 1\n> > +\tdone\n> \n> In practice nobody would \"run\" pack-refs during the rebase session, but I\n> have to wonder if it can be triggered to run as part of automated gc or\n> something, in which case this loop does not work as intended. It needs to\n> be rewritten using for-each-ref.\n\nWhat do you think about this version:\n\ncleanup_before_quit () {\n\trm -rf \"$DOTEST\" &&\n\tfor ref in $(git for-each-ref --format='%(refname)' ${mark_prefix%/})\n\tdo\n\t\tgit update-ref -d \"$ref\" \"$ref\" || return 1\n\tdone\n}\n\n> > @@ -244,6 +252,19 @@ peek_next_command () {\n> >  \tsed -n \"1s/ .*$//p\" < \"$TODO\"\n> >  }\n> >  \n> > +mark_to_ref () {\n> > +\tcase \"$1\" in\n> > +\t:[!/]*)\n> > +\t\t# :/SOMETHING is a reference for the last commit whose\n> > +                # message starts with SOMETHING\n> > +\t\techo \"$mark_prefix${1#:}\"\n> > +\t\t;;\n> \n> What was the conclusion of the mark-syntax discussion?\n\nUse the same as fast-import and fix fast-import. :)\n\nI've posted a new version\n<1208169584-15931-1-git-send-email-joerg@alea.gnuu.de>\n\nBye, Jörg.\n-- \nNutze die Talente, die du hast. Die Wälder wären sehr still,\nwenn nur die begabtesten Vögel sängen.                (Henry van Dyke)\n"},{"id":"74940","messageId":"alpine.DEB.1.00.0804221127360.4460@eeepc-johanness","threadId":"12825","inReplyTo":"20080422095549.GB3752@alea.gnuu.de","subject":"Re: [PATCH v2 04/13] Teach rebase interactive the mark command","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2008-04-22T10:31:41Z","receivedAt":"2008-04-22T10:31:41Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Tue, 22 Apr 2008, Jörg Sommer wrote:\n\n> Junio C Hamano schrieb am Mon 21. Apr, 22:32 (-0700):\n>\n> > What was the conclusion of the mark-syntax discussion?\n> \n> Use the same as fast-import and fix fast-import. :)\n\nI strongly disagree.\n\nAlso with the conclusion that this was the conclusion.\n\nfast-import is a fundamentally different thing compared to rebase -i.  The \nformer should be very easy to write importers for, and therefore have a \nvery easy syntax from the _technical_ view, the latter should be usable by \npeople, and therefore have a very easy syntax from the _usability_ point \nof view.\n\nSo I really hate the idea of introducing yet other marks when we already \nhave unique identifiers: the (abbreviated) commit names.\n\nI guess the only way to prove that I am not wrong is to do it myself. \nSigh.\n\nCiao,\nDscho\n"},{"id":"74983","messageId":"7vy775ygjm.fsf@gitster.siamese.dyndns.org","threadId":"12825","inReplyTo":"alpine.DEB.1.00.0804221127360.4460@eeepc-johanness","subject":"Re: [PATCH v2 04/13] Teach rebase interactive the mark command","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2008-04-22T16:56:29Z","receivedAt":"2008-04-22T16:56:29Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n\n> So I really hate the idea of introducing yet other marks when we already \n> have unique identifiers: the (abbreviated) commit names.\n\nDidn't I give you an example why commit object names are _not_ unique\nidentifiers already?\n\nI also do not understand why you think 'mark' is ugly.  I _suspect_ that\nthe machinery to read the TODO insns would need to keep a copy of what it\ngave to the end user, compare it with what user edited to make sure the\nuser did not make nonsense insn sequence out of it, which Jörg's code\ndoesn't do (yet), and I suspect a simple rule like \"you cannot move insns\nacross 'mark' boundary\" would be sufficient for that check.\n"},{"id":"74987","messageId":"alpine.DEB.1.00.0804221810180.4460@eeepc-johanness","threadId":"12825","inReplyTo":"7vy775ygjm.fsf@gitster.siamese.dyndns.org","subject":"Re: [PATCH v2 04/13] Teach rebase interactive the mark command","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2008-04-22T17:12:00Z","receivedAt":"2008-04-22T17:12:00Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Tue, 22 Apr 2008, Junio C Hamano wrote:\n\n> Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n> \n> > So I really hate the idea of introducing yet other marks when we already \n> > have unique identifiers: the (abbreviated) commit names.\n> \n> Didn't I give you an example why commit object names are _not_ unique\n> identifiers already?\n\nBy that reasoning, rebase -i cannot work anyway: it relies on the \nabbreviated identifiers, not on anything else, for the \"pick\" command.\n\n> I also do not understand why you think 'mark' is ugly.\n\nIs that not obvious?  You _already_ have identifiers.  And there you add \nother ones.  Only because the original idea of the -p implementation was \nignored.\n\nCiao,\nDscho\n"},{"id":"74997","messageId":"7vlk35ydf0.fsf@gitster.siamese.dyndns.org","threadId":"12825","inReplyTo":"20080422095549.GB3752@alea.gnuu.de","subject":"Re: [PATCH v2 04/13] Teach rebase interactive the mark command","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2008-04-22T18:04:03Z","receivedAt":"2008-04-22T18:04:03Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jörg Sommer <joerg@alea.gnuu.de> writes:\n\n> What do you think about this version:\n>\n> cleanup_before_quit () {\n> \trm -rf \"$DOTEST\" &&\n> \tfor ref in $(git for-each-ref --format='%(refname)' ${mark_prefix%/})\n> \tdo\n> \t\tgit update-ref -d \"$ref\" \"$ref\" || return 1\n> \tdone\n> }\n\nYeah, except you would want to dqquote \"${mark_prefix%/}\" part.\n\nAlso this being a \"clean-up\" phase, I wonder if we want to stop at the\nfirst error (e.g. should unremovable \"$DOTEST\" leave marks behind?  should\nunremovable one mark leave other marks that happen to sort after it\nbehind?).\n"},{"id":"75016","messageId":"20080422231515.GJ29771@spearce.org","threadId":"12825","inReplyTo":"20080422093942.GA3752@alea.gnuu.de","subject":"Re: mark parsing in fast-import","fromName":"Shawn O. Pearce","fromEmail":"spearce@spearce.org","sentAt":"2008-04-22T23:15:15Z","receivedAt":"2008-04-22T23:15:15Z","isPatch":false,"sender":{"key":"spearce@spearce.org","avatar":"https://avatars.githubusercontent.com/u/34844?v=4"},"body":"Jrg Sommer <joerg@alea.gnuu.de> wrote:\n> \n> Another question: Is :0 a valid mark? In import_marks() is a check for\n> !mark, but I haven't seen it anywhere else.\n\nNo, in fast-import \":0\" is _not_ a valid mark.  We burn the first\nentry in the marks table (always leaving it empty) as then we can\nuse the idiom \"!mark\" to say \"no mark was requested/given\" and\n\"mark\" to say \"mark was requested/given\".  Hence we do not need an\nextra flag to tell us either way.\n\nGiven that a mark is just a pointer, and that extra flag would\nlikely have been a global \"static int have_mark\" or some such it\nworks out to be about the same amount of memory - 4 or 8 bytes.\nNo big deal, and the code is probably easier to follow as a result.\n\n-- \nShawn.\n"},{"id":"75176","messageId":"1209114264-10742-1-git-send-email-joerg@alea.gnuu.de","threadId":"12825","inReplyTo":"20080422231515.GJ29771@spearce.org","subject":"[PATCH v2] Make mark parsing much more restrictive","fromName":"Jörg Sommer","fromEmail":"joerg@alea.gnuu.de","sentAt":"2008-04-25T09:04:24Z","receivedAt":"2008-04-25T09:04:24Z","isPatch":true,"sender":{"key":"joerg@alea.gnuu.de","avatar":null},"body":"The current implementation of mark parsing doesn't care for trailing\ngarbage like in :12a and doesn't check for unsigned numbers, i.e. it\naccepts :-12 as a valid mark.\n\nThis patch enforces a number follows the colon and there comes nothing\nafter the bignum.\n\nSigned-off-by: Jörg Sommer <joerg@alea.gnuu.de>\n---\n fast-import.c |   49 ++++++++++++++++++++++++++++++++++++++-----------\n 1 files changed, 38 insertions(+), 11 deletions(-)\n\n\"Shawn O. Pearce\" <spearce@spearce.org> wrote:\n> Jrg Sommer <joerg@alea.gnuu.de> wrote:\n> >\n> > Another question: Is :0 a valid mark? In import_marks() is a check for\n> > !mark, but I haven't seen it anywhere else.\n> \n> No, in fast-import \":0\" is _not_ a valid mark.\n\nThen I propose the following patch.\n\ndiff --git a/fast-import.c b/fast-import.c\nindex 73e5439..0c71da8 100644\n--- a/fast-import.c\n+++ b/fast-import.c\n@@ -1690,12 +1690,31 @@ static void skip_optional_lf(void)\n \t\tungetc(term_char, stdin);\n }\n \n+static inline uintmax_t parse_mark(const const char *str, char **after_mark)\n+{\n+\tchar *am;\n+\tuintmax_t m;\n+\n+\tif (!str || str[0] != ':' || !isdigit(str[1]))\n+\t\treturn 0;\n+\n+\tm = strtoumax(&str[1], &am, 10);\n+\tif (m != UINTMAX_MAX || errno == 0) {\n+\t\t*after_mark = am;\n+\t\treturn m;\n+\t}\n+\treturn 0;\n+}\n+\n static void cmd_mark(void)\n {\n-\tif (!prefixcmp(command_buf.buf, \"mark :\")) {\n-\t\tnext_mark = strtoumax(command_buf.buf + 6, NULL, 10);\n+\tuintmax_t mark;\n+\tchar *after_mark = NULL;\n+\n+\tif (!prefixcmp(command_buf.buf, \"mark \") &&\n+\t\t(next_mark = parse_mark(&command_buf.buf[5], &after_mark)) &&\n+\t\t*after_mark == '\\0')\n \t\tread_next_command();\n-\t}\n \telse\n \t\tnext_mark = 0;\n }\n@@ -1877,8 +1896,8 @@ static void file_change_m(struct branch *b)\n \t}\n \n \tif (*p == ':') {\n-\t\tchar *x;\n-\t\toe = find_mark(strtoumax(p + 1, &x, 10));\n+\t\tchar *x = NULL;\n+\t\toe = find_mark(parse_mark(p, &x));\n \t\thashcpy(sha1, oe->sha1);\n \t\tp = x;\n \t} else if (!prefixcmp(p, \"inline\")) {\n@@ -2045,7 +2064,10 @@ static int cmd_from(struct branch *b)\n \t\thashcpy(b->branch_tree.versions[0].sha1, t);\n \t\thashcpy(b->branch_tree.versions[1].sha1, t);\n \t} else if (*from == ':') {\n-\t\tuintmax_t idnum = strtoumax(from + 1, NULL, 10);\n+\t\tchar *after_mark;\n+\t\tuintmax_t idnum = parse_mark(from, &after_mark);\n+\t\tif (!idnum || *after_mark != '\\0')\n+\t\t\tdie(\"Not a valid mark: %s\", from);\n \t\tstruct object_entry *oe = find_mark(idnum);\n \t\tif (oe->type != OBJ_COMMIT)\n \t\t\tdie(\"Mark :%\" PRIuMAX \" not a commit\", idnum);\n@@ -2080,7 +2102,10 @@ static struct hash_list *cmd_merge(unsigned int *count)\n \t\tif (s)\n \t\t\thashcpy(n->sha1, s->sha1);\n \t\telse if (*from == ':') {\n-\t\t\tuintmax_t idnum = strtoumax(from + 1, NULL, 10);\n+\t\t\tchar *after_mark;\n+\t\t\tuintmax_t idnum = parse_mark(from, &after_mark);\n+\t\t\tif (!idnum || *after_mark != '\\0')\n+\t\t\t\tdie(\"Not a valid mark: %s\", from);\n \t\t\tstruct object_entry *oe = find_mark(idnum);\n \t\t\tif (oe->type != OBJ_COMMIT)\n \t\t\t\tdie(\"Mark :%\" PRIuMAX \" not a commit\", idnum);\n@@ -2228,7 +2253,10 @@ static void cmd_new_tag(void)\n \t\thashcpy(sha1, s->sha1);\n \t} else if (*from == ':') {\n \t\tstruct object_entry *oe;\n-\t\tfrom_mark = strtoumax(from + 1, NULL, 10);\n+\t\tchar *after_mark;\n+\t\tfrom_mark = parse_mark(from, &after_mark);\n+\t\tif (!from_mark || *after_mark != '\\0')\n+\t\t\tdie(\"Not a valid mark: %s\", from);\n \t\toe = find_mark(from_mark);\n \t\tif (oe->type != OBJ_COMMIT)\n \t\t\tdie(\"Mark :%\" PRIuMAX \" not a commit\", from_mark);\n@@ -2333,9 +2361,8 @@ static void import_marks(const char *input_file)\n \t\tif (line[0] != ':' || !end)\n \t\t\tdie(\"corrupt mark line: %s\", line);\n \t\t*end = 0;\n-\t\tmark = strtoumax(line + 1, &end, 10);\n-\t\tif (!mark || end == line + 1\n-\t\t\t|| *end != ' ' || get_sha1(end + 1, sha1))\n+\t\tmark = parse_mark(line, &end);\n+\t\tif (!mark || *end != ' ' || get_sha1(end + 1, sha1))\n \t\t\tdie(\"corrupt mark line: %s\", line);\n \t\te = find_object(sha1);\n \t\tif (!e) {\n-- \n1.5.5.1\n"},{"id":"75177","messageId":"20080425091117.GA23726@alea.gnuu.de","threadId":"12825","inReplyTo":"7vlk35ydf0.fsf@gitster.siamese.dyndns.org","subject":"Re: [PATCH v2 04/13] Teach rebase interactive the mark command","fromName":"Jörg Sommer","fromEmail":"joerg@alea.gnuu.de","sentAt":"2008-04-25T09:11:17Z","receivedAt":"2008-04-25T09:11:17Z","isPatch":true,"sender":{"key":"joerg@alea.gnuu.de","avatar":null},"body":"Hi Junio,\n\nJunio C Hamano schrieb am Tue 22. Apr, 11:04 (-0700):\n> Jörg Sommer <joerg@alea.gnuu.de> writes:\n> \n> > What do you think about this version:\n> >\n> > cleanup_before_quit () {\n> > \trm -rf \"$DOTEST\" &&\n> > \tfor ref in $(git for-each-ref --format='%(refname)' ${mark_prefix%/})\n> > \tdo\n> > \t\tgit update-ref -d \"$ref\" \"$ref\" || return 1\n> > \tdone\n> > }\n> \n> Yeah, except you would want to dqquote \"${mark_prefix%/}\" part.\n\nOh, yes.\n\n> Also this being a \"clean-up\" phase, I wonder if we want to stop at the\n> first error (e.g. should unremovable \"$DOTEST\" leave marks behind?\n\nI think it should be the other way: unremovable marks should leave the\nDOTEST behind. This way a rebase should refuse to start a new session and\nstumble accross the old marks and it's possible to run git rebase --abort\nafter manually removing the marks.\n\nBye, Jörg.\n-- \nDamit das Mögliche entsteht, muß immer wieder das Unmögliche versucht\nwerden.                                       (Hermann Hesse)\n"},{"id":"75179","messageId":"1209116688-12266-1-git-send-email-joerg@alea.gnuu.de","threadId":"12825","inReplyTo":"20080425091117.GA23726@alea.gnuu.de","subject":"[PATCH v2.2] Teach rebase interactive the mark command","fromName":"Jörg Sommer","fromEmail":"joerg@alea.gnuu.de","sentAt":"2008-04-25T09:44:48Z","receivedAt":"2008-04-25T09:44:48Z","isPatch":true,"sender":{"key":"joerg@alea.gnuu.de","avatar":null},"body":"This new command can be used to set symbolic marks for an commit while\ndoing a rebase. This symbolic name can later be used for merges or\nresets.\n\nThe decision to use references for the marks and not files like done with\nthe rewritten commits for preserve merges was made to ensure no commit\nobjects get lost if prune is started while (a long term) rebase is\nrunning. This also unifies the checking of the validity of marks and\nreferences by using rev-parse for it.\n\nThe format of the marks is as close as possible to the format of the\nmarks used by fast-export and fast-import, i.e. :001 == :1 and “:12a” is\nan invalid mark. It differs from the format of fast-import in that point\nthat the colon is not required after the mark command, i.e. “mark 12” is\nthe same as “mark :12”. This should ease the writing of commads.\n\nSigned-off-by: Jörg Sommer <joerg@alea.gnuu.de>\n---\n git-rebase--interactive.sh    |   31 +++++++++++++++++++++++++++++++\n t/t3404-rebase-interactive.sh |   17 +++++++++++++++++\n 2 files changed, 48 insertions(+), 0 deletions(-)\n\nThat's the diff to the last version:\n>diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\n>index eaf5563..1751b08 100755\n>--- a/git-rebase--interactive.sh\n>+++ b/git-rebase--interactive.sh\n>@@ -105,13 +105,11 @@ die_with_patch () {\n> }\n> \n> cleanup_before_quit () {\n>-\trm -rf \"$DOTEST\" &&\n>-\tfor ref in \"$GIT_DIR/$mark_prefix\"*\n>+\tfor ref in $(git for-each-ref --format='%(refname)' \"${mark_prefix%/}\")\n> \tdo\n>-\t\ttest \"$ref\" = \"$GIT_DIR/$mark_prefix*\" && continue\n>-\t\tgit update-ref -d \"${ref#$GIT_DIR/}\" \"${ref#$GIT_DIR/}\" || \\\n>-\t\t\treturn 1\n>+\t\tgit update-ref -d \"$ref\" \"$ref\" || return 1\n> \tdone\n>+\trm -rf \"$DOTEST\"\n> }\n> \n> die_abort () {\n>@@ -194,14 +192,12 @@ peek_next_command () {\n> }\n> \n> mark_to_ref () {\n>-\tcase \"$1\" in\n>-\t:[0-9]*)\n>-\t\techo \"$mark_prefix$(printf %d ${1#:} 2>/dev/null)\"\n>-\t\t;;\n>-\t*)\n>+\tif expr match \"$1\" \"^:[0-9][0-9]*$\" >/dev/null\n>+\tthen\n>+\t\techo \"$mark_prefix$(printf %d ${1#:})\"\n>+\telse\n> \t\techo \"$1\"\n>-\t\t;;\n>-\tesac\n>+\tfi\n> }\n> \n> do_next () {\n>@@ -285,6 +281,8 @@ do_next () {\n> \t\tmark_action_done\n> \n> \t\tmark=$(mark_to_ref :${sha1#:})\n>+\t\ttest :${sha1#:} = \"$mark\" && die \"Invalid mark '$sha1'\"\n>+\n> \t\tgit rev-parse --verify \"$mark\" > /dev/null 2>&1 && \\\n> \t\t\twarn \"mark $sha1 already exist; overwriting it\"\n> \n\n\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex 531ee94..c0abc01 100755\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -35,6 +35,8 @@ mark the corrected paths with 'git add <paths>', and\n run 'git rebase --continue'\"\n export GIT_CHERRY_PICK_HELP\n \n+mark_prefix=refs/rebase-marks/\n+\n warn () {\n \techo \"$*\" >&2\n }\n@@ -105,6 +107,10 @@ die_with_patch () {\n }\n \n cleanup_before_quit () {\n+\tfor ref in $(git for-each-ref --format='%(refname)' \"${mark_prefix%/}\")\n+\tdo\n+\t\tgit update-ref -d \"$ref\" \"$ref\" || return 1\n+\tdone\n \trm -rf \"$DOTEST\"\n }\n \n@@ -244,6 +250,15 @@ peek_next_command () {\n \tsed -n \"1s/ .*$//p\" < \"$TODO\"\n }\n \n+mark_to_ref () {\n+\tif expr match \"$1\" \"^:[0-9][0-9]*$\" >/dev/null\n+\tthen\n+\t\techo \"$mark_prefix$(printf %d ${1#:})\"\n+\telse\n+\t\techo \"$1\"\n+\tfi\n+}\n+\n do_next () {\n \trm -f \"$DOTEST\"/message \"$DOTEST\"/author-script \\\n \t\t\"$DOTEST\"/amend || exit\n@@ -321,6 +336,17 @@ do_next () {\n \t\t\tdie_with_patch $sha1 \"\"\n \t\tfi\n \t\t;;\n+\tmark)\n+\t\tmark_action_done\n+\n+\t\tmark=$(mark_to_ref :${sha1#:})\n+\t\ttest :${sha1#:} = \"$mark\" && die \"Invalid mark '$sha1'\"\n+\n+\t\tgit rev-parse --verify \"$mark\" > /dev/null 2>&1 && \\\n+\t\t\twarn \"mark $sha1 already exist; overwriting it\"\n+\n+\t\tgit update-ref \"$mark\" HEAD || die \"update-ref failed\"\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@@ -533,10 +559,15 @@ do\n \n # Rebase $SHORTUPSTREAM..$SHORTHEAD onto $SHORTONTO\n #\n+# In the todo insn whenever you need to refer to a commit, in addition\n+# to the usual commit object name, you can use ':mark' syntax to refer\n+# to a commit previously marked with the 'mark' insn.\n+#\n # Commands:\n #  pick = use commit\n #  edit = use commit, but stop for amending\n #  squash = use commit, but meld into previous commit\n+#  mark :mark = mark the current HEAD for later reference\n #\n # If you remove a line here THAT COMMIT WILL BE LOST.\n # However, if you remove everything, the rebase will be aborted.\ndiff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh\nindex 8d29878..fa3560e 100755\n--- a/t/t3404-rebase-interactive.sh\n+++ b/t/t3404-rebase-interactive.sh\n@@ -82,6 +82,9 @@ for line in $FAKE_LINES; do\n \tcase $line in\n \tsquash|edit)\n \t\taction=\"$line\";;\n+\tmark*)\n+\t\techo \"mark ${line#mark}\"\n+\t\techo \"mark ${line#mark}\" >> \"$1\";;\n \t*)\n \t\techo sed -n \"${line}s/^pick/$action/p\"\n \t\tsed -n \"${line}p\" < \"$1\".tmp\n@@ -189,6 +192,20 @@ test_expect_success '-p handles \"no changes\" gracefully' '\n \ttest $HEAD = $(git rev-parse HEAD)\n '\n \n+test_expect_success 'setting marks works' '\n+\tgit checkout master &&\n+\tFAKE_LINES=\"mark:0 2 1 mark:42 3 edit 4\" git rebase -i HEAD~4 &&\n+\tmarks_dir=.git/refs/rebase-marks &&\n+\ttest -d $marks_dir &&\n+\ttest $(ls $marks_dir | wc -l) -eq 2 &&\n+\ttest \"$(git rev-parse HEAD~4)\" = \\\n+\t\t\"$(git rev-parse refs/rebase-marks/0)\" &&\n+\ttest \"$(git rev-parse HEAD~2)\" = \\\n+\t\t\"$(git rev-parse refs/rebase-marks/42)\" &&\n+\tgit rebase --abort &&\n+\tls $marks_dir | wc -l | grep -Fx 0\n+'\n+\n test_expect_success 'preserve merges with -p' '\n \tgit checkout -b to-be-preserved master^ &&\n \t: > unrelated-file &&\n-- \n1.5.5.1\n"},{"id":"75262","messageId":"7vej8rj04p.fsf@gitster.siamese.dyndns.org","threadId":"12825","inReplyTo":"1209116688-12266-1-git-send-email-joerg@alea.gnuu.de","subject":"Re: [PATCH v2.2] Teach rebase interactive the mark command","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2008-04-27T06:13:42Z","receivedAt":"2008-04-27T06:13:42Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Thanks; as I already queued the series to 'next', I took the liberty of\napplying the interdiff as a separate fix-up/improvement commit to the tip\nof the topic.\n"},{"id":"75282","messageId":"20080427082840.GA15144@alea.gnuu.de","threadId":"12825","inReplyTo":"7vej8rj04p.fsf@gitster.siamese.dyndns.org","subject":"Re: [PATCH v2.2] Teach rebase interactive the mark command","fromName":"Jörg Sommer","fromEmail":"joerg@alea.gnuu.de","sentAt":"2008-04-27T08:28:40Z","receivedAt":"2008-04-27T08:28:40Z","isPatch":true,"sender":{"key":"joerg@alea.gnuu.de","avatar":null},"body":"Hallo Junio,\n\nJunio C Hamano schrieb am Sat 26. Apr, 23:13 (-0700):\n> Thanks; as I already queued the series to 'next', I took the liberty of\n> applying the interdiff as a separate fix-up/improvement commit to the tip\n> of the topic.\n\nThat's alright.\n\nBye, Jörg.\n-- \nJe planmäßiger ein Mensch vorgeht,\ndesto stärker mag ihn der Zufall treffen.\n\t\t    Erich Krunau ‚Die Physiker‘\n"},{"id":"75479","messageId":"7v3ap5a4ny.fsf@gitster.siamese.dyndns.org","threadId":"12825","inReplyTo":"alpine.DEB.1.00.0804221810180.4460@eeepc-johanness","subject":"Re: [PATCH v2 04/13] Teach rebase interactive the mark command","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2008-04-29T00:25:05Z","receivedAt":"2008-04-29T00:25:05Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n\n> On Tue, 22 Apr 2008, Junio C Hamano wrote:\n>\n>> Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n>> \n>> > So I really hate the idea of introducing yet other marks when we already \n>> > have unique identifiers: the (abbreviated) commit names.\n>> \n>> Didn't I give you an example why commit object names are _not_ unique\n>> identifiers already?\n>\n> By that reasoning, rebase -i cannot work anyway: it relies on the \n> abbreviated identifiers, not on anything else, for the \"pick\" command.\n\nNo, read the message again and think for 5 minutes.\n\nPicking the same commit twice does not make any sense, neither does\npicking the resulting commit from an earlier operation in the same\nsequencer run.  Which means that the commit object name for 'pick' can\nmean _only_ the pre-rewritten commit object, not 'the result of an earlier\noperation that used that commit'.  And you always pick on top of the\ncurrent (detached) HEAD.\n\nReset is different.  You can reset either to the named commit to start\nbuilding from a known state that existed before the sequencer run started,\nor reset to the result of pick (or merge) of the named commit, and your\nproposal breaks down here, because you cannot tell between the two.\n\nTo rebuild this history on top of a commit O' elsewhere:\n\n        O---A---B\n             \\   \\\n              D---E---F---G\n                         / \n                        X\n\nyou would need to:\n\n\tpick A\n        pick B\n        reset <<to the state after \"pick A\">>\n        pick D\n        merge <<the state after \"pick B\">>\n        pick F\n        merge X (taken from somebody else)\n\nand the syntax proposed to express <<the above part>> can either be your\n\"the result of the last operation that used the named commit\", which is\nsimple in some cases, or \"named commit, be it with mark or standard sha-1\nexpression\".\n\nIntroducing a 'mark' insn to mark the previous result you may want to go\nback to is one way to solve this without ambiguity.  Then abbreviated\nobject name won't have to be mapped as in your proposal.\n"},{"id":"75480","messageId":"alpine.DEB.1.00.0804290138170.27457@eeepc-johanness","threadId":"12825","inReplyTo":"7v3ap5a4ny.fsf@gitster.siamese.dyndns.org","subject":"Re: [PATCH v2 04/13] Teach rebase interactive the mark command","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2008-04-29T00:39:51Z","receivedAt":"2008-04-29T00:39:51Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Mon, 28 Apr 2008, Junio C Hamano wrote:\n\n> Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n> \n> > On Tue, 22 Apr 2008, Junio C Hamano wrote:\n> >\n> >> Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n> >> \n> >> > So I really hate the idea of introducing yet other marks when we already \n> >> > have unique identifiers: the (abbreviated) commit names.\n> >> \n> >> Didn't I give you an example why commit object names are _not_ unique \n> >> identifiers already?\n> >\n> > By that reasoning, rebase -i cannot work anyway: it relies on the \n> > abbreviated identifiers, not on anything else, for the \"pick\" command.\n> \n> No, read the message again and think for 5 minutes.\n\npick abcdefg\npick pqrstuv\n\nNow imagine that pqrstuv is a unique commit name _before_ cherry-picking \nabcdefg, but not _after_ it.  Unlikely?  Yes.  Impossible?  No.\n\nCiao,\nDscho\n"},{"id":"75490","messageId":"7vk5ih8ckp.fsf@gitster.siamese.dyndns.org","threadId":"12825","inReplyTo":"alpine.DEB.1.00.0804290138170.27457@eeepc-johanness","subject":"Re: [PATCH v2 04/13] Teach rebase interactive the mark command","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2008-04-29T05:17:10Z","receivedAt":"2008-04-29T05:17:10Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n\n>> No, read the message again and think for 5 minutes.\n>\n> pick abcdefg\n> pick pqrstuv\n>\n> Now imagine that pqrstuv is a unique commit name _before_ cherry-picking \n> abcdefg, but not _after_ it.  Unlikely?  Yes.  Impossible?  No.\n\nNo, I am still being misunderstood.  That is not the uniqueness issue I\nwas talking about.\n\nAs I tried to describe in a message that used a phrase \"the beauty of your\napproach\" (which I suspect you stopped reading after that phrase), your\nrule \"an object name names the commit after the last operation that used\nthe commit, unless it is the first appearance in the sequence, in which\ncase it names the original commit\" works most of the time, but becomes\ncumbersome and unwieldy when the history you try to reproduce becomes more\nelaborate.  And the reason I suggested 'mark' was because I was seeing\nthis in the context of the sequencer, not just \"rebase -i\".\n\nThis is just a minor syntax issue and I am not sure why we got into this\nmisunderstanding, but let's try again.  Suppose you want to recreate this\nhistory on top of a different O'.  For merges, upper parents are earlier\nones:\n\n     A         reset O'\n    / \\        pick  B\n   /   X       reset O'\n  /   / \\      pick A\n O---B   Z     merge B -- recreate X\n  \\   \\ /      reset O'\n   \\   Y       pick C\n    \\ /        merge B? -- recreate Y\n     C         reset B -- go back to recreated X\n               merge B? -- recreate Z\n\nThe above sequence does not work.  As you already used B to create X',\nwhen you want to recreate Y, the last operation used B is now X' and you\ncannot name B' to merge that to C' to produce Y' (and the above sequence\nis wrong in that it attempts to recreate Y' in a wrong order --- we should\nreset to the recreated B and merge recreated C to produce Y', but for that\nyou need to be able to say \"reset to B'\", but you've already used B to\nrecreate X' so you cannot do that).\n\nYou could (because you are intelligent human) reorder things to take\nadvantage of the fact that pick and merge uses the \"current detached HEAD\"\nto avoid refering to B in this particular case, like this:\n\n        reset O'\n        pick A\n        reset O'\n        pick B\t\n        reset O'\n        pick C\n        reset B\t-- go back to recreated B\n        merge C -- recreate Y\n        reset A -- go back to recreated A\n        merge B -- recreate X\n        merge C -- recreate Z\n\nBut I think the only reason you can do this in this case is because B is\nused only twice.  If you have a history where rewritten B itself (not the\nresult of applying/merging the rewritten B) needs to be used more than\ntwice as the second or later merge parent, I do not think you would have a\nway to name that rewritten B for the later uses.\n\nI may be mistaken and you may even be able to prove that there is always a\nway to recreate any shape of history by reordering insns and still using\nyour rule, but the point is that the insn sequence needs to be prepared by\ntools (i.e. frontends for the sequencer), and I do not want to make the\nlife of people who are writing the frontends any harder than necessary.\n\nThe syntax and semantics that uses 'mark' avoids this unwieldiness by\nmaking the rule much simpler.\n\n * Operation operates on the current detached HEAD (as in your rule)\n\n * A commit object name always names _that_ commit object.\n\n * If you need to name an intermediate result, you 'mark' it.\n"},{"id":"75504","messageId":"4816CA72.8070405@viscovery.net","threadId":"12825","inReplyTo":"7vk5ih8ckp.fsf@gitster.siamese.dyndns.org","subject":"Re: [PATCH v2 04/13] Teach rebase interactive the mark command","fromName":"Johannes Sixt","fromEmail":"j.sixt@viscovery.net","sentAt":"2008-04-29T07:12:50Z","receivedAt":"2008-04-29T07:12:50Z","isPatch":true,"sender":{"key":"j6t@kdbg.org","avatar":"https://avatars.githubusercontent.com/u/14810926?v=4"},"body":"Junio C Hamano schrieb:\n> This is just a minor syntax issue and I am not sure why we got into this\n> misunderstanding, but let's try again.  Suppose you want to recreate this\n> history on top of a different O'.  For merges, upper parents are earlier\n> ones:\n> \n>      A         reset O'\n>     / \\        pick  B\n>    /   X       reset O'\n>   /   / \\      pick A\n>  O---B   Z     merge B -- recreate X\n>   \\   \\ /      reset O'\n>    \\   Y       pick C\n>     \\ /        merge B? -- recreate Y\n>      C         reset B -- go back to recreated X\n>                merge B? -- recreate Z\n> \n> The above sequence does not work.\n\nBecause it is hand-crafted. I'd expect rebase to suggest a series that\nworks as long as the user doesn't modify it. Like this:\n\n\treset O'\n\tpick C\n\treset O'\n\tpick B\n\tmerge C -- recreate Y\n\treset O'\n\tpick A\n\tmerge B -- recreate X\n\tmerge Y -- recreate Z\n\nHere all commit names are clearly the original in the first insn that\nreferences it, and the rewritten version in later references. No marks needed.\n\nIf the user modifies the insns, he better knows what he's doing, in\nparticular, when it's necessary to rebuild such complex histories.\n\n-- Hannes\n"},{"id":"75517","messageId":"alpine.DEB.1.00.0804291147450.27457@eeepc-johanness","threadId":"12825","inReplyTo":"4816CA72.8070405@viscovery.net","subject":"Re: [PATCH v2 04/13] Teach rebase interactive the mark command","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2008-04-29T10:52:32Z","receivedAt":"2008-04-29T10:52:32Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Tue, 29 Apr 2008, Johannes Sixt wrote:\n\n> Junio C Hamano schrieb:\n> > This is just a minor syntax issue and I am not sure why we got into \n> > this misunderstanding, but let's try again.  Suppose you want to \n> > recreate this history on top of a different O'.  For merges, upper \n> > parents are earlier ones:\n> > \n> >      A         reset O'\n> >     / \\        pick  B\n> >    /   X       reset O'\n> >   /   / \\      pick A\n> >  O---B   Z     merge B -- recreate X\n> >   \\   \\ /      reset O'\n> >    \\   Y       pick C\n> >     \\ /        merge B? -- recreate Y\n> >      C         reset B -- go back to recreated X\n> >                merge B? -- recreate Z\n> > \n> > The above sequence does not work.\n> \n> Because it is hand-crafted. I'd expect rebase to suggest a series that \n> works as long as the user doesn't modify it. Like this:\n> \n> \treset O'\n> \tpick C\n> \treset O'\n> \tpick B\n> \tmerge C -- recreate Y\n> \treset O'\n> \tpick A\n> \tmerge B -- recreate X\n> \tmerge Y -- recreate Z\n> \n> Here all commit names are clearly the original in the first insn that \n> references it, and the rewritten version in later references. No marks \n> needed.\n> \n> If the user modifies the insns, he better knows what he's doing, in \n> particular, when it's necessary to rebuild such complex histories.\n\nI fully agree.  rebase -i is _not_ about the same goal as git-sequencer.  \nrebase -i is about user interaction.  sequencer is about having a common \nplumbing for the different porcelains.\n\nAnd of course, if you want to play games with rebase -i, you can _always_ \nuse the \"edit\" command (even if you do not plan to edit) to get the commit \nname of the new commit.\n\nAnd you can _always_ use the _full_ commit name to reference the original \ncommit (at least that is how I planned it: the original _short_ name would \nbe replaced by the rewritten commit name, but not the _long_ name).\n\nCiao,\nDscho\n"},{"id":"75579","messageId":"7vk5ig745b.fsf@gitster.siamese.dyndns.org","threadId":"12825","inReplyTo":"alpine.DEB.1.00.0804291147450.27457@eeepc-johanness","subject":"Re: [PATCH v2 04/13] Teach rebase interactive the mark command","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2008-04-29T21:16:48Z","receivedAt":"2008-04-29T21:16:48Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n\n> On Tue, 29 Apr 2008, Johannes Sixt wrote:\n>\n>> Junio C Hamano schrieb:\n>> > This is just a minor syntax issue and I am not sure why we got into \n>> > this misunderstanding, but let's try again.  Suppose you want to \n>> > recreate this history on top of a different O'.  For merges, upper \n>> > parents are earlier ones:\n>> > \n>> >      A         reset O'\n>> >     / \\        pick  B\n>> >    /   X       reset O'\n>> >   /   / \\      pick A\n>> >  O---B   Z     merge B -- recreate X\n>> >   \\   \\ /      reset O'\n>> >    \\   Y       pick C\n>> >     \\ /        merge B? -- recreate Y\n>> >      C         reset B -- go back to recreated X\n>> >                merge B? -- recreate Z\n>> > \n>> > The above sequence does not work.\n>> \n>> Because it is hand-crafted. I'd expect rebase to suggest a series that \n>> works as long as the user doesn't modify it. Like this:\n>> \n>> \treset O'\n>> \tpick C\n>> \treset O'\n>> \tpick B\n>> \tmerge C -- recreate Y\n>> \treset O'\n>> \tpick A\n>> \tmerge B -- recreate X\n>> \tmerge Y -- recreate Z\n>> \n>> Here all commit names are clearly the original in the first insn that \n>> references it, and the rewritten version in later references. No marks \n>> needed.\n>> \n>> If the user modifies the insns, he better knows what he's doing, in \n>> particular, when it's necessary to rebuild such complex histories.\n>\n> I fully agree.  rebase -i is _not_ about the same goal as git-sequencer.  \n> rebase -i is about user interaction.  sequencer is about having a common \n> plumbing for the different porcelains.\n\nThe problem is that both of you stopped reading after the part you quoted.\n"},{"id":"75582","messageId":"alpine.DEB.1.00.0804292220120.13650@eeepc-johanness","threadId":"12825","inReplyTo":"7vk5ig745b.fsf@gitster.siamese.dyndns.org","subject":"Re: [PATCH v2 04/13] Teach rebase interactive the mark command","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2008-04-29T21:25:59Z","receivedAt":"2008-04-29T21:25:59Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Tue, 29 Apr 2008, Junio C Hamano wrote:\n\n> The problem is that both of you stopped reading after the part you \n> quoted.\n\nI did not.  But I assumed that Hannes' example showed that it is always \npossible to reorder the commands such that you there is no problem with \ninterpreting a short commit name as the original commit _until_ that \ncommit is rewritten, and _then_ as the rewritten commit.\n\nIt is a simple matter of the word \"acyclic\" in the term \"DAG\".  It means \nthat whenever you need to refer to a commit, it either comes before or \nafter the commit you need it for, not both directions.\n\nAnd I tried to make clear that I thought deeply about the issue by \nmentioning that you can always use \"edit\" to stop somewhere and mark (even \nby a lightweight tag), should you need to split a commit such that you \nneed to reference both the original and the rewritten commit.\n\nI think the balance to cut here is that of usability.  You can cater for \nthe obscure cases, but that just does not make sense.  With some recipe -- \nas illustrated by Hannes -- it is very easy to see what it does, and as \neasy to modify it, should that be necessary.\n\nThe alternative is obviously easier for the cases that next to nobody will \nneed.\n\nSo no, your argument does not convince me, and I still think that I \nunderstood it correctly from the start.\n\nCiao,\nDscho\n"},{"id":"75601","messageId":"7viqy05mhp.fsf@gitster.siamese.dyndns.org","threadId":"12825","inReplyTo":"alpine.DEB.1.00.0804292220120.13650@eeepc-johanness","subject":"Re: [PATCH v2 04/13] Teach rebase interactive the mark command","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2008-04-29T22:23:30Z","receivedAt":"2008-04-29T22:23:30Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n\n> It is a simple matter of the word \"acyclic\" in the term \"DAG\".  It means \n> that whenever you need to refer to a commit, it either comes before or \n> after the commit you need it for, not both directions.\n\nI fell in the same \"acyclic\" fallacy before I realized it was a mistake,\nespecially after thought about the \"rewritten B needs to be used more than\ntwice as a merge source\" issue.  That's why I earlier said the beauty of\nyour approach is attractive but it \"unfortunately\" breaks down.\n\nFor \"rebase -i\", the tool needs to spit out insns (and again I'd prefer\nnot to require the tools to be clever to be able to write them out), and\nthe generated sequence needs to be easily understood by the end user who\nneeds to be able to edit (e.g. drop lines, reorder them, s/pick/edit/) and\neasily visualize what the resulting shape of the history would be.  If we\nlimit ourselves to the context of a non-merge-preserving \"rebase -i\", the\ninsns will not need 'mark' (nor 'merge') and the resulting todo file would\nlook identical in both approaches.\n\nBut we also would want to have a sequencer generic enough to be capable of\nfaithfully reproducing a history with merges.\n"},{"id":"75605","messageId":"alpine.DEB.1.00.0804292355060.17469@eeepc-johanness","threadId":"12825","inReplyTo":"7viqy05mhp.fsf@gitster.siamese.dyndns.org","subject":"Re: [PATCH v2 04/13] Teach rebase interactive the mark command","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2008-04-29T22:55:49Z","receivedAt":"2008-04-29T22:55:49Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"hi,\n\nOn Tue, 29 Apr 2008, Junio C Hamano wrote:\n\n> Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n> \n> > It is a simple matter of the word \"acyclic\" in the term \"DAG\".  It means \n> > that whenever you need to refer to a commit, it either comes before or \n> > after the commit you need it for, not both directions.\n> \n> I fell in the same \"acyclic\" fallacy before I realized it was a mistake, \n> especially after thought about the \"rewritten B needs to be used more \n> than twice as a merge source\" issue.  That's why I earlier said the \n> beauty of your approach is attractive but it \"unfortunately\" breaks \n> down.\n\nI do not understand.  The topological order assures that you have \nrewritten every commit that needs to be rewritten before rewriting the \ncurrent commit.\n\nPuzzled,\nDscho\n"},{"id":"75608","messageId":"7v63u05khw.fsf@gitster.siamese.dyndns.org","threadId":"12825","inReplyTo":"alpine.DEB.1.00.0804292355060.17469@eeepc-johanness","subject":"Re: [PATCH v2 04/13] Teach rebase interactive the mark command","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2008-04-29T23:06:35Z","receivedAt":"2008-04-29T23:06:35Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n\n> On Tue, 29 Apr 2008, Junio C Hamano wrote:\n>\n>> Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n>> \n>> > It is a simple matter of the word \"acyclic\" in the term \"DAG\".  It means \n>> > that whenever you need to refer to a commit, it either comes before or \n>> > after the commit you need it for, not both directions.\n>> \n>> I fell in the same \"acyclic\" fallacy before I realized it was a mistake, \n>> especially after thought about the \"rewritten B needs to be used more \n>> than twice as a merge source\" issue.  That's why I earlier said the \n>> beauty of your approach is attractive but it \"unfortunately\" breaks \n>> down.\n>\n> I do not understand.  The topological order assures that you have \n> rewritten every commit that needs to be rewritten before rewriting the \n> current commit.\n\nPerhaps it would help to go back to the message J6t incompletely quoted,\nand try the example with the parent order of Y swapped (i.e. B == Y^2, C\n== Y^1)\n\nRecreating X and Y both need to refer to the rewritten B as the parameter\nto \"merge\" insn.  You create X first then you cannot refer to B anymore to\nrecreate Y.  The other way around you cannot name B to recreate X.\n"},{"id":"75613","messageId":"alpine.DEB.1.00.0804300016130.17469@eeepc-johanness","threadId":"12825","inReplyTo":"7v63u05khw.fsf@gitster.siamese.dyndns.org","subject":"Re: [PATCH v2 04/13] Teach rebase interactive the mark command","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2008-04-29T23:31:17Z","receivedAt":"2008-04-29T23:31:17Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Tue, 29 Apr 2008, Junio C Hamano wrote:\n\n> Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n> \n> > On Tue, 29 Apr 2008, Junio C Hamano wrote:\n> >\n> >> Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n> >> \n> >> > It is a simple matter of the word \"acyclic\" in the term \"DAG\".  It \n> >> > means that whenever you need to refer to a commit, it either comes \n> >> > before or after the commit you need it for, not both directions.\n> >> \n> >> I fell in the same \"acyclic\" fallacy before I realized it was a \n> >> mistake, especially after thought about the \"rewritten B needs to be \n> >> used more than twice as a merge source\" issue.  That's why I earlier \n> >> said the beauty of your approach is attractive but it \"unfortunately\" \n> >> breaks down.\n> >\n> > I do not understand.  The topological order assures that you have \n> > rewritten every commit that needs to be rewritten before rewriting the \n> > current commit.\n> \n> Perhaps it would help to go back to the message J6t incompletely quoted, \n> and try the example with the parent order of Y swapped (i.e. B == Y^2, C \n> == Y^1)\n> \n> Recreating X and Y both need to refer to the rewritten B as the \n> parameter to \"merge\" insn.  You create X first then you cannot refer to \n> B anymore to recreate Y.  The other way around you cannot name B to \n> recreate X.\n\nIf you refer to \"B\" as the \"short name of the original commit which refers \nto the rewritten commit as soon as B was rewritten\", then I really do not \nsee the problem.\n\nEvery commit has 0..n parents.  These are properly identified before \nrebasing.  Some of them have to be rewritten, because they are rebased.\n\nSo if you order the commits topologically, so that ancestors come first, \nyou will have to jump around a bit with the \"reset\" command, but you can \nbasically make sure that all parents that needed rewriting were \nrewritten already before rewriting that commit.\n\nNow, if you want to split a commit, you may want to refer to the original \ncommit instead of an already rewritten commit, but I think that this \noccasion is rare enough, that we can ask the user to tag that commit, and \nrefer to that commit by its tag in the todo list.\n\nOr you write down the original's long name and use that one.\n\nBut if you use the _default_ todo list, i.e. you want to rebase preserving \nmerges without interfering manually with the process, what I said about \nthe topological ordering still holds true.\n\nAt no point will you need to refer _both_ to the original _and_ to the \nrewritten commit name.\n\nCome to think of it, I cannot think of a (default) case where the \n_original_ name of a to-be-rewritten commit has to be referred to, except \nfor the \"pick\" command.\n\nCiao,\nDscho\n"},{"id":"75621","messageId":"7v1w4o3zle.fsf@gitster.siamese.dyndns.org","threadId":"12825","inReplyTo":"alpine.DEB.1.00.0804300016130.17469@eeepc-johanness","subject":"Re: [PATCH v2 04/13] Teach rebase interactive the mark command","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2008-04-30T01:23:25Z","receivedAt":"2008-04-30T01:23:25Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n\n> On Tue, 29 Apr 2008, Junio C Hamano wrote:\n>> Perhaps it would help to go back to the message J6t incompletely quoted, \n>> and try the example with the parent order of Y swapped (i.e. B == Y^2, C \n>> == Y^1)\n>> \n>> Recreating X and Y both need to refer to the rewritten B as the \n>> parameter to \"merge\" insn.  You create X first then you cannot refer to \n>> B anymore to recreate Y.  The other way around you cannot name B to \n>> recreate X.\n>\n> If you refer to \"B\" as the \"short name of the original commit which refers \n> to the rewritten commit as soon as B was rewritten\", then I really do not \n> see the problem.\n\nHmmm.  Perhaps you are thinking about using not just A, B, C but also\nnames like X, Y, and Z in the insn sequence?  I was operating under the\nimpression that you used only single parent commits to name things, and a\nname will stand for the result of the last operation that used the name\n(e.g. after \"pick B\", B names the result of cherry-picking the original B\nto detached HEAD).\n\n\n                 A\n                / \\\n               /   X\n              /   / \\\n             O---B   Z\n              \\   \\ /\n               \\   Y\n                \\ /\n                 C\n\n            X = checkout A, merge B\n            Y = checkout C, merge B\n            Z = checkout X, merge Y\n\nI start from Q, create A', B' and C' with:\n\n\treset Q\n\tpick A\n        reset Q\n        pick B\n        reset Q\n        pick C\n\nThen I can recreate X by doing\n\n\treset A\n        merge B\n\nThe problem I had was to figure out the way to go back to \"rewritten X\".\nI assumed you would say \"B\" because that is the last insn in the sequence\nthat used that name.\n\nBut instead you are thinking of letting me just say \"X\", and somehow make\nthe machinery guess by noticing \"Ah, original X is a merge between\noriginal A and B, and we have a merge between rewritten A and rewritten B,\nso we will treat that merge as rewritten \"X\"?\n\nI actually was hoping we could avoid that, which feels messy.\n\nBut now I may be misunderstanding what you meant to say.\n"},{"id":"75642","messageId":"481810C9.3030409@viscovery.net","threadId":"12825","inReplyTo":"7v1w4o3zle.fsf@gitster.siamese.dyndns.org","subject":"Re: [PATCH v2 04/13] Teach rebase interactive the mark command","fromName":"Johannes Sixt","fromEmail":"j.sixt@viscovery.net","sentAt":"2008-04-30T06:25:13Z","receivedAt":"2008-04-30T06:25:13Z","isPatch":true,"sender":{"key":"j6t@kdbg.org","avatar":"https://avatars.githubusercontent.com/u/14810926?v=4"},"body":"Junio C Hamano schrieb:\n> Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n> \n>> On Tue, 29 Apr 2008, Junio C Hamano wrote:\n>>> Perhaps it would help to go back to the message J6t incompletely quoted, \n>>> and try the example with the parent order of Y swapped (i.e. B == Y^2, C \n>>> == Y^1)\n>>>\n>>> Recreating X and Y both need to refer to the rewritten B as the \n>>> parameter to \"merge\" insn.  You create X first then you cannot refer to \n>>> B anymore to recreate Y.  The other way around you cannot name B to \n>>> recreate X.\n>> If you refer to \"B\" as the \"short name of the original commit which refers \n>> to the rewritten commit as soon as B was rewritten\", then I really do not \n>> see the problem.\n> \n> Hmmm.  Perhaps you are thinking about using not just A, B, C but also\n> names like X, Y, and Z in the insn sequence?  I was operating under the\n> impression that you used only single parent commits to name things, and a\n> name will stand for the result of the last operation that used the name\n> (e.g. after \"pick B\", B names the result of cherry-picking the original B\n> to detached HEAD).\n> \n> \n>                  A\n>                 / \\\n>                /   X\n>               /   / \\\n>              O---B   Z\n>               \\   \\ /\n>                \\   Y\n>                 \\ /\n>                  C\n> \n>             X = checkout A, merge B\n>             Y = checkout C, merge B\n>             Z = checkout X, merge Y\n> \n> I start from Q, create A', B' and C' with:\n> \n> \treset Q\n> \tpick A\n>         reset Q\n>         pick B\n>         reset Q\n>         pick C\n> \n> Then I can recreate X by doing\n> \n> \treset A\n>         merge B\n> \n> The problem I had was to figure out the way to go back to \"rewritten X\".\n> I assumed you would say \"B\" because that is the last insn in the sequence\n> that used that name.\n> \n> But instead you are thinking of letting me just say \"X\", and somehow make\n> the machinery guess by noticing \"Ah, original X is a merge between\n> original A and B, and we have a merge between rewritten A and rewritten B,\n> so we will treat that merge as rewritten \"X\"?\n\nYou had used this notion in your post:\n\n\tmerge B -- recreate X\n\nDid you mean the '-- recreate X' part as just a comment? I understood it\nas part of the instruction, namely to say that the result of the merge is\nthe rewritten X. In this case you can refer to X in subsequent insns\nunambiguously (keep in mind that it is actually the abbreviated SHA1 of\nthe original merge commit).\n\n-- Hannes\n"},{"id":"75645","messageId":"7vlk2v3jia.fsf@gitster.siamese.dyndns.org","threadId":"12825","inReplyTo":"481810C9.3030409@viscovery.net","subject":"Re: [PATCH v2 04/13] Teach rebase interactive the mark command","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2008-04-30T07:10:53Z","receivedAt":"2008-04-30T07:10:53Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Sixt <j.sixt@viscovery.net> writes:\n\n>> The problem I had was to figure out the way to go back to \"rewritten X\".\n>> I assumed you would say \"B\" because that is the last insn in the sequence\n>> that used that name.\n>> \n>> But instead you are thinking of letting me just say \"X\", and somehow make\n>> the machinery guess by noticing \"Ah, original X is a merge between\n>> original A and B, and we have a merge between rewritten A and rewritten B,\n>> so we will treat that merge as rewritten \"X\"?\n>\n> You had used this notion in your post:\n>\n> \tmerge B -- recreate X\n>\n> Did you mean the '-- recreate X' part as just a comment?\n\nPurely as a comment to let the readers know what I was describing.\n"},{"id":"75654","messageId":"alpine.DEB.1.00.0804300938190.17469@eeepc-johanness","threadId":"12825","inReplyTo":"7v1w4o3zle.fsf@gitster.siamese.dyndns.org","subject":"Re: [PATCH v2 04/13] Teach rebase interactive the mark command","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2008-04-30T08:47:02Z","receivedAt":"2008-04-30T08:47:02Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Tue, 29 Apr 2008, Junio C Hamano wrote:\n\n> \n>                  A\n>                 / \\\n>                /   X\n>               /   / \\\n>              O---B   Z\n>               \\   \\ /\n>                \\   Y\n>                 \\ /\n>                  C\n> \n>             X = checkout A, merge B\n>             Y = checkout C, merge B\n>             Z = checkout X, merge Y\n> \n> I start from Q, create A', B' and C' with:\n> \n> \treset Q\n> \tpick A\n>         reset Q\n>         pick B\n>         reset Q\n>         pick C\n> \n> Then I can recreate X by doing\n> \n> \treset A\n>         merge B\n> \n> The problem I had was to figure out the way to go back to \"rewritten X\". \n> I assumed you would say \"B\" because that is the last insn in the \n> sequence that used that name.\n> \n> But instead you are thinking of letting me just say \"X\", and somehow \n> make the machinery guess by noticing \"Ah, original X is a merge between \n> original A and B, and we have a merge between rewritten A and rewritten \n> B, so we will treat that merge as rewritten \"X\"?\n> \n> I actually was hoping we could avoid that, which feels messy.\n\nI cannot bring myself to feel that this is messy.  The more I think about \nit, the clearer it becomes for me that the pick call should use the \noriginal commit, whereas the merge call should use the rewritten commit \n(and should therefore only be called when all ancestors of that merge \nwhich need rebasing were rebased already).\n\nBTW I think that I made a stupid mistake in one of my previous mails: when \nI wrote an example for the \"merge\" command (as I would like it), I did \n_not_ list the original commit name of that merge.  I.e.\n\n\tmerge <parent2> <parent3>... <message>\n\nI completely forgot that for the $DOTEST/rewritten/ to work, the original \ncommit name of that merge has to be listed.\n\nBut this got me thinking, and I think that to leave out the first parent \nwas another mistake I made, so I really would like to have this syntax:\n\n\tmerge <orig-commit> <parent1> <parent2>... <message>\n\nThis would allow to change the parents in the interactive rebase, and if \n<parent1> is not the current commit at that point, it would implicitly \ncall \"reset\".\n\nWhat appeals to me is the simplicity of this approach: you refer to the \ncommits by calling them by their (original) name.\n\nIn the (probably really rare) occasion that you really need to refer to an \noriginal _and_ a rewritten commit, you can always use _any_ commit-ish as \nargument to the command.\n\nCiao,\nDscho\n"},{"id":"75659","messageId":"7vr6cn1yzk.fsf@gitster.siamese.dyndns.org","threadId":"12825","inReplyTo":"alpine.DEB.1.00.0804300938190.17469@eeepc-johanness","subject":"Re: [PATCH v2 04/13] Teach rebase interactive the mark command","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2008-04-30T09:19:27Z","receivedAt":"2008-04-30T09:19:27Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n\n>> But instead you are thinking of letting me just say \"X\", and somehow \n>> make the machinery guess by noticing \"Ah, original X is a merge between \n>> original A and B, and we have a merge between rewritten A and rewritten \n>> B, so we will treat that merge as rewritten \"X\"?\n>> \n>> I actually was hoping we could avoid that, which feels messy.\n> ...\n> But this got me thinking, and I think that to leave out the first parent \n> was another mistake I made, so I really would like to have this syntax:\n>\n> \tmerge <orig-commit> <parent1> <parent2>... <message>\n>\n> This would allow to change the parents in the interactive rebase, and if \n> <parent1> is not the current commit at that point, it would implicitly \n> call \"reset\".\n>\n> What appeals to me is the simplicity of this approach: you refer to the \n> commits by calling them by their (original) name.\n\nOk, that clears my confusion, but it raises another issue.\n\nIn the context of \"rebase -i\", this may not be a problem, but by forcing\nus to name commits always with original commits, we cannot build (instead\nof rebuild) a history that does not yet exist using the sequencer\nmachinery, can we?\n\nIf we want to transplant \"^C ^N O\" in this history elsewhere:\n\n      --o---C---N\n               / \n          B---M\n         /   /\n        O---A\n\nwhile inserting a new fix-up commit F on top of B before we merge that\nside branch to rewritten A:\n\n              --o---C---N'\n                       / \n              B'--X---M'\n             /       /\n        O---Q-------A'\n\nWould/Should the machinery somehow figure out that the merge between the\nrewritten A (which is A') and an inserted commit X (which is made on top\nof the rewritten B) corresponds to M in the original history?\n\nThis is not a made up example, but something I have to do once (on my\nnon-git days) or many more times (on my git days) every day when\nrebuilding 'pu' on top of updated 'next' using updated tips of topic\nbranches.  I was hoping that the sequencer mechanism can help me\nautomating the process a bit more.\n"},{"id":"75665","messageId":"48184A0E.3050704@viscovery.net","threadId":"12825","inReplyTo":"7vr6cn1yzk.fsf@gitster.siamese.dyndns.org","subject":"Re: [PATCH v2 04/13] Teach rebase interactive the mark command","fromName":"Johannes Sixt","fromEmail":"j.sixt@viscovery.net","sentAt":"2008-04-30T10:29:34Z","receivedAt":"2008-04-30T10:29:34Z","isPatch":true,"sender":{"key":"j6t@kdbg.org","avatar":"https://avatars.githubusercontent.com/u/14810926?v=4"},"body":"Junio C Hamano schrieb:\n> In the context of \"rebase -i\", this may not be a problem, but by forcing\n> us to name commits always with original commits, we cannot build (instead\n> of rebuild) a history that does not yet exist using the sequencer\n> machinery, can we?\n> \n> If we want to transplant \"^C ^N O\" in this history elsewhere:\n> \n>       --o---C---N\n>                / \n>           B---M\n>          /   /\n>         O---A\n> \n> while inserting a new fix-up commit F on top of B before we merge that\n> side branch to rewritten A:\n> \n>               --o---C---N'\n>                        / \n>               B'--X---M'\n>              /       /\n>         O---Q-------A'\n> \n> Would/Should the machinery somehow figure out that the merge between the\n> rewritten A (which is A') and an inserted commit X (which is made on top\n> of the rewritten B) corresponds to M in the original history?\n\nNo. The 'merge' insn tells the original merge commit. So, rebase would\nsuggest this todo list:\n\n\tpick B\n\treset Q\n\tpick A\n\tmerge M A B\n\tmerge N M C\n\nand you would have to change it to\n\n\tpick B\n\tpick X       <--\n\treset Q\n\tpick A\n\tmerge M A X  <--\n\tmerge N M C\n\nBut you could just as well do this:\n\n\tedit B       <--\n\treset Q\n\tpick A\n\tmerge M A B\n\tmerge N M C\n\nWhen the 'edit B' stops, HEAD is at B'. Now you git-am X, then 'rebase\n--continue'. Since now HEAD is at X, X is recorded as the rewritten\nversion of B, and the 'merge M A B' would pick X as the second parent.\n\n-- Hannes\n"},{"id":"75672","messageId":"alpine.DEB.1.00.0804301253520.2136@eeepc-johanness","threadId":"12825","inReplyTo":"7vr6cn1yzk.fsf@gitster.siamese.dyndns.org","subject":"Re: [PATCH v2 04/13] Teach rebase interactive the mark command","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2008-04-30T11:56:44Z","receivedAt":"2008-04-30T11:56:44Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Wed, 30 Apr 2008, Junio C Hamano wrote:\n\n> Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n> \n> >> But instead you are thinking of letting me just say \"X\", and somehow \n> >> make the machinery guess by noticing \"Ah, original X is a merge between \n> >> original A and B, and we have a merge between rewritten A and rewritten \n> >> B, so we will treat that merge as rewritten \"X\"?\n> >> \n> >> I actually was hoping we could avoid that, which feels messy.\n> > ...\n> > But this got me thinking, and I think that to leave out the first parent \n> > was another mistake I made, so I really would like to have this syntax:\n> >\n> > \tmerge <orig-commit> <parent1> <parent2>... <message>\n> >\n> > This would allow to change the parents in the interactive rebase, and if \n> > <parent1> is not the current commit at that point, it would implicitly \n> > call \"reset\".\n> >\n> > What appeals to me is the simplicity of this approach: you refer to the \n> > commits by calling them by their (original) name.\n> \n> Ok, that clears my confusion, but it raises another issue.\n> \n> In the context of \"rebase -i\", this may not be a problem, but by forcing\n> us to name commits always with original commits, we cannot build (instead\n> of rebuild) a history that does not yet exist using the sequencer\n> machinery, can we?\n\nThe idea I hinted at was to refer to them by another name than the short \nname.  Then we can use the sequencer machinery.\n\nI still maintain that it is such a rare need (even if you are a power user \nof it) that it makes sense to cater for other, simpler uses.\n\nCiao,\nDscho\n"},{"id":"75678","messageId":"20080430130653.GD6160@dpotapov.dyndns.org","threadId":"12825","inReplyTo":"alpine.DEB.1.00.0804300938190.17469@eeepc-johanness","subject":"Re: [PATCH v2 04/13] Teach rebase interactive the mark command","fromName":"Dmitry Potapov","fromEmail":"dpotapov@gmail.com","sentAt":"2008-04-30T13:06:53Z","receivedAt":"2008-04-30T13:06:53Z","isPatch":true,"sender":{"key":"dpotapov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/6568595?v=4"},"body":"On Wed, Apr 30, 2008 at 09:47:02AM +0100, Johannes Schindelin wrote:\n> \n> I cannot bring myself to feel that this is messy.  The more I think about \n> it, the clearer it becomes for me that the pick call should use the \n> original commit, whereas the merge call should use the rewritten commit \n> (and should therefore only be called when all ancestors of that merge \n> which need rebasing were rebased already).\n>\n\nMaybe, it would be better if re-written commits were marked a bit\ndifferently, so there will be no confusion about whether an original\nor re-written commit is referred. For instance, re-written commits can\nbe marked by adding apostrophe at the end, so if the original commit\nwas \"abcdef\" then the re-written should be called as \"abcdef'\". At\nleast, it will make plain clear for anyone where in merge rewritten\ncommits are mentioned. Otherwise, it looks too magical to me.\n\nDmitry\n"},{"id":"75751","messageId":"alpine.DEB.1.00.0805011355540.5247@eeepc-johanness","threadId":"12825","inReplyTo":"20080430130653.GD6160@dpotapov.dyndns.org","subject":"Re: [PATCH v2 04/13] Teach rebase interactive the mark command","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2008-05-01T12:59:40Z","receivedAt":"2008-05-01T12:59:40Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Wed, 30 Apr 2008, Dmitry Potapov wrote:\n\n> On Wed, Apr 30, 2008 at 09:47:02AM +0100, Johannes Schindelin wrote:\n> > \n> > I cannot bring myself to feel that this is messy.  The more I think about \n> > it, the clearer it becomes for me that the pick call should use the \n> > original commit, whereas the merge call should use the rewritten commit \n> > (and should therefore only be called when all ancestors of that merge \n> > which need rebasing were rebased already).\n> >\n> \n> Maybe, it would be better if re-written commits were marked a bit \n> differently, so there will be no confusion about whether an original or \n> re-written commit is referred. For instance, re-written commits can be \n> marked by adding apostrophe at the end, so if the original commit was \n> \"abcdef\" then the re-written should be called as \"abcdef'\". At least, it \n> will make plain clear for anyone where in merge rewritten commits are \n> mentioned. Otherwise, it looks too magical to me.\n\nFair enough.  (For the \"too magical\" part.)\n\nBut it would break down if you picked one commit twice, in order to split \nit.  OTOH, this is a rare thing, and you really only need to refer to \nrewritten commits in the \"reset\" and \"merge\" commands.\n\nBut there is a bigger problem with what you suggest: When merging a commit \nthat is _not_ in the rewritten part of the history, adding an apostrophe \nis actively wrong.\n\nAnd I still believe strongly that a regular \"rebase -i -p\" user will not \nwant to refer to original commits, except for the \"pick\" command.\n\nCiao,\nDscho\n"},{"id":"75776","messageId":"7vy76tyhfd.fsf@gitster.siamese.dyndns.org","threadId":"12825","inReplyTo":"alpine.DEB.1.00.0804301253520.2136@eeepc-johanness","subject":"Re: [PATCH v2 04/13] Teach rebase interactive the mark command","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2008-05-01T19:04:38Z","receivedAt":"2008-05-01T19:04:38Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n\n> The idea I hinted at was to refer to them by another name than the short \n> name.  Then we can use the sequencer machinery.\n>\n> I still maintain that it is such a rare need (even if you are a power user \n> of it) that it makes sense to cater for other, simpler uses.\n\nAs usual, I am greedy and I would want to have both supported in such a\nway that (1) simple things are simple and (2) the language is expressive\nenough that complex things are possible.  And I try to stress that while\nwe are still in the drawing board phase, because it would be painful to\nchange once we start with a language without enough expressiveness.\n\nAnd that was where my \"Can the approach to use the original commit ID to\nstand for rewritten one express everything we would want to do in the\nfuture, not just limited to 'rebase -i -p'\" series of questions came\nfrom.\n"},{"id":"75918","messageId":"alpine.DEB.1.00.0805031340550.30431@racer","threadId":"12825","inReplyTo":"7vy76tyhfd.fsf@gitster.siamese.dyndns.org","subject":"Re: [PATCH v2 04/13] Teach rebase interactive the mark command","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2008-05-03T12:45:40Z","receivedAt":"2008-05-03T12:45:40Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Thu, 1 May 2008, Junio C Hamano wrote:\n\n> Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n> \n> > The idea I hinted at was to refer to them by another name than the short \n> > name.  Then we can use the sequencer machinery.\n> >\n> > I still maintain that it is such a rare need (even if you are a power user \n> > of it) that it makes sense to cater for other, simpler uses.\n> \n> As usual, I am greedy and I would want to have both supported in such a\n> way that (1) simple things are simple and (2) the language is expressive\n> enough that complex things are possible.\n\nAgreed.\n\n> And I try to stress that while we are still in the drawing board phase, \n> because it would be painful to change once we start with a language \n> without enough expressiveness.\n\nUnfortunately, we are no longer in the drawing board phase, because the \noffending code is already in 'next'.\n\n> And that was where my \"Can the approach to use the original commit ID to \n> stand for rewritten one express everything we would want to do in the \n> future, not just limited to 'rebase -i -p'\" series of questions came \n> from.\n\nI maintain that it can.  Because you can _still_ refer to the original \ncommit name quite easily: just take one more letter.\n\nIn the meantime I thought about the \"<commit name>'\" approach (note the \nsingle apostrophe at the end), though, and it seems that this would not \nbe too involved.\n\nBut hey, the code is so ugly and complicated by now, that I avert my eyes \nto other tasks.\n\nCiao,\nDscho\n"},{"id":"75945","messageId":"7vtzhfuxfd.fsf@gitster.siamese.dyndns.org","threadId":"12825","inReplyTo":"alpine.DEB.1.00.0805031340550.30431@racer","subject":"Re: [PATCH v2 04/13] Teach rebase interactive the mark command","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2008-05-03T17:09:26Z","receivedAt":"2008-05-03T17:09:26Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n\n>> And I try to stress that while we are still in the drawing board phase, \n>> because it would be painful to change once we start with a language \n>> without enough expressiveness.\n>\n> Unfortunately, we are no longer in the drawing board phase, because the \n> offending code is already in 'next'.\n\nWhat does that mean?  \"Now we are committed to it, so I will stop\ncomplaining and work within the overall design in a more constructive\nway\"?\n\nWe have precedence of even reverting the whole series from 'next'. When\nthere is a better design available, I think it is perfectly fine to\nimprove what is in 'next' in a way that is not backward compatible with\nstuff that has not hit 'master'.  That is what 'next' is for.\n"},{"id":"75999","messageId":"alpine.DEB.1.00.0805041032070.30431@racer","threadId":"12825","inReplyTo":"7vtzhfuxfd.fsf@gitster.siamese.dyndns.org","subject":"Re: [PATCH v2 04/13] Teach rebase interactive the mark command","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2008-05-04T09:38:49Z","receivedAt":"2008-05-04T09:38:49Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Sat, 3 May 2008, Junio C Hamano wrote:\n\n> Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n> \n> >> And I try to stress that while we are still in the drawing board \n> >> phase, because it would be painful to change once we start with a \n> >> language without enough expressiveness.\n> >\n> > Unfortunately, we are no longer in the drawing board phase, because \n> > the offending code is already in 'next'.\n> \n> What does that mean?  \"Now we are committed to it, so I will stop \n> complaining and work within the overall design in a more constructive \n> way\"?\n\nFine.\n\nI think that the \"mark\" mechanism is a fine thing for scripts that import \ninto Git.  There, the limitation to integers in a certain range does not \nhurt.\n\nThe \"mark\" mechanism could even be used to implement a user-friendly \nrebase -i -p, but I think that _exposing_ it is a mistake.\n\nSure, I could imagine that _editing_ a list of commits, you want to mark a \ncommit (why not \"tag\", which would be much more consistent with the rest \nof Git?), but name it something human-readable, such as\n\n\tpick 1234567 Clean up rebase -i -p\n\ttag cleanup\n\t...\n\tmerge 2345678 cleanup master\n\nYes, you read that correctly, I think that allowing plain ref names is \nvery valuable.  AFAICT my original implementation allows that (dunno about \nthe current code).\n\nI actually grow fonder and fonder of the ' idea (rewritten commits can be \nreferenced by their short commit name with a single apostroph appended, \nand if that commit was not rewritten at all, it falls back to the original \ncommit).\n\nThat should please you, and the other guy commenting on the \"magic\".\n\nIn the meantime I am also convinced that it could be implemented in an \nelegant way.\n\nCiao,\nDscho\n"},{"id":"76017","messageId":"20080504125258.GA3399@alea.gnuu.de","threadId":"12825","inReplyTo":"alpine.DEB.1.00.0805041032070.30431@racer","subject":"Re: [PATCH v2 04/13] Teach rebase interactive the mark command","fromName":"Jörg Sommer","fromEmail":"joerg@alea.gnuu.de","sentAt":"2008-05-04T12:52:58Z","receivedAt":"2008-05-04T12:52:58Z","isPatch":true,"sender":{"key":"joerg@alea.gnuu.de","avatar":null},"body":"Hi,\n\nJohannes Schindelin schrieb am Sun 04. May, 10:38 (+0100):\n> \tpick 1234567 Clean up rebase -i -p\n> \ttag cleanup\n> \t...\n> \tmerge 2345678 cleanup master\n> \n> Yes, you read that correctly, I think that allowing plain ref names is \n> very valuable.  AFAICT my original implementation allows that (dunno about \n> the current code).\n\nYour code is still used and you can do things like:\n\nmerge abc --strategy=YOUR_STRATEGY master 022ef38 my_tag\n\nAnd I think it's really easy to do a git-describe for each ref that is not\nmarked of reset and merge commands\n\nFrom fec670a4dc6fdf484a197687db5fbd0a4f668449 Mon Sep 17 00:00:00 2001\nFrom: =?utf-8?q?J=C3=B6rg=20Sommer?= <joerg@alea.gnuu.de>\nDate: Sun, 4 May 2008 14:52:01 +0200\nSubject: [PATCH] Use names instead of sha1 ID for reset and merge if possible\nMIME-Version: 1.0\nContent-Type: text/plain; charset=utf-8\nContent-Transfer-Encoding: 8bit\n\nSometimes it's much more helpful to see the name of a branch or a tag as\nthe argument of a merge or reset command.\n\nSigned-off-by: Jörg Sommer <joerg@alea.gnuu.de>\n---\n git-rebase--interactive.sh |    8 ++++++++\n 1 files changed, 8 insertions(+), 0 deletions(-)\n\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex 2a01182..2bd858c 100755\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -493,6 +493,10 @@ create_extended_todo_list () {\n \t\t\tif tmp=$(get_value_from_list $args \"$commit_mark_list\")\n \t\t\tthen\n \t\t\t\targs=\":$tmp\"\n+\t\t\telif tmp=$(git describe --all --exact-match $args \\\n+\t\t\t\t2>/dev/null)\n+\t\t\tthen\n+\t\t\t\targs=\"$tmp\"\n \t\t\tfi\n \t\t\t;;\n \t\tmerge)\n@@ -503,6 +507,10 @@ create_extended_todo_list () {\n \t\t\t\t\t\"$commit_mark_list\")\n \t\t\t\tthen\n \t\t\t\t\tnew_args=\"$new_args :$tmp\"\n+\t\t\t\telif tmp=$(git describe --all --exact-match \\\n+\t\t\t\t\t$i 2>/dev/null)\n+\t\t\t\tthen\n+\t\t\t\t\tnew_args=\"$new_args $tmp\"\n \t\t\t\telse\n \t\t\t\t\tnew_args=\"$new_args $i\"\n \t\t\t\tfi\n-- \n1.5.5.1\n\nBye, Jörg.\n-- \nDiskutiere nie mit einem Idioten:\nSie ziehen Dich auf ihr Niveau herab und schlagen Dich dann mit\nErfahrung.\n"}]}