{"thread":{"id":"5997","subject":"[PATCH 1/2] Regression test for \"stg delete\"","startedAt":"2006-10-22T12:53:37Z","lastAt":"2006-11-02T10:36:51Z","messageCount":8,"participants":["Karl Hasselström","Catalin Marinas"],"isPatch":true,"patchVersion":1,"patchTotal":2},"messages":[{"id":"29613","messageId":"20061022125337.15194.64831.stgit@localhost","threadId":"5997","inReplyTo":null,"subject":"[PATCH 0/2] Teach \"stg delete\" to delete several patches at once","fromName":"Karl Hasselström","fromEmail":"kha@treskal.com","sentAt":"2006-10-22T12:53:37Z","receivedAt":"2006-10-22T12:53:37Z","isPatch":true,"sender":{"key":"kha@treskal.com","avatar":"https://gravatar.com/avatar/f0120c734b5279b345075a28521e1ac66acb20c9913ffe9bf6ae97e53f7f3f13?d=mp&s=160"},"body":"The first patch introduces a test for \"stg delete\", since there wasn't\nalready one, and it's much less stressful to modify stuff if you have\nan automatic test that can tell you if you broke stuff.\n\nAs it turns out, this test finds an existing bug: it's not possible to\ndelete a patch in another branch if there's an identically named\nbranch in the current branch, and both patches are topmost in their\nrespective applied stacks.\n\nThe second patch teaches \"delete\" how to delete multiple patches in\none go.\n\n-- \nKarl Hasselström, kha@treskal.com\n      www.treskal.com/kalle\n"},{"id":"29612","messageId":"20061022125811.15194.63337.stgit@localhost","threadId":"5997","inReplyTo":"20061022125337.15194.64831.stgit@localhost","subject":"[PATCH 1/2] Regression test for \"stg delete\"","fromName":"Karl Hasselström","fromEmail":"kha@treskal.com","sentAt":"2006-10-22T12:58:11Z","receivedAt":"2006-10-22T12:58:11Z","isPatch":true,"sender":{"key":"kha@treskal.com","avatar":"https://gravatar.com/avatar/f0120c734b5279b345075a28521e1ac66acb20c9913ffe9bf6ae97e53f7f3f13?d=mp&s=160"},"body":"From: Karl Hasselström <kha@treskal.com>\n\nNOTE: The subtest that attempts to delete a patch in another branch\ncurrently fails, because there's a bug in \"delete\".\n\nSigned-off-by: Karl Hasselström <kha@treskal.com>\n---\n\n t/t1600-delete.sh |  109 +++++++++++++++++++++++++++++++++++++++++++++++++++++\n 1 files changed, 109 insertions(+), 0 deletions(-)\n\ndiff --git a/t/t1600-delete.sh b/t/t1600-delete.sh\nnew file mode 100644\nindex 0000000..e22e624\n--- /dev/null\n+++ b/t/t1600-delete.sh\n@@ -0,0 +1,109 @@\n+#!/bin/sh\n+# Copyright (c) 2006 Karl Hasselström\n+test_description='Test the delete command.'\n+. ./test-lib.sh\n+\n+test_expect_success \\\n+    'Initialize the StGIT repository' \\\n+    'stg init'\n+\n+test_expect_success \\\n+    'Create a patch' \\\n+    '\n+    stg new foo -m foo &&\n+    echo foo > foo.txt &&\n+    stg add foo.txt &&\n+    stg refresh\n+    '\n+\n+test_expect_success \\\n+    'Try to delete a non-existing patch' \\\n+    '\n+    [ $(stg applied | wc -l) -eq 1 ] &&\n+    ! stg delete bar &&\n+    [ $(stg applied | wc -l) -eq 1 ]\n+    '\n+\n+test_expect_success \\\n+    'Try to delete the topmost patch while dirty' \\\n+    '\n+    echo dirty >> foo.txt &&\n+    [ $(stg applied | wc -l) -eq 1 ] &&\n+    ! stg delete foo &&\n+    [ $(stg applied | wc -l) -eq 1 ] &&\n+    git reset --hard\n+    '\n+\n+test_expect_success \\\n+    'Delete the topmost patch' \\\n+    '\n+    [ $(stg applied | wc -l) -eq 1 ] &&\n+    stg delete foo &&\n+    [ $(stg applied | wc -l) -eq 0 ]\n+    '\n+\n+test_expect_success \\\n+    'Create an unapplied patch' \\\n+    '\n+    stg new foo -m foo &&\n+    echo foo > foo.txt &&\n+    stg add foo.txt &&\n+    stg refresh &&\n+    stg pop\n+    '\n+\n+test_expect_success \\\n+    'Delete an unapplied patch' \\\n+    '\n+    [ $(stg unapplied | wc -l) -eq 1 ] &&\n+    stg delete foo &&\n+    [ $(stg unapplied | wc -l) -eq 0 ]\n+    '\n+\n+test_expect_success \\\n+    'Create two patches' \\\n+    '\n+    stg new foo -m foo &&\n+    echo foo > foo.txt &&\n+    stg add foo.txt &&\n+    stg refresh &&\n+    stg new bar -m bar &&\n+    echo bar > bar.txt &&\n+    stg add bar.txt &&\n+    stg refresh\n+    '\n+\n+test_expect_success \\\n+    'Try to delete a non-topmost applied patch' \\\n+    '\n+    [ $(stg applied | wc -l) -eq 2 ] &&\n+    ! stg delete foo &&\n+    [ $(stg applied | wc -l) -eq 2 ]\n+    '\n+\n+test_expect_success \\\n+    'Create another branch, and put one patch in each branch' \\\n+    '\n+    stg branch --create br &&\n+    stg new baz -m baz &&\n+    echo baz > baz.txt &&\n+    stg add baz.txt &&\n+    stg refresh &&\n+    stg branch master &&\n+    stg new baz -m baz &&\n+    echo baz > baz.txt &&\n+    stg add baz.txt &&\n+    stg refresh\n+    '\n+\n+test_expect_success \\\n+    'Delete a patch in another branch' \\\n+    '\n+    [ $(stg applied | wc -l) -eq 3 ] &&\n+    [ $(stg applied -b br | wc -l) -eq 1 ] &&\n+    stg delete -b br baz &&\n+    [ $(stg applied | wc -l) -eq 3 ] &&\n+    [ $(stg applied -b br | wc -l) -eq 0 ]\n+    '\n+\n+test_done\n"},{"id":"29614","messageId":"20061022125816.15194.3341.stgit@localhost","threadId":"5997","inReplyTo":"20061022125337.15194.64831.stgit@localhost","subject":"[PATCH 2/2] Allow deletion of several patches at once","fromName":"Karl Hasselström","fromEmail":"kha@treskal.com","sentAt":"2006-10-22T12:58:16Z","receivedAt":"2006-10-22T12:58:16Z","isPatch":true,"sender":{"key":"kha@treskal.com","avatar":"https://gravatar.com/avatar/f0120c734b5279b345075a28521e1ac66acb20c9913ffe9bf6ae97e53f7f3f13?d=mp&s=160"},"body":"From: Karl Hasselström <kha@treskal.com>\n\n\n\nSigned-off-by: Karl Hasselström <kha@treskal.com>\n---\n\n stgit/commands/delete.py |   50 ++++++++++++++++-----\n t/t1600-delete-one.sh    |  109 ++++++++++++++++++++++++++++++++++++++++++++++\n t/t1600-delete.sh        |  109 ----------------------------------------------\n t/t1601-delete-many.sh   |   45 +++++++++++++++++++\n 4 files changed, 193 insertions(+), 120 deletions(-)\n\ndiff --git a/stgit/commands/delete.py b/stgit/commands/delete.py\nindex c97d8ed..5617ca1 100644\n--- a/stgit/commands/delete.py\n+++ b/stgit/commands/delete.py\n@@ -24,13 +24,16 @@ from stgit.utils import *\n from stgit import stack, git\n \n \n-help = 'remove the topmost or any unapplied patch'\n-usage = \"\"\"%prog [options] <patch>\n+help = 'delete patches'\n+usage = \"\"\"%prog [options] <patch> [ <patch> [...] ]\n \n-Delete the patch passed as argument. The patch to be deleted can only\n-be part of the unapplied list or be the topmost one, in the latter\n-case the command also popping it from the stack. Note that the\n-'delete' operation is irreversible.\"\"\"\n+Delete the patches passed as arguments. If an applied patch is to be\n+deleted, all other patches applied on top of it must be deleted too;\n+and they must be explicitly specified, since this command will not try\n+to delete a patch unless you explicitly ask it to. If any applied\n+patches are deleted, they are popped from the stack.\n+\n+Note that the 'delete' operation is irreversible.\"\"\"\n \n options = [make_option('-b', '--branch',\n                        help = 'use BRANCH instead of the default one')]\n@@ -38,16 +41,41 @@ options = [make_option('-b', '--branch',\n def func(parser, options, args):\n     \"\"\"Deletes a patch\n     \"\"\"\n-    if len(args) != 1:\n-        parser.error('incorrect number of arguments')\n+    if not args:\n+        parser.error('no patches to delete')\n+\n+    applied = {}\n+    unapplied = {}\n+    dontexist = {}\n+    for patch in args:\n+        if patch in crt_series.get_unapplied():\n+            unapplied[patch] = None\n+        elif patch in crt_series.get_applied():\n+            applied[patch] = None\n+        else:\n+            dontexist[patch] = None\n \n-    if args[0] == crt_series.get_current():\n+    while crt_series.get_current() in applied:\n+        patch = crt_series.get_current()\n         check_local_changes()\n         check_conflicts()\n         check_head_top_equal()\n+        crt_series.delete_patch(patch)\n+        del applied[patch]\n+        print 'Patch \"%s\" successfully deleted' % patch\n+\n+    for patch in unapplied.iterkeys():\n+        crt_series.delete_patch(patch)\n+        print 'Patch \"%s\" successfully deleted' % patch\n+\n+    if dontexist:\n+        print 'Error: no such patch: %s' % ', '.join(dontexist.iterkeys())\n+    if applied:\n+        print 'Error: failed to delete %s' % ', '.join(applied.iterkeys())\n \n-    crt_series.delete_patch(args[0])\n-    print 'Patch \"%s\" successfully deleted' % args[0]\n+    failed = len(dontexist) + len(applied)\n+    if failed:\n+        raise CmdException, 'Failed to delete %d patches' % failed\n \n     if not options.branch:\n         print_crt_patch()\ndiff --git a/t/t1600-delete-one.sh b/t/t1600-delete-one.sh\nnew file mode 100644\nindex 0000000..df03d79\n--- /dev/null\n+++ b/t/t1600-delete-one.sh\n@@ -0,0 +1,109 @@\n+#!/bin/sh\n+# Copyright (c) 2006 Karl Hasselström\n+test_description='Test the delete command (deleting one patch at a time).'\n+. ./test-lib.sh\n+\n+test_expect_success \\\n+    'Initialize the StGIT repository' \\\n+    'stg init'\n+\n+test_expect_success \\\n+    'Create a patch' \\\n+    '\n+    stg new foo -m foo &&\n+    echo foo > foo.txt &&\n+    stg add foo.txt &&\n+    stg refresh\n+    '\n+\n+test_expect_success \\\n+    'Try to delete a non-existing patch' \\\n+    '\n+    [ $(stg applied | wc -l) -eq 1 ] &&\n+    ! stg delete bar &&\n+    [ $(stg applied | wc -l) -eq 1 ]\n+    '\n+\n+test_expect_success \\\n+    'Try to delete the topmost patch while dirty' \\\n+    '\n+    echo dirty >> foo.txt &&\n+    [ $(stg applied | wc -l) -eq 1 ] &&\n+    ! stg delete foo &&\n+    [ $(stg applied | wc -l) -eq 1 ] &&\n+    git reset --hard\n+    '\n+\n+test_expect_success \\\n+    'Delete the topmost patch' \\\n+    '\n+    [ $(stg applied | wc -l) -eq 1 ] &&\n+    stg delete foo &&\n+    [ $(stg applied | wc -l) -eq 0 ]\n+    '\n+\n+test_expect_success \\\n+    'Create an unapplied patch' \\\n+    '\n+    stg new foo -m foo &&\n+    echo foo > foo.txt &&\n+    stg add foo.txt &&\n+    stg refresh &&\n+    stg pop\n+    '\n+\n+test_expect_success \\\n+    'Delete an unapplied patch' \\\n+    '\n+    [ $(stg unapplied | wc -l) -eq 1 ] &&\n+    stg delete foo &&\n+    [ $(stg unapplied | wc -l) -eq 0 ]\n+    '\n+\n+test_expect_success \\\n+    'Create two patches' \\\n+    '\n+    stg new foo -m foo &&\n+    echo foo > foo.txt &&\n+    stg add foo.txt &&\n+    stg refresh &&\n+    stg new bar -m bar &&\n+    echo bar > bar.txt &&\n+    stg add bar.txt &&\n+    stg refresh\n+    '\n+\n+test_expect_success \\\n+    'Try to delete a non-topmost applied patch' \\\n+    '\n+    [ $(stg applied | wc -l) -eq 2 ] &&\n+    ! stg delete foo &&\n+    [ $(stg applied | wc -l) -eq 2 ]\n+    '\n+\n+test_expect_success \\\n+    'Create another branch, and put one patch in each branch' \\\n+    '\n+    stg branch --create br &&\n+    stg new baz -m baz &&\n+    echo baz > baz.txt &&\n+    stg add baz.txt &&\n+    stg refresh &&\n+    stg branch master &&\n+    stg new baz -m baz &&\n+    echo baz > baz.txt &&\n+    stg add baz.txt &&\n+    stg refresh\n+    '\n+\n+test_expect_success \\\n+    'Delete a patch in another branch' \\\n+    '\n+    [ $(stg applied | wc -l) -eq 3 ] &&\n+    [ $(stg applied -b br | wc -l) -eq 1 ] &&\n+    stg delete -b br baz &&\n+    [ $(stg applied | wc -l) -eq 3 ] &&\n+    [ $(stg applied -b br | wc -l) -eq 0 ]\n+    '\n+\n+test_done\ndiff --git a/t/t1600-delete.sh b/t/t1600-delete.sh\ndeleted file mode 100644\nindex e22e624..0000000\n--- a/t/t1600-delete.sh\n+++ /dev/null\n@@ -1,109 +0,0 @@\n-#!/bin/sh\n-# Copyright (c) 2006 Karl Hasselström\n-test_description='Test the delete command.'\n-. ./test-lib.sh\n-\n-test_expect_success \\\n-    'Initialize the StGIT repository' \\\n-    'stg init'\n-\n-test_expect_success \\\n-    'Create a patch' \\\n-    '\n-    stg new foo -m foo &&\n-    echo foo > foo.txt &&\n-    stg add foo.txt &&\n-    stg refresh\n-    '\n-\n-test_expect_success \\\n-    'Try to delete a non-existing patch' \\\n-    '\n-    [ $(stg applied | wc -l) -eq 1 ] &&\n-    ! stg delete bar &&\n-    [ $(stg applied | wc -l) -eq 1 ]\n-    '\n-\n-test_expect_success \\\n-    'Try to delete the topmost patch while dirty' \\\n-    '\n-    echo dirty >> foo.txt &&\n-    [ $(stg applied | wc -l) -eq 1 ] &&\n-    ! stg delete foo &&\n-    [ $(stg applied | wc -l) -eq 1 ] &&\n-    git reset --hard\n-    '\n-\n-test_expect_success \\\n-    'Delete the topmost patch' \\\n-    '\n-    [ $(stg applied | wc -l) -eq 1 ] &&\n-    stg delete foo &&\n-    [ $(stg applied | wc -l) -eq 0 ]\n-    '\n-\n-test_expect_success \\\n-    'Create an unapplied patch' \\\n-    '\n-    stg new foo -m foo &&\n-    echo foo > foo.txt &&\n-    stg add foo.txt &&\n-    stg refresh &&\n-    stg pop\n-    '\n-\n-test_expect_success \\\n-    'Delete an unapplied patch' \\\n-    '\n-    [ $(stg unapplied | wc -l) -eq 1 ] &&\n-    stg delete foo &&\n-    [ $(stg unapplied | wc -l) -eq 0 ]\n-    '\n-\n-test_expect_success \\\n-    'Create two patches' \\\n-    '\n-    stg new foo -m foo &&\n-    echo foo > foo.txt &&\n-    stg add foo.txt &&\n-    stg refresh &&\n-    stg new bar -m bar &&\n-    echo bar > bar.txt &&\n-    stg add bar.txt &&\n-    stg refresh\n-    '\n-\n-test_expect_success \\\n-    'Try to delete a non-topmost applied patch' \\\n-    '\n-    [ $(stg applied | wc -l) -eq 2 ] &&\n-    ! stg delete foo &&\n-    [ $(stg applied | wc -l) -eq 2 ]\n-    '\n-\n-test_expect_success \\\n-    'Create another branch, and put one patch in each branch' \\\n-    '\n-    stg branch --create br &&\n-    stg new baz -m baz &&\n-    echo baz > baz.txt &&\n-    stg add baz.txt &&\n-    stg refresh &&\n-    stg branch master &&\n-    stg new baz -m baz &&\n-    echo baz > baz.txt &&\n-    stg add baz.txt &&\n-    stg refresh\n-    '\n-\n-test_expect_success \\\n-    'Delete a patch in another branch' \\\n-    '\n-    [ $(stg applied | wc -l) -eq 3 ] &&\n-    [ $(stg applied -b br | wc -l) -eq 1 ] &&\n-    stg delete -b br baz &&\n-    [ $(stg applied | wc -l) -eq 3 ] &&\n-    [ $(stg applied -b br | wc -l) -eq 0 ]\n-    '\n-\n-test_done\ndiff --git a/t/t1601-delete-many.sh b/t/t1601-delete-many.sh\nnew file mode 100644\nindex 0000000..f217804\n--- /dev/null\n+++ b/t/t1601-delete-many.sh\n@@ -0,0 +1,45 @@\n+#!/bin/sh\n+# Copyright (c) 2006 Karl Hasselström\n+test_description='Test the delete command (deleting many patches at once).'\n+. ./test-lib.sh\n+\n+test_expect_success \\\n+    'Initialize the StGIT repository' \\\n+    'stg init'\n+\n+test_expect_success \\\n+    'Create five applied and five unapplied patches' \\\n+    '\n+    stg new foo0 -m foo0 &&\n+    echo foo0 > foo.txt &&\n+    stg add foo.txt &&\n+    stg refresh &&\n+    for i in 1 2 3 4 5 6 7 8 9; do\n+        stg new foo$i -m foo$i &&\n+        echo foo$i >> foo.txt &&\n+        stg refresh;\n+    done &&\n+    stg pop -n 5\n+    '\n+\n+test_expect_success \\\n+    'Delete some patches' \\\n+    '\n+    [ $(stg applied | wc -l) -eq 5 ] &&\n+    [ $(stg unapplied | wc -l) -eq 5 ] &&\n+    stg delete foo7 foo6 foo3 foo4 &&\n+    [ $(stg applied | wc -l) -eq 3 ] &&\n+    [ $(stg unapplied | wc -l) -eq 3 ]\n+    '\n+\n+test_expect_success \\\n+    'Delete some more patches, some of which fail' \\\n+    '\n+    [ $(stg applied | wc -l) -eq 3 ] &&\n+    [ $(stg unapplied | wc -l) -eq 3 ] &&\n+    ! stg delete foo7 foo8 foo2 foo0 &&\n+    [ $(stg applied | wc -l) -eq 2 ] &&\n+    [ $(stg unapplied | wc -l) -eq 2 ]\n+    '\n+\n+test_done\n"},{"id":"29615","messageId":"20061022130145.GB21084@diana.vm.bytemark.co.uk","threadId":"5997","inReplyTo":"20061022125816.15194.3341.stgit@localhost","subject":"Re: [PATCH 2/2] Allow deletion of several patches at once","fromName":"Karl Hasselström","fromEmail":"kha@treskal.com","sentAt":"2006-10-22T13:01:45Z","receivedAt":"2006-10-22T13:01:45Z","isPatch":true,"sender":{"key":"kha@treskal.com","avatar":"https://gravatar.com/avatar/f0120c734b5279b345075a28521e1ac66acb20c9913ffe9bf6ae97e53f7f3f13?d=mp&s=160"},"body":"On 2006-10-22 14:58:16 +0200, Karl Hasselström wrote:\n\n>  t/t1600-delete-one.sh    |  109 ++++++++++++++++++++++++++++++++++++++++++++++\n>  t/t1600-delete.sh        |  109 ----------------------------------------------\n\nBy the way, this is why I complained about StGIT's lack of rename\nsupport earlier. This is a file move with maybe three of 109 lines\nchanged, but you won't be able to see that without importing the patch\nand examining it with the git tools. :-(\n\n-- \nKarl Hasselström, kha@treskal.com\n      www.treskal.com/kalle\n"},{"id":"29712","messageId":"b0943d9e0610230457l2ff82a05pd9c7eddfcfac68f2@mail.gmail.com","threadId":"5997","inReplyTo":"20061022125816.15194.3341.stgit@localhost","subject":"Re: [PATCH 2/2] Allow deletion of several patches at once","fromName":"Catalin Marinas","fromEmail":"catalin.marinas@gmail.com","sentAt":"2006-10-23T11:57:03Z","receivedAt":"2006-10-23T11:57:03Z","isPatch":true,"sender":{"key":"catalin.marinas@gmail.com","avatar":null},"body":"On 22/10/06, Karl Hasselström <kha@treskal.com> wrote:\n> +    applied = {}\n> +    unapplied = {}\n> +    dontexist = {}\n> +    for patch in args:\n\nAny reason for not using the parse_patches() function in\nstgit.command.common? It allows one to specify patch ranges like\npatch1..patch2. Have a look at how it is used for the push or float\ncommands.\n\n-- \nCatalin\n"},{"id":"29713","messageId":"20061023123714.GB10872@diana.vm.bytemark.co.uk","threadId":"5997","inReplyTo":"b0943d9e0610230457l2ff82a05pd9c7eddfcfac68f2@mail.gmail.com","subject":"Re: [PATCH 2/2] Allow deletion of several patches at once","fromName":"Karl Hasselström","fromEmail":"kha@treskal.com","sentAt":"2006-10-23T12:37:14Z","receivedAt":"2006-10-23T12:37:14Z","isPatch":true,"sender":{"key":"kha@treskal.com","avatar":"https://gravatar.com/avatar/f0120c734b5279b345075a28521e1ac66acb20c9913ffe9bf6ae97e53f7f3f13?d=mp&s=160"},"body":"On 2006-10-23 12:57:03 +0100, Catalin Marinas wrote:\n\n> On 22/10/06, Karl Hasselström <kha@treskal.com> wrote:\n>\n> > +    applied = {}\n> > +    unapplied = {}\n> > +    dontexist = {}\n> > +    for patch in args:\n>\n> Any reason for not using the parse_patches() function in\n> stgit.command.common? It allows one to specify patch ranges like\n> patch1..patch2. Have a look at how it is used for the push or float\n> commands.\n\nAh, no, I just didn't know it existed. I'll send an updated patch (but\nit may be a few days).\n\n-- \nKarl Hasselström, kha@treskal.com\n      www.treskal.com/kalle\n"},{"id":"295275","messageId":"20061101090714.2066.93948.stgit@localhost","threadId":"5997","inReplyTo":"20061023123714.GB10872@diana.vm.bytemark.co.uk","subject":"[PATCH] Allow deletion of several patches at once","fromName":"Karl Hasselström","fromEmail":"kha@treskal.com","sentAt":"2006-11-01T09:07:14Z","receivedAt":"2006-11-01T09:07:14Z","isPatch":true,"sender":{"key":"kha@treskal.com","avatar":"https://gravatar.com/avatar/f0120c734b5279b345075a28521e1ac66acb20c9913ffe9bf6ae97e53f7f3f13?d=mp&s=160"},"body":"From: Karl Hasselström <kha@treskal.com>\n\nSigned-off-by: Karl Hasselström <kha@treskal.com>\n---\n\nThis is an updated patch, which uses parse_patches() to support patch\nranges. It replaces patch 2/2 in the series; patch 1/2 (original\ndelete regression test) is unaffected.\n\n stgit/commands/delete.py |   54 +++++++++++++++++------\n t/t1600-delete-one.sh    |  109 ++++++++++++++++++++++++++++++++++++++++++++++\n t/t1600-delete.sh        |  109 ----------------------------------------------\n t/t1601-delete-many.sh   |   55 +++++++++++++++++++++++\n 4 files changed, 205 insertions(+), 122 deletions(-)\n\ndiff --git a/stgit/commands/delete.py b/stgit/commands/delete.py\nindex c97d8ed..2f3aece 100644\n--- a/stgit/commands/delete.py\n+++ b/stgit/commands/delete.py\n@@ -24,30 +24,58 @@ from stgit.utils import *\n from stgit import stack, git\n \n \n-help = 'remove the topmost or any unapplied patch'\n-usage = \"\"\"%prog [options] <patch>\n+help = 'delete patches'\n+usage = \"\"\"%prog [options] [<patch1>] [<patch2>] [<patch3>..<patch4>]\n \n-Delete the patch passed as argument. The patch to be deleted can only\n-be part of the unapplied list or be the topmost one, in the latter\n-case the command also popping it from the stack. Note that the\n-'delete' operation is irreversible.\"\"\"\n+Delete the patches passed as arguments. If an applied patch is to be\n+deleted, all other patches applied on top of it must be deleted too;\n+and they must be explicitly specified, since this command will not try\n+to delete a patch unless you explicitly ask it to. If any applied\n+patches are deleted, they are popped from the stack.\n+\n+Note that the 'delete' operation is irreversible.\"\"\"\n \n options = [make_option('-b', '--branch',\n                        help = 'use BRANCH instead of the default one')]\n \n def func(parser, options, args):\n-    \"\"\"Deletes a patch\n-    \"\"\"\n-    if len(args) != 1:\n-        parser.error('incorrect number of arguments')\n+    \"\"\"Deletes one or more patches.\"\"\"\n+    applied_patches = crt_series.get_applied()\n+    unapplied_patches = crt_series.get_unapplied()\n+    all_patches = applied_patches + unapplied_patches\n+\n+    if args:\n+        patches = parse_patches(args, all_patches)\n+    else:\n+        parser.error('No patches specified')\n+\n+    applied = {}\n+    unapplied = {}\n+    for patch in patches:\n+        if patch in unapplied_patches:\n+            unapplied[patch] = None\n+        else:\n+            applied[patch] = None\n \n-    if args[0] == crt_series.get_current():\n+    while crt_series.get_current() in applied:\n+        patch = crt_series.get_current()\n         check_local_changes()\n         check_conflicts()\n         check_head_top_equal()\n+        crt_series.delete_patch(patch)\n+        del applied[patch]\n+        print 'Patch \"%s\" successfully deleted' % patch\n+\n+    for patch in unapplied.iterkeys():\n+        crt_series.delete_patch(patch)\n+        print 'Patch \"%s\" successfully deleted' % patch\n+\n+    if applied:\n+        print 'Error: failed to delete %s' % ', '.join(applied.iterkeys())\n \n-    crt_series.delete_patch(args[0])\n-    print 'Patch \"%s\" successfully deleted' % args[0]\n+    failed = len(applied)\n+    if failed:\n+        raise CmdException, 'Failed to delete %d patches' % failed\n \n     if not options.branch:\n         print_crt_patch()\ndiff --git a/t/t1600-delete-one.sh b/t/t1600-delete-one.sh\nnew file mode 100644\nindex 0000000..df03d79\n--- /dev/null\n+++ b/t/t1600-delete-one.sh\n@@ -0,0 +1,109 @@\n+#!/bin/sh\n+# Copyright (c) 2006 Karl Hasselström\n+test_description='Test the delete command (deleting one patch at a time).'\n+. ./test-lib.sh\n+\n+test_expect_success \\\n+    'Initialize the StGIT repository' \\\n+    'stg init'\n+\n+test_expect_success \\\n+    'Create a patch' \\\n+    '\n+    stg new foo -m foo &&\n+    echo foo > foo.txt &&\n+    stg add foo.txt &&\n+    stg refresh\n+    '\n+\n+test_expect_success \\\n+    'Try to delete a non-existing patch' \\\n+    '\n+    [ $(stg applied | wc -l) -eq 1 ] &&\n+    ! stg delete bar &&\n+    [ $(stg applied | wc -l) -eq 1 ]\n+    '\n+\n+test_expect_success \\\n+    'Try to delete the topmost patch while dirty' \\\n+    '\n+    echo dirty >> foo.txt &&\n+    [ $(stg applied | wc -l) -eq 1 ] &&\n+    ! stg delete foo &&\n+    [ $(stg applied | wc -l) -eq 1 ] &&\n+    git reset --hard\n+    '\n+\n+test_expect_success \\\n+    'Delete the topmost patch' \\\n+    '\n+    [ $(stg applied | wc -l) -eq 1 ] &&\n+    stg delete foo &&\n+    [ $(stg applied | wc -l) -eq 0 ]\n+    '\n+\n+test_expect_success \\\n+    'Create an unapplied patch' \\\n+    '\n+    stg new foo -m foo &&\n+    echo foo > foo.txt &&\n+    stg add foo.txt &&\n+    stg refresh &&\n+    stg pop\n+    '\n+\n+test_expect_success \\\n+    'Delete an unapplied patch' \\\n+    '\n+    [ $(stg unapplied | wc -l) -eq 1 ] &&\n+    stg delete foo &&\n+    [ $(stg unapplied | wc -l) -eq 0 ]\n+    '\n+\n+test_expect_success \\\n+    'Create two patches' \\\n+    '\n+    stg new foo -m foo &&\n+    echo foo > foo.txt &&\n+    stg add foo.txt &&\n+    stg refresh &&\n+    stg new bar -m bar &&\n+    echo bar > bar.txt &&\n+    stg add bar.txt &&\n+    stg refresh\n+    '\n+\n+test_expect_success \\\n+    'Try to delete a non-topmost applied patch' \\\n+    '\n+    [ $(stg applied | wc -l) -eq 2 ] &&\n+    ! stg delete foo &&\n+    [ $(stg applied | wc -l) -eq 2 ]\n+    '\n+\n+test_expect_success \\\n+    'Create another branch, and put one patch in each branch' \\\n+    '\n+    stg branch --create br &&\n+    stg new baz -m baz &&\n+    echo baz > baz.txt &&\n+    stg add baz.txt &&\n+    stg refresh &&\n+    stg branch master &&\n+    stg new baz -m baz &&\n+    echo baz > baz.txt &&\n+    stg add baz.txt &&\n+    stg refresh\n+    '\n+\n+test_expect_success \\\n+    'Delete a patch in another branch' \\\n+    '\n+    [ $(stg applied | wc -l) -eq 3 ] &&\n+    [ $(stg applied -b br | wc -l) -eq 1 ] &&\n+    stg delete -b br baz &&\n+    [ $(stg applied | wc -l) -eq 3 ] &&\n+    [ $(stg applied -b br | wc -l) -eq 0 ]\n+    '\n+\n+test_done\ndiff --git a/t/t1600-delete.sh b/t/t1600-delete.sh\ndeleted file mode 100644\nindex e22e624..0000000\n--- a/t/t1600-delete.sh\n+++ /dev/null\n@@ -1,109 +0,0 @@\n-#!/bin/sh\n-# Copyright (c) 2006 Karl Hasselström\n-test_description='Test the delete command.'\n-. ./test-lib.sh\n-\n-test_expect_success \\\n-    'Initialize the StGIT repository' \\\n-    'stg init'\n-\n-test_expect_success \\\n-    'Create a patch' \\\n-    '\n-    stg new foo -m foo &&\n-    echo foo > foo.txt &&\n-    stg add foo.txt &&\n-    stg refresh\n-    '\n-\n-test_expect_success \\\n-    'Try to delete a non-existing patch' \\\n-    '\n-    [ $(stg applied | wc -l) -eq 1 ] &&\n-    ! stg delete bar &&\n-    [ $(stg applied | wc -l) -eq 1 ]\n-    '\n-\n-test_expect_success \\\n-    'Try to delete the topmost patch while dirty' \\\n-    '\n-    echo dirty >> foo.txt &&\n-    [ $(stg applied | wc -l) -eq 1 ] &&\n-    ! stg delete foo &&\n-    [ $(stg applied | wc -l) -eq 1 ] &&\n-    git reset --hard\n-    '\n-\n-test_expect_success \\\n-    'Delete the topmost patch' \\\n-    '\n-    [ $(stg applied | wc -l) -eq 1 ] &&\n-    stg delete foo &&\n-    [ $(stg applied | wc -l) -eq 0 ]\n-    '\n-\n-test_expect_success \\\n-    'Create an unapplied patch' \\\n-    '\n-    stg new foo -m foo &&\n-    echo foo > foo.txt &&\n-    stg add foo.txt &&\n-    stg refresh &&\n-    stg pop\n-    '\n-\n-test_expect_success \\\n-    'Delete an unapplied patch' \\\n-    '\n-    [ $(stg unapplied | wc -l) -eq 1 ] &&\n-    stg delete foo &&\n-    [ $(stg unapplied | wc -l) -eq 0 ]\n-    '\n-\n-test_expect_success \\\n-    'Create two patches' \\\n-    '\n-    stg new foo -m foo &&\n-    echo foo > foo.txt &&\n-    stg add foo.txt &&\n-    stg refresh &&\n-    stg new bar -m bar &&\n-    echo bar > bar.txt &&\n-    stg add bar.txt &&\n-    stg refresh\n-    '\n-\n-test_expect_success \\\n-    'Try to delete a non-topmost applied patch' \\\n-    '\n-    [ $(stg applied | wc -l) -eq 2 ] &&\n-    ! stg delete foo &&\n-    [ $(stg applied | wc -l) -eq 2 ]\n-    '\n-\n-test_expect_success \\\n-    'Create another branch, and put one patch in each branch' \\\n-    '\n-    stg branch --create br &&\n-    stg new baz -m baz &&\n-    echo baz > baz.txt &&\n-    stg add baz.txt &&\n-    stg refresh &&\n-    stg branch master &&\n-    stg new baz -m baz &&\n-    echo baz > baz.txt &&\n-    stg add baz.txt &&\n-    stg refresh\n-    '\n-\n-test_expect_success \\\n-    'Delete a patch in another branch' \\\n-    '\n-    [ $(stg applied | wc -l) -eq 3 ] &&\n-    [ $(stg applied -b br | wc -l) -eq 1 ] &&\n-    stg delete -b br baz &&\n-    [ $(stg applied | wc -l) -eq 3 ] &&\n-    [ $(stg applied -b br | wc -l) -eq 0 ]\n-    '\n-\n-test_done\ndiff --git a/t/t1601-delete-many.sh b/t/t1601-delete-many.sh\nnew file mode 100644\nindex 0000000..8648ed1\n--- /dev/null\n+++ b/t/t1601-delete-many.sh\n@@ -0,0 +1,55 @@\n+#!/bin/sh\n+# Copyright (c) 2006 Karl Hasselström\n+test_description='Test the delete command (deleting many patches at once).'\n+. ./test-lib.sh\n+\n+test_expect_success \\\n+    'Initialize the StGIT repository' \\\n+    'stg init'\n+\n+test_expect_success \\\n+    'Create five applied and five unapplied patches' \\\n+    '\n+    stg new foo0 -m foo0 &&\n+    echo foo0 > foo.txt &&\n+    stg add foo.txt &&\n+    stg refresh &&\n+    for i in 1 2 3 4 5 6 7 8 9; do\n+        stg new foo$i -m foo$i &&\n+        echo foo$i >> foo.txt &&\n+        stg refresh;\n+    done &&\n+    stg pop -n 5\n+    '\n+\n+test_expect_success \\\n+    'Delete some patches' \\\n+    '\n+    [ $(stg applied | wc -l) -eq 5 ] &&\n+    [ $(stg unapplied | wc -l) -eq 5 ] &&\n+    stg delete foo7 foo6 foo3 foo4 &&\n+    [ $(stg applied | wc -l) -eq 3 ] &&\n+    [ $(stg unapplied | wc -l) -eq 3 ]\n+    '\n+\n+test_expect_success \\\n+    'Delete some more patches, some of which do not exist' \\\n+    '\n+    [ $(stg applied | wc -l) -eq 3 ] &&\n+    [ $(stg unapplied | wc -l) -eq 3 ] &&\n+    ! stg delete foo7 foo8 foo2 foo0 &&\n+    [ $(stg applied | wc -l) -eq 3 ] &&\n+    [ $(stg unapplied | wc -l) -eq 3 ]\n+    '\n+\n+test_expect_success \\\n+    'Delete a range of patches' \\\n+    '\n+    [ $(stg applied | wc -l) -eq 3 ] &&\n+    [ $(stg unapplied | wc -l) -eq 3 ] &&\n+    stg delete foo1..foo8 &&\n+    [ $(stg applied | wc -l) -eq 1 ] &&\n+    [ $(stg unapplied | wc -l) -eq 1 ]\n+    '\n+\n"},{"id":"294943","messageId":"b0943d9e0611020236p60859a97ide18b95a2e069b1b@mail.gmail.com","threadId":"5997","inReplyTo":"20061101090714.2066.93948.stgit@localhost","subject":"Re: [PATCH] Allow deletion of several patches at once","fromName":"Catalin Marinas","fromEmail":"catalin.marinas@gmail.com","sentAt":"2006-11-02T10:36:51Z","receivedAt":"2006-11-02T10:36:51Z","isPatch":true,"sender":{"key":"catalin.marinas@gmail.com","avatar":null},"body":"On 01/11/06, Karl Hasselström <kha@treskal.com> wrote:\n> This is an updated patch, which uses parse_patches() to support patch\n> ranges. It replaces patch 2/2 in the series; patch 1/2 (original\n> delete regression test) is unaffected.\n\nI applied it but added another commit to change the algorithm\nslightly. It now first checks whether the applied patches can be\ndeleted before deleting any patch (I find this safer). It also checks\nfor local changes, conflicts and HEAD == top only if you delete\napplied patches on the current branch. Actually, the HEAD == top test\nfailed when deleting on a different branch, which is normal since the\ntop is that of the other branch.\n\nI'll make the changes public tonight.\n\nThanks.\n\n-- \n"}]}