{"thread":{"id":"25635","subject":"[PATCH 1/2] rebase: better rearranging of fixup!/squash! lines with --autosquash","startedAt":"2010-11-04T02:41:43Z","lastAt":"2010-11-08T11:10:05Z","messageCount":13,"participants":["Kevin Ballard","Sverre Rabbelier","Junio C Hamano","Peter Krefting","Yann Dirson"],"isPatch":true,"patchVersion":1,"patchTotal":2},"messages":[{"id":"155124","messageId":"1288838504-69114-1-git-send-email-kevin@sb.org","threadId":"25635","inReplyTo":null,"subject":"[PATCH 1/2] rebase: better rearranging of fixup!/squash! lines with --autosquash","fromName":"Kevin Ballard","fromEmail":"kevin@sb.org","sentAt":"2010-11-04T02:41:43Z","receivedAt":"2010-11-04T02:41:43Z","isPatch":true,"sender":{"key":"kevin@sb.org","avatar":"https://avatars.githubusercontent.com/u/714?v=4"},"body":"The current behvaior of --autosquash can duplicate fixup!/squash! lines\nif they match multiple commits, and it can also apply them to commits\nthat come after them in the todo list. Even more oddly, a commit that\nlooks like \"fixup! fixup!\" will match itself and be duplicated in the\ntodo list.\n\nChange the todo list rearranging to mark all commits as used as soon\nas they are emitted, and to avoid emitting a fixup/squash commit if the\ncommit has already been marked as used.\n\nSigned-off-by: Kevin Ballard <kevin@sb.org>\n---\n git-rebase--interactive.sh   |    4 +++\n t/t3415-rebase-autosquash.sh |   43 ++++++++++++++++++++++++++++++++++++++++++\n 2 files changed, 47 insertions(+), 0 deletions(-)\n\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex a27952d..379bbac 100755\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -687,8 +687,12 @@ rearrange_squash () {\n \t\t*\" $sha1 \"*) continue ;;\n \t\tesac\n \t\tprintf '%s\\n' \"$pick $sha1 $message\"\n+\t\tused=\"$used$sha1 \"\n \t\twhile read -r squash action msg\n \t\tdo\n+\t\t\tcase \" $used\" in\n+\t\t\t*\" $squash \"*) continue ;;\n+\t\t\tesac\n \t\t\tcase \"$message\" in\n \t\t\t\"$msg\"*)\n \t\t\t\tprintf '%s\\n' \"$action $squash $action! $msg\"\ndiff --git a/t/t3415-rebase-autosquash.sh b/t/t3415-rebase-autosquash.sh\nindex fd2184c..712bbe8 100755\n--- a/t/t3415-rebase-autosquash.sh\n+++ b/t/t3415-rebase-autosquash.sh\n@@ -94,4 +94,47 @@ test_expect_success 'misspelled auto squash' '\n \ttest 0 = $(git rev-list final-missquash...HEAD | wc -l)\n '\n \n+test_expect_success 'auto squash that matches 2 commits' '\n+\tgit reset --hard base &&\n+\techo 4 >file4 &&\n+\tgit add file4 &&\n+\ttest_tick &&\n+\tgit commit -m \"first new commit\" &&\n+\techo 1 >file1 &&\n+\tgit add -u &&\n+\ttest_tick &&\n+\tgit commit -m \"squash! first\" &&\n+\tgit tag final-multisquash &&\n+\ttest_tick &&\n+\tgit rebase --autosquash -i HEAD~4 &&\n+\tgit log --oneline >actual &&\n+\ttest 4 = $(wc -l <actual) &&\n+\tgit diff --exit-code final-multisquash &&\n+\ttest 1 = \"$(git cat-file blob HEAD^^:file1)\" &&\n+\ttest 2 = $(git cat-file commit HEAD^^ | grep first | wc -l) &&\n+\ttest 1 = $(git cat-file commit HEAD | grep first | wc -l)\n+'\n+\n+test_expect_success 'auto squash that matches a commit after the squash' '\n+\tgit reset --hard base &&\n+\techo 1 >file1 &&\n+\tgit add -u &&\n+\ttest_tick &&\n+\tgit commit -m \"squash! third\" &&\n+\techo 4 >file4 &&\n+\tgit add file4 &&\n+\ttest_tick &&\n+\tgit commit -m \"third commit\" &&\n+\tgit tag final-presquash &&\n+\ttest_tick &&\n+\tgit rebase --autosquash -i HEAD~4 &&\n+\tgit log --oneline >actual &&\n+\ttest 5 = $(wc -l <actual) &&\n+\tgit diff --exit-code final-presquash &&\n+\ttest 0 = \"$(git cat-file blob HEAD^^:file1)\" &&\n+\ttest 1 = \"$(git cat-file blob HEAD^:file1)\" &&\n+\ttest 1 = $(git cat-file commit HEAD | grep third | wc -l) &&\n+\ttest 1 = $(git cat-file commit HEAD^ | grep third | wc -l)\n+'\n+\n test_done\n-- \n1.7.3.2.201.g24941.dirty\n"},{"id":"155125","messageId":"1288838504-69114-2-git-send-email-kevin@sb.org","threadId":"25635","inReplyTo":"1288838504-69114-1-git-send-email-kevin@sb.org","subject":"[PATCH 2/2] rebase: teach --autosquash to match on sha1 in addition to message","fromName":"Kevin Ballard","fromEmail":"kevin@sb.org","sentAt":"2010-11-04T02:41:44Z","receivedAt":"2010-11-04T02:41:44Z","isPatch":true,"sender":{"key":"kevin@sb.org","avatar":"https://avatars.githubusercontent.com/u/714?v=4"},"body":"Support lines of the form \"fixup! 7a235b\" that specify an exact commit\nin addition to the normal \"squash! Old commit message\" form.\n\nSigned-off-by: Kevin Ballard <kevin@sb.org>\n---\nI chose 4 characters as the restriction because that's the minimum number\nthat `git rev-parse --short=<n>` will emit.\n\n git-rebase--interactive.sh   |   13 +++++++++----\n t/t3415-rebase-autosquash.sh |   33 +++++++++++++++++++++++++++++++++\n 2 files changed, 42 insertions(+), 4 deletions(-)\n\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex 379bbac..9121bb6 100755\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -693,12 +693,17 @@ rearrange_squash () {\n \t\t\tcase \" $used\" in\n \t\t\t*\" $squash \"*) continue ;;\n \t\t\tesac\n-\t\t\tcase \"$message\" in\n-\t\t\t\"$msg\"*)\n+\t\t\temit=0\n+\t\t\tcase \"$message\" in \"$msg\"*) emit=1;; esac\n+\t\t\tif test $emit != 1; then\n+\t\t\t\tcase \"$sha1\" in \"$msg\"*) emit=1;; esac\n+\t\t\t\t# ensure the message is at least 4 characters long\n+\t\t\t\tcase \"$msg\" in ????*);; *) emit=0;; esac\n+\t\t\tfi\n+\t\t\tif test $emit = 1; then\n \t\t\t\tprintf '%s\\n' \"$action $squash $action! $msg\"\n \t\t\t\tused=\"$used$squash \"\n-\t\t\t\t;;\n-\t\t\tesac\n+\t\t\tfi\n \t\tdone <\"$1.sq\"\n \tdone >\"$1.rearranged\" <\"$1\"\n \tcat \"$1.rearranged\" >\"$1\"\ndiff --git a/t/t3415-rebase-autosquash.sh b/t/t3415-rebase-autosquash.sh\nindex 712bbe8..14cdbeb 100755\n--- a/t/t3415-rebase-autosquash.sh\n+++ b/t/t3415-rebase-autosquash.sh\n@@ -136,5 +136,38 @@ test_expect_success 'auto squash that matches a commit after the squash' '\n \ttest 1 = $(git cat-file commit HEAD | grep third | wc -l) &&\n \ttest 1 = $(git cat-file commit HEAD^ | grep third | wc -l)\n '\n+test_expect_success 'auto squash that matches a sha1' '\n+\tgit reset --hard base &&\n+\techo 1 >file1 &&\n+\tgit add -u &&\n+\ttest_tick &&\n+\tgit commit -m \"squash! $(git rev-parse --short HEAD^)\" &&\n+\tgit tag final-shasquash &&\n+\ttest_tick &&\n+\tgit rebase --autosquash -i HEAD^^^ &&\n+\tgit log --oneline >actual &&\n+\ttest 3 = $(wc -l <actual) &&\n+\tgit diff --exit-code final-shasquash &&\n+\ttest 1 = \"$(git cat-file blob HEAD^:file1)\" &&\n+\ttest 1 = $(git cat-file commit HEAD^ | grep squash | wc -l)\n+'\n+\n+# this test just ensures that < 4 characters can't match a sha1\n+test_expect_success 'auto squash that accidentally matches a sha1' '\n+\tgit reset --hard base &&\n+\techo 1 >file1 &&\n+\tgit add -u &&\n+\ttest_tick &&\n+\tgit commit -m \"squash! $(git rev-parse HEAD^ | cut -c 1-3)\" &&\n+\tgit tag final-badshasquash &&\n+\ttest_tick &&\n+\tgit rebase --autosquash -i HEAD^^^ &&\n+\tgit log --oneline >actual &&\n+\ttest 4 = $(wc -l <actual) &&\n+\tgit diff --exit-code final-badshasquash &&\n+\ttest 0 = \"$(git cat-file blob HEAD^^:file1)\" &&\n+\ttest 0 = $(git cat-file commit HEAD^^ | grep squash | wc -l) &&\n+\ttest 1 = $(git cat-file commit HEAD | grep squash | wc -l)\n+'\n \n test_done\n-- \n1.7.3.2.201.g24941.dirty\n"},{"id":"155134","messageId":"5CCA000B-2178-4DF7-8D72-29F95A9BB360@sb.org","threadId":"25635","inReplyTo":"1288838504-69114-2-git-send-email-kevin@sb.org","subject":"Re: [PATCH 2/2] rebase: teach --autosquash to match on sha1 in addition to message","fromName":"Kevin Ballard","fromEmail":"kevin@sb.org","sentAt":"2010-11-04T04:49:10Z","receivedAt":"2010-11-04T04:49:10Z","isPatch":true,"sender":{"key":"kevin@sb.org","avatar":"https://avatars.githubusercontent.com/u/714?v=4"},"body":"On Nov 3, 2010, at 7:41 PM, Kevin Ballard wrote:\n\n> Support lines of the form \"fixup! 7a235b\" that specify an exact commit\n> in addition to the normal \"squash! Old commit message\" form.\n\nI just realized that this only works for sha1's of up to 7 characters.\nIf you provide more it won't match, as it's comparing against the sha1\ngiven in the todo list. I wonder if it's worth resolving all sha1s to\ntheir full length if the provided string is longer than 7 characters?\n\n-Kevin Ballard\n"},{"id":"155161","messageId":"AANLkTikA_46ZdrRBCnh-1Rx1jfqGb377jeg=9OO5T3Tr@mail.gmail.com","threadId":"25635","inReplyTo":"5CCA000B-2178-4DF7-8D72-29F95A9BB360@sb.org","subject":"Re: [PATCH 2/2] rebase: teach --autosquash to match on sha1 in addition to message","fromName":"Sverre Rabbelier","fromEmail":"srabbelier@gmail.com","sentAt":"2010-11-04T10:44:46Z","receivedAt":"2010-11-04T10:44:46Z","isPatch":true,"sender":{"key":"srabbelier@gmail.com","avatar":"https://avatars.githubusercontent.com/u/3098?v=4"},"body":"Heya,\n\nOn Thu, Nov 4, 2010 at 05:49, Kevin Ballard <kevin@sb.org> wrote:\n> I just realized that this only works for sha1's of up to 7 characters.\n> If you provide more it won't match, as it's comparing against the sha1\n> given in the todo list. I wonder if it's worth resolving all sha1s to\n> their full length if the provided string is longer than 7 characters?\n\nWell, not if you're resolving them based on the 7-character string\nfrom the rebase todo list. If you run in to ambiguity with those\n7-length hash we should instead increase the length of the hashes in\nthe todo list.\n\nSo I'd say, solve this by doing a prefix match?\n\n-- \nCheers,\n\nSverre Rabbelier\n"},{"id":"155195","messageId":"7vr5f0vrbn.fsf@alter.siamese.dyndns.org","threadId":"25635","inReplyTo":"5CCA000B-2178-4DF7-8D72-29F95A9BB360@sb.org","subject":"Re: [PATCH 2/2] rebase: teach --autosquash to match on sha1 in addition to message","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2010-11-04T19:09:32Z","receivedAt":"2010-11-04T19:09:32Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Kevin Ballard <kevin@sb.org> writes:\n\n> On Nov 3, 2010, at 7:41 PM, Kevin Ballard wrote:\n>\n>> Support lines of the form \"fixup! 7a235b\" that specify an exact commit\n>> in addition to the normal \"squash! Old commit message\" form.\n>\n> I just realized that this only works for sha1's of up to 7 characters.\n> If you provide more it won't match, as it's comparing against the sha1\n> given in the todo list. I wonder if it's worth resolving all sha1s to\n> their full length if the provided string is longer than 7 characters?\n\nYeah, this is a nice feature I sometimes missed ;-)\n"},{"id":"155219","messageId":"F2547972-0FEF-4123-96AF-75F60967DAB5@sb.org","threadId":"25635","inReplyTo":"AANLkTikA_46ZdrRBCnh-1Rx1jfqGb377jeg=9OO5T3Tr@mail.gmail.com","subject":"Re: [PATCH 2/2] rebase: teach --autosquash to match on sha1 in addition to message","fromName":"Kevin Ballard","fromEmail":"kevin@sb.org","sentAt":"2010-11-04T21:35:14Z","receivedAt":"2010-11-04T21:35:14Z","isPatch":true,"sender":{"key":"kevin@sb.org","avatar":"https://avatars.githubusercontent.com/u/714?v=4"},"body":"On Nov 4, 2010, at 3:44 AM, Sverre Rabbelier wrote:\n\n> On Thu, Nov 4, 2010 at 05:49, Kevin Ballard <kevin@sb.org> wrote:\n>> I just realized that this only works for sha1's of up to 7 characters.\n>> If you provide more it won't match, as it's comparing against the sha1\n>> given in the todo list. I wonder if it's worth resolving all sha1s to\n>> their full length if the provided string is longer than 7 characters?\n> \n> Well, not if you're resolving them based on the 7-character string\n> from the rebase todo list. If you run in to ambiguity with those\n> 7-length hash we should instead increase the length of the hashes in\n> the todo list.\n> \n> So I'd say, solve this by doing a prefix match?\n\nPrefix match of what against what? If the 7-character string used in the\nTODO list is already ambiguous, then the rebase itself would be expected\nto fail. I'm inclined to just try to resolve the message in the fixup!\nline itself to a full SHA1, and if that works, then try to match the\n7-character sha1 with a prefix comparison.\n\n-Kevin Ballard\n"},{"id":"155232","messageId":"1288910192-10247-1-git-send-email-kevin@sb.org","threadId":"25635","inReplyTo":"7vr5f0vrbn.fsf@alter.siamese.dyndns.org","subject":"[PATCHv2 1/2] rebase: better rearranging of fixup!/squash! lines with --autosquash","fromName":"Kevin Ballard","fromEmail":"kevin@sb.org","sentAt":"2010-11-04T22:36:31Z","receivedAt":"2010-11-04T22:36:31Z","isPatch":false,"sender":{"key":"kevin@sb.org","avatar":"https://avatars.githubusercontent.com/u/714?v=4"},"body":"The current behvaior of --autosquash can duplicate fixup!/squash! lines\nif they match multiple commits, and it can also apply them to commits\nthat come after them in the todo list. Even more oddly, a commit that\nlooks like \"fixup! fixup!\" will match itself and be duplicated in the\ntodo list.\n\nChange the todo list rearranging to mark all commits as used as soon\nas they are emitted, and to avoid emitting a fixup/squash commit if the\ncommit has already been marked as used.\n\nSigned-off-by: Kevin Ballard <kevin@sb.org>\n---\nThis patch is unchanged from the previous version.\n\n git-rebase--interactive.sh   |    4 +++\n t/t3415-rebase-autosquash.sh |   43 ++++++++++++++++++++++++++++++++++++++++++\n 2 files changed, 47 insertions(+), 0 deletions(-)\n\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex a27952d..379bbac 100755\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -687,8 +687,12 @@ rearrange_squash () {\n \t\t*\" $sha1 \"*) continue ;;\n \t\tesac\n \t\tprintf '%s\\n' \"$pick $sha1 $message\"\n+\t\tused=\"$used$sha1 \"\n \t\twhile read -r squash action msg\n \t\tdo\n+\t\t\tcase \" $used\" in\n+\t\t\t*\" $squash \"*) continue ;;\n+\t\t\tesac\n \t\t\tcase \"$message\" in\n \t\t\t\"$msg\"*)\n \t\t\t\tprintf '%s\\n' \"$action $squash $action! $msg\"\ndiff --git a/t/t3415-rebase-autosquash.sh b/t/t3415-rebase-autosquash.sh\nindex fd2184c..712bbe8 100755\n--- a/t/t3415-rebase-autosquash.sh\n+++ b/t/t3415-rebase-autosquash.sh\n@@ -94,4 +94,47 @@ test_expect_success 'misspelled auto squash' '\n \ttest 0 = $(git rev-list final-missquash...HEAD | wc -l)\n '\n \n+test_expect_success 'auto squash that matches 2 commits' '\n+\tgit reset --hard base &&\n+\techo 4 >file4 &&\n+\tgit add file4 &&\n+\ttest_tick &&\n+\tgit commit -m \"first new commit\" &&\n+\techo 1 >file1 &&\n+\tgit add -u &&\n+\ttest_tick &&\n+\tgit commit -m \"squash! first\" &&\n+\tgit tag final-multisquash &&\n+\ttest_tick &&\n+\tgit rebase --autosquash -i HEAD~4 &&\n+\tgit log --oneline >actual &&\n+\ttest 4 = $(wc -l <actual) &&\n+\tgit diff --exit-code final-multisquash &&\n+\ttest 1 = \"$(git cat-file blob HEAD^^:file1)\" &&\n+\ttest 2 = $(git cat-file commit HEAD^^ | grep first | wc -l) &&\n+\ttest 1 = $(git cat-file commit HEAD | grep first | wc -l)\n+'\n+\n+test_expect_success 'auto squash that matches a commit after the squash' '\n+\tgit reset --hard base &&\n+\techo 1 >file1 &&\n+\tgit add -u &&\n+\ttest_tick &&\n+\tgit commit -m \"squash! third\" &&\n+\techo 4 >file4 &&\n+\tgit add file4 &&\n+\ttest_tick &&\n+\tgit commit -m \"third commit\" &&\n+\tgit tag final-presquash &&\n+\ttest_tick &&\n+\tgit rebase --autosquash -i HEAD~4 &&\n+\tgit log --oneline >actual &&\n+\ttest 5 = $(wc -l <actual) &&\n+\tgit diff --exit-code final-presquash &&\n+\ttest 0 = \"$(git cat-file blob HEAD^^:file1)\" &&\n+\ttest 1 = \"$(git cat-file blob HEAD^:file1)\" &&\n+\ttest 1 = $(git cat-file commit HEAD | grep third | wc -l) &&\n+\ttest 1 = $(git cat-file commit HEAD^ | grep third | wc -l)\n+'\n+\n test_done\n-- \n1.7.3.2.202.g3b863.dirty\n"},{"id":"155233","messageId":"1288910192-10247-2-git-send-email-kevin@sb.org","threadId":"25635","inReplyTo":"7vr5f0vrbn.fsf@alter.siamese.dyndns.org","subject":"[PATCHv2 2/2] rebase: teach --autosquash to match on sha1 in addition to message","fromName":"Kevin Ballard","fromEmail":"kevin@sb.org","sentAt":"2010-11-04T22:36:32Z","receivedAt":"2010-11-04T22:36:32Z","isPatch":false,"sender":{"key":"kevin@sb.org","avatar":"https://avatars.githubusercontent.com/u/714?v=4"},"body":"Support lines of the form \"fixup! 7a235b\" that specify an exact commit\nin addition to the normal \"squash! Old commit message\" form.\n\nSigned-off-by: Kevin Ballard <kevin@sb.org>\n---\nThis version attempts to resolve all single-word fixup!/squash! messages to\nfull sha1s. It only tries this once per line and records the results in the\n$TODO.sq file. The reasoning for the duplication of such lines is to allow\na line like\n\n  fixup! 8a23b5f 7a5436\n\nto still prefix-match \"7a5436\" against commit messages in addition to matching\nthe fullly-resolved sha1 against the other sha1's.\n\n git-rebase--interactive.sh   |   40 +++++++++++++++++++++++++++++++++-------\n t/t3415-rebase-autosquash.sh |   31 +++++++++++++++++++++++++++++++\n 2 files changed, 64 insertions(+), 7 deletions(-)\n\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex 379bbac..c2383bf 100755\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -675,9 +675,27 @@ get_saved_options () {\n # comes immediately after the former, and change \"pick\" to\n # \"fixup\"/\"squash\".\n rearrange_squash () {\n-\tsed -n -e 's/^pick \\([0-9a-f]*\\) \\(squash\\)! /\\1 \\2 /p' \\\n-\t\t-e 's/^pick \\([0-9a-f]*\\) \\(fixup\\)! /\\1 \\2 /p' \\\n-\t\t\"$1\" >\"$1.sq\"\n+\t# extract fixup!/squash! lines and resolve any referenced sha1's\n+\twhile read -r pick sha1 message\n+\tdo\n+\t\tcase \"$message\" in\n+\t\t\"squash! \"*|\"fixup! \"*)\n+\t\t\taction=\"${message%%!*}\"\n+\t\t\trest=\"${message#*! }\"\n+\t\t\techo \"$sha1 $action $rest\"\n+\t\t\t# if it's a single word, try to resolve to a full sha1 and\n+\t\t\t# emit a second copy. This allows us to match on both message\n+\t\t\t# and on sha1 prefix\n+\t\t\tif test \"${rest#* }\" = \"$rest\"; then\n+\t\t\t\tfullsha=\"$(git rev-parse -q --verify \"$rest\" 2>/dev/null)\"\n+\t\t\t\tif test -n \"$fullsha\"; then\n+\t\t\t\t\t# prefix the action to uniquely identify this line as\n+\t\t\t\t\t# intended for full sha1 match\n+\t\t\t\t\techo \"$sha1 +$action $fullsha\"\n+\t\t\t\tfi\n+\t\t\tfi\n+\t\tesac\n+\tdone >\"$1.sq\" <\"$1\"\n \ttest -s \"$1.sq\" || return\n \n \tused=\n@@ -693,12 +711,20 @@ rearrange_squash () {\n \t\t\tcase \" $used\" in\n \t\t\t*\" $squash \"*) continue ;;\n \t\t\tesac\n-\t\t\tcase \"$message\" in\n-\t\t\t\"$msg\"*)\n+\t\t\temit=0\n+\t\t\tcase \"$action\" in\n+\t\t\t+*)\n+\t\t\t\taction=\"${action#+}\"\n+\t\t\t\t# full sha1 prefix test\n+\t\t\t\tcase \"$msg\" in \"$sha1\"*) emit=1;; esac ;;\n+\t\t\t*)\n+\t\t\t\t# message prefix test\n+\t\t\t\tcase \"$message\" in \"$msg\"*) emit=1;; esac ;;\n+\t\t\tesac\n+\t\t\tif test $emit = 1; then\n \t\t\t\tprintf '%s\\n' \"$action $squash $action! $msg\"\n \t\t\t\tused=\"$used$squash \"\n-\t\t\t\t;;\n-\t\t\tesac\n+\t\t\tfi\n \t\tdone <\"$1.sq\"\n \tdone >\"$1.rearranged\" <\"$1\"\n \tcat \"$1.rearranged\" >\"$1\"\ndiff --git a/t/t3415-rebase-autosquash.sh b/t/t3415-rebase-autosquash.sh\nindex 712bbe8..ca16b70 100755\n--- a/t/t3415-rebase-autosquash.sh\n+++ b/t/t3415-rebase-autosquash.sh\n@@ -136,5 +136,36 @@ test_expect_success 'auto squash that matches a commit after the squash' '\n \ttest 1 = $(git cat-file commit HEAD | grep third | wc -l) &&\n \ttest 1 = $(git cat-file commit HEAD^ | grep third | wc -l)\n '\n+test_expect_success 'auto squash that matches a sha1' '\n+\tgit reset --hard base &&\n+\techo 1 >file1 &&\n+\tgit add -u &&\n+\ttest_tick &&\n+\tgit commit -m \"squash! $(git rev-parse --short HEAD^)\" &&\n+\tgit tag final-shasquash &&\n+\ttest_tick &&\n+\tgit rebase --autosquash -i HEAD^^^ &&\n+\tgit log --oneline >actual &&\n+\ttest 3 = $(wc -l <actual) &&\n+\tgit diff --exit-code final-shasquash &&\n+\ttest 1 = \"$(git cat-file blob HEAD^:file1)\" &&\n+\ttest 1 = $(git cat-file commit HEAD^ | grep squash | wc -l)\n+'\n+\n+test_expect_success 'auto squash that matches longer sha1' '\n+\tgit reset --hard base &&\n+\techo 1 >file1 &&\n+\tgit add -u &&\n+\ttest_tick &&\n+\tgit commit -m \"squash! $(git rev-parse --short=11 HEAD^)\" &&\n+\tgit tag final-longshasquash &&\n+\ttest_tick &&\n+\tgit rebase --autosquash -i HEAD^^^ &&\n+\tgit log --oneline >actual &&\n+\ttest 3 = $(wc -l <actual) &&\n+\tgit diff --exit-code final-longshasquash &&\n+\ttest 1 = \"$(git cat-file blob HEAD^:file1)\" &&\n+\ttest 1 = $(git cat-file commit HEAD^ | grep squash | wc -l)\n+'\n \n test_done\n-- \n1.7.3.2.202.g3b863.dirty\n"},{"id":"155257","messageId":"alpine.DEB.2.00.1011051401090.7611@ds9.cixit.se","threadId":"25635","inReplyTo":"1288838504-69114-2-git-send-email-kevin@sb.org","subject":"Re: [PATCH 2/2] rebase: teach --autosquash to match on sha1 in addition to message","fromName":"Peter Krefting","fromEmail":"peter@softwolves.pp.se","sentAt":"2010-11-05T13:04:26Z","receivedAt":"2010-11-05T13:04:26Z","isPatch":true,"sender":{"key":"peter@softwolves.pp.se","avatar":"https://avatars.githubusercontent.com/u/990764?v=4"},"body":"Kevin Ballard:\n\n> Support lines of the form \"fixup! 7a235b\" that specify an exact commit\n> in addition to the normal \"squash! Old commit message\" form.\n\nThe patch I posted for this in June (Message-Id: \n<20100617125746.E86B42FC00@perkele>) also updated the manual page for \ngit-rebase. You may want to re-use parts of that.\n\nhttp://www.spinics.net/lists/git/msg133571.html has an archived version of it.\n\n-- \n\\\\// Peter - http://www.softwolves.pp.se/\n"},{"id":"155365","messageId":"1289213283-24294-1-git-send-email-kevin@sb.org","threadId":"25635","inReplyTo":"alpine.DEB.2.00.1011051401090.7611@ds9.cixit.se","subject":"[PATCHv3 1/2] rebase: better rearranging of fixup!/squash! lines with --autosquash","fromName":"Kevin Ballard","fromEmail":"kevin@sb.org","sentAt":"2010-11-08T10:48:02Z","receivedAt":"2010-11-08T10:48:02Z","isPatch":false,"sender":{"key":"kevin@sb.org","avatar":"https://avatars.githubusercontent.com/u/714?v=4"},"body":"The current behvaior of --autosquash can duplicate fixup!/squash! lines\nif they match multiple commits, and it can also apply them to commits\nthat come after them in the todo list. Even more oddly, a commit that\nlooks like \"fixup! fixup!\" will match itself and be duplicated in the\ntodo list.\n\nChange the todo list rearranging to mark all commits as used as soon\nas they are emitted, and to avoid emitting a fixup/squash commit if the\ncommit has already been marked as used.\n\nSigned-off-by: Kevin Ballard <kevin@sb.org>\n---\n\nThis patch is unchanged from v2.\n\n git-rebase--interactive.sh   |    4 +++\n t/t3415-rebase-autosquash.sh |   43 ++++++++++++++++++++++++++++++++++++++++++\n 2 files changed, 47 insertions(+), 0 deletions(-)\n\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex e29fd91..56cfdb5 100755\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -707,8 +707,12 @@ rearrange_squash () {\n \t\t*\" $sha1 \"*) continue ;;\n \t\tesac\n \t\tprintf '%s\\n' \"$pick $sha1 $message\"\n+\t\tused=\"$used$sha1 \"\n \t\twhile read -r squash action msg\n \t\tdo\n+\t\t\tcase \" $used\" in\n+\t\t\t*\" $squash \"*) continue ;;\n+\t\t\tesac\n \t\t\tcase \"$message\" in\n \t\t\t\"$msg\"*)\n \t\t\t\tprintf '%s\\n' \"$action $squash $action! $msg\"\ndiff --git a/t/t3415-rebase-autosquash.sh b/t/t3415-rebase-autosquash.sh\nindex fd2184c..712bbe8 100755\n--- a/t/t3415-rebase-autosquash.sh\n+++ b/t/t3415-rebase-autosquash.sh\n@@ -94,4 +94,47 @@ test_expect_success 'misspelled auto squash' '\n \ttest 0 = $(git rev-list final-missquash...HEAD | wc -l)\n '\n \n+test_expect_success 'auto squash that matches 2 commits' '\n+\tgit reset --hard base &&\n+\techo 4 >file4 &&\n+\tgit add file4 &&\n+\ttest_tick &&\n+\tgit commit -m \"first new commit\" &&\n+\techo 1 >file1 &&\n+\tgit add -u &&\n+\ttest_tick &&\n+\tgit commit -m \"squash! first\" &&\n+\tgit tag final-multisquash &&\n+\ttest_tick &&\n+\tgit rebase --autosquash -i HEAD~4 &&\n+\tgit log --oneline >actual &&\n+\ttest 4 = $(wc -l <actual) &&\n+\tgit diff --exit-code final-multisquash &&\n+\ttest 1 = \"$(git cat-file blob HEAD^^:file1)\" &&\n+\ttest 2 = $(git cat-file commit HEAD^^ | grep first | wc -l) &&\n+\ttest 1 = $(git cat-file commit HEAD | grep first | wc -l)\n+'\n+\n+test_expect_success 'auto squash that matches a commit after the squash' '\n+\tgit reset --hard base &&\n+\techo 1 >file1 &&\n+\tgit add -u &&\n+\ttest_tick &&\n+\tgit commit -m \"squash! third\" &&\n+\techo 4 >file4 &&\n+\tgit add file4 &&\n+\ttest_tick &&\n+\tgit commit -m \"third commit\" &&\n+\tgit tag final-presquash &&\n+\ttest_tick &&\n+\tgit rebase --autosquash -i HEAD~4 &&\n+\tgit log --oneline >actual &&\n+\ttest 5 = $(wc -l <actual) &&\n+\tgit diff --exit-code final-presquash &&\n+\ttest 0 = \"$(git cat-file blob HEAD^^:file1)\" &&\n+\ttest 1 = \"$(git cat-file blob HEAD^:file1)\" &&\n+\ttest 1 = $(git cat-file commit HEAD | grep third | wc -l) &&\n+\ttest 1 = $(git cat-file commit HEAD^ | grep third | wc -l)\n+'\n+\n test_done\n-- \n1.7.3.2.195.gc69dde\n"},{"id":"155366","messageId":"1289213283-24294-2-git-send-email-kevin@sb.org","threadId":"25635","inReplyTo":"alpine.DEB.2.00.1011051401090.7611@ds9.cixit.se","subject":"[PATCHv3 2/2] rebase: teach --autosquash to match on sha1 in addition to message","fromName":"Kevin Ballard","fromEmail":"kevin@sb.org","sentAt":"2010-11-08T10:48:03Z","receivedAt":"2010-11-08T10:48:03Z","isPatch":false,"sender":{"key":"kevin@sb.org","avatar":"https://avatars.githubusercontent.com/u/714?v=4"},"body":"Support lines of the form \"fixup! 7a235b\" that specify an exact commit\nin addition to the normal \"squash! Old commit message\" form.\n\nSigned-off-by: Kevin Ballard <kevin@sb.org>\n---\n\nThe only change from v2 is I've added the manpage change from Peter Krefting's\nprevious patch on this subject (http://www.spinics.net/lists/git/msg133571.html),\nas referenced in message id <alpine.DEB.2.00.1011051401090.7611@ds9.cixit.se>.\n\n Documentation/git-rebase.txt |    8 ++++----\n git-rebase--interactive.sh   |   40 +++++++++++++++++++++++++++++++++-------\n t/t3415-rebase-autosquash.sh |   31 +++++++++++++++++++++++++++++++\n 3 files changed, 68 insertions(+), 11 deletions(-)\n\ndiff --git a/Documentation/git-rebase.txt b/Documentation/git-rebase.txt\nindex 30e5c0e..17f50cb 100644\n--- a/Documentation/git-rebase.txt\n+++ b/Documentation/git-rebase.txt\n@@ -339,10 +339,10 @@ idea unless you know what you are doing (see BUGS below).\n --no-autosquash::\n \tWhen the commit log message begins with \"squash! ...\" (or\n \t\"fixup! ...\"), and there is a commit whose title begins with\n-\tthe same ..., automatically modify the todo list of rebase -i\n-\tso that the commit marked for squashing comes right after the\n-\tcommit to be modified, and change the action of the moved\n-\tcommit from `pick` to `squash` (or `fixup`).\n+\tthe same ..., or whose hash is ..., automatically modify the\n+\ttodo list of rebase -i so that the commit marked for squashing\n+\tcomes right after the commit to be modified, and change the\n+\taction of the moved commit from `pick` to `squash` (or `fixup`).\n +\n This option is only valid when the '--interactive' option is used.\n +\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex 56cfdb5..31abbff 100755\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -695,9 +695,27 @@ get_saved_options () {\n # comes immediately after the former, and change \"pick\" to\n # \"fixup\"/\"squash\".\n rearrange_squash () {\n-\tsed -n -e 's/^pick \\([0-9a-f]*\\) \\(squash\\)! /\\1 \\2 /p' \\\n-\t\t-e 's/^pick \\([0-9a-f]*\\) \\(fixup\\)! /\\1 \\2 /p' \\\n-\t\t\"$1\" >\"$1.sq\"\n+\t# extract fixup!/squash! lines and resolve any referenced sha1's\n+\twhile read -r pick sha1 message\n+\tdo\n+\t\tcase \"$message\" in\n+\t\t\"squash! \"*|\"fixup! \"*)\n+\t\t\taction=\"${message%%!*}\"\n+\t\t\trest=\"${message#*! }\"\n+\t\t\techo \"$sha1 $action $rest\"\n+\t\t\t# if it's a single word, try to resolve to a full sha1 and\n+\t\t\t# emit a second copy. This allows us to match on both message\n+\t\t\t# and on sha1 prefix\n+\t\t\tif test \"${rest#* }\" = \"$rest\"; then\n+\t\t\t\tfullsha=\"$(git rev-parse -q --verify \"$rest\" 2>/dev/null)\"\n+\t\t\t\tif test -n \"$fullsha\"; then\n+\t\t\t\t\t# prefix the action to uniquely identify this line as\n+\t\t\t\t\t# intended for full sha1 match\n+\t\t\t\t\techo \"$sha1 +$action $fullsha\"\n+\t\t\t\tfi\n+\t\t\tfi\n+\t\tesac\n+\tdone >\"$1.sq\" <\"$1\"\n \ttest -s \"$1.sq\" || return\n \n \tused=\n@@ -713,12 +731,20 @@ rearrange_squash () {\n \t\t\tcase \" $used\" in\n \t\t\t*\" $squash \"*) continue ;;\n \t\t\tesac\n-\t\t\tcase \"$message\" in\n-\t\t\t\"$msg\"*)\n+\t\t\temit=0\n+\t\t\tcase \"$action\" in\n+\t\t\t+*)\n+\t\t\t\taction=\"${action#+}\"\n+\t\t\t\t# full sha1 prefix test\n+\t\t\t\tcase \"$msg\" in \"$sha1\"*) emit=1;; esac ;;\n+\t\t\t*)\n+\t\t\t\t# message prefix test\n+\t\t\t\tcase \"$message\" in \"$msg\"*) emit=1;; esac ;;\n+\t\t\tesac\n+\t\t\tif test $emit = 1; then\n \t\t\t\tprintf '%s\\n' \"$action $squash $action! $msg\"\n \t\t\t\tused=\"$used$squash \"\n-\t\t\t\t;;\n-\t\t\tesac\n+\t\t\tfi\n \t\tdone <\"$1.sq\"\n \tdone >\"$1.rearranged\" <\"$1\"\n \tcat \"$1.rearranged\" >\"$1\"\ndiff --git a/t/t3415-rebase-autosquash.sh b/t/t3415-rebase-autosquash.sh\nindex 712bbe8..ca16b70 100755\n--- a/t/t3415-rebase-autosquash.sh\n+++ b/t/t3415-rebase-autosquash.sh\n@@ -136,5 +136,36 @@ test_expect_success 'auto squash that matches a commit after the squash' '\n \ttest 1 = $(git cat-file commit HEAD | grep third | wc -l) &&\n \ttest 1 = $(git cat-file commit HEAD^ | grep third | wc -l)\n '\n+test_expect_success 'auto squash that matches a sha1' '\n+\tgit reset --hard base &&\n+\techo 1 >file1 &&\n+\tgit add -u &&\n+\ttest_tick &&\n+\tgit commit -m \"squash! $(git rev-parse --short HEAD^)\" &&\n+\tgit tag final-shasquash &&\n+\ttest_tick &&\n+\tgit rebase --autosquash -i HEAD^^^ &&\n+\tgit log --oneline >actual &&\n+\ttest 3 = $(wc -l <actual) &&\n+\tgit diff --exit-code final-shasquash &&\n+\ttest 1 = \"$(git cat-file blob HEAD^:file1)\" &&\n+\ttest 1 = $(git cat-file commit HEAD^ | grep squash | wc -l)\n+'\n+\n+test_expect_success 'auto squash that matches longer sha1' '\n+\tgit reset --hard base &&\n+\techo 1 >file1 &&\n+\tgit add -u &&\n+\ttest_tick &&\n+\tgit commit -m \"squash! $(git rev-parse --short=11 HEAD^)\" &&\n+\tgit tag final-longshasquash &&\n+\ttest_tick &&\n+\tgit rebase --autosquash -i HEAD^^^ &&\n+\tgit log --oneline >actual &&\n+\ttest 3 = $(wc -l <actual) &&\n+\tgit diff --exit-code final-longshasquash &&\n+\ttest 1 = \"$(git cat-file blob HEAD^:file1)\" &&\n+\ttest 1 = $(git cat-file commit HEAD^ | grep squash | wc -l)\n+'\n \n test_done\n-- \n1.7.3.2.195.gc69dde\n"},{"id":"155367","messageId":"20101108115239.7309504f@chalon.bertin.fr","threadId":"25635","inReplyTo":"1289213283-24294-1-git-send-email-kevin@sb.org","subject":"Re: [PATCHv3 1/2] rebase: better rearranging of fixup!/squash! lines with --autosquash","fromName":"Yann Dirson","fromEmail":"dirson@bertin.fr","sentAt":"2010-11-08T10:52:39Z","receivedAt":"2010-11-08T10:52:39Z","isPatch":false,"sender":{"key":"dirson@bertin.fr","avatar":null},"body":"Kevin wrote:\n>The current behvaior of --autosquash can duplicate fixup!/squash! lines\n>if they match multiple commits, and it can also apply them to commits\n>that come after them in the todo list.\n\nThat last part of the sentence does not match my experience - it looks\nlike you describe as a bug a nonexistent feature I miss :)\n\nSee http://marc.info/?l=git&m=128784082701920 for a testcase that\nexhibits what I think is a problem.\n\n-- \nYann Dirson - Bertin Technologies\n"},{"id":"155370","messageId":"FB418838-D9A9-4FA6-8C32-FDC5F51DE783@sb.org","threadId":"25635","inReplyTo":"20101108115239.7309504f@chalon.bertin.fr","subject":"Re: [PATCHv3 1/2] rebase: better rearranging of fixup!/squash! lines with --autosquash","fromName":"Kevin Ballard","fromEmail":"kevin@sb.org","sentAt":"2010-11-08T11:10:05Z","receivedAt":"2010-11-08T11:10:05Z","isPatch":false,"sender":{"key":"kevin@sb.org","avatar":"https://avatars.githubusercontent.com/u/714?v=4"},"body":"On Nov 8, 2010, at 2:52 AM, Yann Dirson wrote:\n\n> Kevin wrote:\n>> The current behvaior of --autosquash can duplicate fixup!/squash! lines\n>> if they match multiple commits, and it can also apply them to commits\n>> that come after them in the todo list.\n> \n> That last part of the sentence does not match my experience - it looks\n> like you describe as a bug a nonexistent feature I miss :)\n> \n> See http://marc.info/?l=git&m=128784082701920 for a testcase that\n> exhibits what I think is a problem.\n\nThe bug is definitely present. It seems what you're describing is that you\nwant it to continue to place that fixup! there, but you want it to skip the\npick line that occurs earlier in the TODO list. My feeling is that this is\npurely a bug, and should be fixed to not place the fixup! line after the\nlater commit.\n\nIf you do want the behavior where it skips the pick and places the fixup!\nline after the later commit, I would encourage you to file a separate patch\nfor that.\n\n-Kevin Ballard\n"}]}