{"thread":{"id":"11285","subject":"[StGit PATCH 0/5] More experimental patches","startedAt":"2007-12-14T06:32:07Z","lastAt":"2007-12-14T06:32:36Z","messageCount":6,"participants":["Karl Hasselström"],"isPatch":true,"patchVersion":1,"patchTotal":5},"messages":[{"id":"63102","messageId":"20071214062618.29290.70792.stgit@yoghurt","threadId":"11285","inReplyTo":null,"subject":"[StGit PATCH 0/5] More experimental patches","fromName":"Karl Hasselström","fromEmail":"kha@treskal.com","sentAt":"2007-12-14T06:32:07Z","receivedAt":"2007-12-14T06:32:07Z","isPatch":true,"sender":{"key":"kha@treskal.com","avatar":"https://gravatar.com/avatar/f0120c734b5279b345075a28521e1ac66acb20c9913ffe9bf6ae97e53f7f3f13?d=mp&s=160"},"body":"Also available from\n\n  git://repo.or.cz/stgit/kha.git experimental\n\nHowever, the experimentalness is getting decidedly low. And now that\nwe just had a release, I have just one more thing I intend to take a\nlook at -- subdirectory safeness -- before I'm going to transfer all\nthe \"experimental\" patches to \"safe\", wholesale.\n\nSo if anyone knows of problems that would make this a bad idea, please\nsay so.\n\n---\n\nKarl Hasselström (5):\n      Make \"stg commit\" fancier\n      Convert \"stg commit\" to new infrastructure\n      Set exit code to 3 on merge conflict\n      stg coalesce: Support --file and --save-template\n      Expose transaction abort function\n\n\n stgit/commands/coalesce.py |   32 ++++++++-----\n stgit/commands/commit.py   |  111 ++++++++++++++++++++++++++++----------------\n stgit/commands/goto.py     |    2 -\n stgit/commands/uncommit.py |    2 -\n stgit/lib/transaction.py   |   24 ++++++++--\n stgit/main.py              |    4 +-\n stgit/utils.py             |    1 \n t/t1300-uncommit.sh        |   12 ++---\n 8 files changed, 121 insertions(+), 67 deletions(-)\n\n-- \nKarl Hasselström, kha@treskal.com\n      www.treskal.com/kalle\n"},{"id":"63104","messageId":"20071214063213.29290.54202.stgit@yoghurt","threadId":"11285","inReplyTo":"20071214062618.29290.70792.stgit@yoghurt","subject":"[StGit PATCH 1/5] Expose transaction abort function","fromName":"Karl Hasselström","fromEmail":"kha@treskal.com","sentAt":"2007-12-14T06:32:13Z","receivedAt":"2007-12-14T06:32:13Z","isPatch":true,"sender":{"key":"kha@treskal.com","avatar":"https://gravatar.com/avatar/f0120c734b5279b345075a28521e1ac66acb20c9913ffe9bf6ae97e53f7f3f13?d=mp&s=160"},"body":"Users of stack transactions may call abort() instead of run(), if they\nwish to roll back the transaction instead of committing it.\n\nSigned-off-by: Karl Hasselström <kha@treskal.com>\n\n---\n\n stgit/lib/transaction.py |    9 ++++++---\n 1 files changed, 6 insertions(+), 3 deletions(-)\n\n\ndiff --git a/stgit/lib/transaction.py b/stgit/lib/transaction.py\nindex 77333b3..663d393 100644\n--- a/stgit/lib/transaction.py\n+++ b/stgit/lib/transaction.py\n@@ -77,6 +77,10 @@ class StackTransaction(object):\n             return self.__patches[self.__applied[-1]]\n         else:\n             return self.__stack.base\n+    def abort(self, iw = None):\n+        # The only state we need to restore is index+worktree.\n+        if iw:\n+            self.__checkout(self.__stack.head.data.tree, iw)\n     def run(self, iw = None):\n         self.__check_consistency()\n         new_head = self.__head\n@@ -85,9 +89,8 @@ class StackTransaction(object):\n         try:\n             self.__checkout(new_head.data.tree, iw)\n         except git.CheckoutException:\n-            # We have to abort the transaction. The only state we need\n-            # to restore is index+worktree.\n-            self.__checkout(self.__stack.head.data.tree, iw)\n+            # We have to abort the transaction.\n+            self.abort(iw)\n             self.__abort()\n         self.__stack.set_head(new_head, self.__msg)\n \n"},{"id":"63103","messageId":"20071214063219.29290.24743.stgit@yoghurt","threadId":"11285","inReplyTo":"20071214062618.29290.70792.stgit@yoghurt","subject":"[StGit PATCH 2/5] stg coalesce: Support --file and --save-template","fromName":"Karl Hasselström","fromEmail":"kha@treskal.com","sentAt":"2007-12-14T06:32:19Z","receivedAt":"2007-12-14T06:32:19Z","isPatch":true,"sender":{"key":"kha@treskal.com","avatar":"https://gravatar.com/avatar/f0120c734b5279b345075a28521e1ac66acb20c9913ffe9bf6ae97e53f7f3f13?d=mp&s=160"},"body":"--save-template was a bit tricky, because we want that\n\n  * if we reached the stage where the message is needed without\n    conflicts, the message should be written and no other side effects\n    should occur; but\n\n  * if we run into conflicts before reaching that point, behave just\n    as if --save-template was not given.\n\nThis makes this script\n\n  stg coalesce --save-template <patches>\n  if template was saved:\n    let user edit template\n    if user didn't abort:\n      stg coalesce --file <patches>\n\nequivalent to\n\n  stg coalesce <patches>\n\nwith the added benefit that the user can abort the whole thing without\nvisible side effects.\n\nSigned-off-by: Karl Hasselström <kha@treskal.com>\n\n---\n\n stgit/commands/coalesce.py |   28 +++++++++++++++++++---------\n 1 files changed, 19 insertions(+), 9 deletions(-)\n\n\ndiff --git a/stgit/commands/coalesce.py b/stgit/commands/coalesce.py\nindex e3e1629..2330231 100644\n--- a/stgit/commands/coalesce.py\n+++ b/stgit/commands/coalesce.py\n@@ -34,11 +34,13 @@ you specify, you will have to resolve them manually just as if you had\n done a sequence of pushes and pops yourself.\"\"\"\n \n directory = common.DirectoryHasRepositoryLib()\n-options = [make_option('-n', '--name', help = 'name of coalesced patch'),\n-           make_option('-m', '--message',\n-                       help = 'commit message of coalesced patch')]\n+options = [make_option('-n', '--name', help = 'name of coalesced patch')\n+           ] + utils.make_message_options()\n \n-def _coalesce_patches(trans, patches, msg):\n+class SaveTemplateDone(Exception):\n+    pass\n+\n+def _coalesce_patches(trans, patches, msg, save_template):\n     cd = trans.patches[patches[0]].data\n     cd = git.Commitdata(tree = cd.tree, parents = cd.parents)\n     for pn in patches[1:]:\n@@ -53,12 +55,16 @@ def _coalesce_patches(trans, patches, msg):\n         msg = '\\n\\n'.join('%s\\n\\n%s' % (pn.ljust(70, '-'),\n                                         trans.patches[pn].data.message)\n                           for pn in patches)\n-        msg = utils.edit_string(msg, '.stgit-coalesce.txt').strip()\n+        if save_template:\n+            save_template(msg)\n+            raise SaveTemplateDone()\n+        else:\n+            msg = utils.edit_string(msg, '.stgit-coalesce.txt').strip()\n     cd = cd.set_message(msg)\n \n     return cd\n \n-def _coalesce(stack, iw, name, msg, patches):\n+def _coalesce(stack, iw, name, msg, save_template, patches):\n \n     # If a name was supplied on the command line, make sure it's OK.\n     def bad_name(pn):\n@@ -75,8 +81,8 @@ def _coalesce(stack, iw, name, msg, patches):\n \n     trans = transaction.StackTransaction(stack, 'stg coalesce')\n     push_new_patch = bool(set(patches) & set(trans.applied))\n-    new_commit_data = _coalesce_patches(trans, patches, msg)\n     try:\n+        new_commit_data = _coalesce_patches(trans, patches, msg, save_template)\n         if new_commit_data:\n             # We were able to construct the coalesced commit\n             # automatically. So just delete its constituent patches.\n@@ -88,7 +94,8 @@ def _coalesce(stack, iw, name, msg, patches):\n             to_push = trans.pop_patches(lambda pn: pn in patches)\n             for pn in patches:\n                 trans.push_patch(pn, iw)\n-            new_commit_data = _coalesce_patches(trans, patches, msg)\n+            new_commit_data = _coalesce_patches(trans, patches, msg,\n+                                                save_template)\n             assert not trans.delete_patches(lambda pn: pn in patches)\n         make_coalesced_patch(trans, new_commit_data)\n \n@@ -98,6 +105,9 @@ def _coalesce(stack, iw, name, msg, patches):\n             trans.push_patch(get_name(new_commit_data), iw)\n         for pn in to_push:\n             trans.push_patch(pn, iw)\n+    except SaveTemplateDone:\n+        trans.abort(iw)\n+        return\n     except transaction.TransactionHalted:\n         pass\n     trans.run(iw)\n@@ -109,4 +119,4 @@ def func(parser, options, args):\n     if len(patches) < 2:\n         raise common.CmdException('Need at least two patches')\n     _coalesce(stack, stack.repository.default_iw(),\n-              options.name, options.message, patches)\n+              options.name, options.message, options.save_template, patches)\n"},{"id":"63105","messageId":"20071214063224.29290.45251.stgit@yoghurt","threadId":"11285","inReplyTo":"20071214062618.29290.70792.stgit@yoghurt","subject":"[StGit PATCH 3/5] Set exit code to 3 on merge conflict","fromName":"Karl Hasselström","fromEmail":"kha@treskal.com","sentAt":"2007-12-14T06:32:24Z","receivedAt":"2007-12-14T06:32:24Z","isPatch":true,"sender":{"key":"kha@treskal.com","avatar":"https://gravatar.com/avatar/f0120c734b5279b345075a28521e1ac66acb20c9913ffe9bf6ae97e53f7f3f13?d=mp&s=160"},"body":"Signed-off-by: Karl Hasselström <kha@treskal.com>\n\n---\n\n stgit/commands/coalesce.py |    6 +++---\n stgit/commands/goto.py     |    2 +-\n stgit/lib/transaction.py   |    7 ++++++-\n stgit/main.py              |    4 ++--\n stgit/utils.py             |    1 +\n 5 files changed, 13 insertions(+), 7 deletions(-)\n\n\ndiff --git a/stgit/commands/coalesce.py b/stgit/commands/coalesce.py\nindex 2330231..d2cba3e 100644\n--- a/stgit/commands/coalesce.py\n+++ b/stgit/commands/coalesce.py\n@@ -110,7 +110,7 @@ def _coalesce(stack, iw, name, msg, save_template, patches):\n         return\n     except transaction.TransactionHalted:\n         pass\n-    trans.run(iw)\n+    return trans.run(iw)\n \n def func(parser, options, args):\n     stack = directory.repository.current_stack\n@@ -118,5 +118,5 @@ def func(parser, options, args):\n                                           + list(stack.patchorder.unapplied)))\n     if len(patches) < 2:\n         raise common.CmdException('Need at least two patches')\n-    _coalesce(stack, stack.repository.default_iw(),\n-              options.name, options.message, options.save_template, patches)\n+    return _coalesce(stack, stack.repository.default_iw(), options.name,\n+                     options.message, options.save_template, patches)\ndiff --git a/stgit/commands/goto.py b/stgit/commands/goto.py\nindex d78929d..763a8af 100644\n--- a/stgit/commands/goto.py\n+++ b/stgit/commands/goto.py\n@@ -48,4 +48,4 @@ def func(parser, options, args):\n             pass\n     else:\n         raise common.CmdException('Patch \"%s\" does not exist' % patch)\n-    trans.run(iw)\n+    return trans.run(iw)\ndiff --git a/stgit/lib/transaction.py b/stgit/lib/transaction.py\nindex 663d393..0ca647e 100644\n--- a/stgit/lib/transaction.py\n+++ b/stgit/lib/transaction.py\n@@ -1,4 +1,4 @@\n-from stgit import exception\n+from stgit import exception, utils\n from stgit.out import *\n from stgit.lib import git\n \n@@ -111,6 +111,11 @@ class StackTransaction(object):\n         self.__stack.patchorder.applied = self.__applied\n         self.__stack.patchorder.unapplied = self.__unapplied\n \n+        if self.__error:\n+            return utils.STGIT_CONFLICT\n+        else:\n+            return utils.STGIT_SUCCESS\n+\n     def __halt(self, msg):\n         self.__error = msg\n         raise TransactionHalted(msg)\ndiff --git a/stgit/main.py b/stgit/main.py\nindex a95eeb9..2577693 100644\n--- a/stgit/main.py\n+++ b/stgit/main.py\n@@ -273,7 +273,7 @@ def main():\n             else:\n                 command.crt_series = Series()\n \n-        command.func(parser, options, args)\n+        ret = command.func(parser, options, args)\n     except (StgException, IOError, ParsingError, NoSectionError), err:\n         out.error(str(err), title = '%s %s' % (prog, cmd))\n         if debug_level > 0:\n@@ -283,4 +283,4 @@ def main():\n     except KeyboardInterrupt:\n         sys.exit(utils.STGIT_GENERAL_ERROR)\n \n-    sys.exit(utils.STGIT_SUCCESS)\n+    sys.exit(ret or utils.STGIT_SUCCESS)\ndiff --git a/stgit/utils.py b/stgit/utils.py\nindex 6568da5..2ff1d74 100644\n--- a/stgit/utils.py\n+++ b/stgit/utils.py\n@@ -317,6 +317,7 @@ def make_message_options():\n STGIT_SUCCESS = 0        # everything's OK\n STGIT_GENERAL_ERROR = 1  # seems to be non-command-specific error\n STGIT_COMMAND_ERROR = 2  # seems to be a command that failed\n+STGIT_CONFLICT = 3       # merge conflict, otherwise OK\n \n def strip_leading(prefix, s):\n     \"\"\"Strip leading prefix from a string. Blow up if the prefix isn't\n"},{"id":"63107","messageId":"20071214063230.29290.22561.stgit@yoghurt","threadId":"11285","inReplyTo":"20071214062618.29290.70792.stgit@yoghurt","subject":"[StGit PATCH 4/5] Convert \"stg commit\" to new infrastructure","fromName":"Karl Hasselström","fromEmail":"kha@treskal.com","sentAt":"2007-12-14T06:32:30Z","receivedAt":"2007-12-14T06:32:30Z","isPatch":true,"sender":{"key":"kha@treskal.com","avatar":"https://gravatar.com/avatar/f0120c734b5279b345075a28521e1ac66acb20c9913ffe9bf6ae97e53f7f3f13?d=mp&s=160"},"body":"Signed-off-by: Karl Hasselström <kha@treskal.com>\n\n---\n\n stgit/commands/commit.py |   42 ++++++++++++++----------------------------\n stgit/lib/transaction.py |    7 ++++++-\n 2 files changed, 20 insertions(+), 29 deletions(-)\n\n\ndiff --git a/stgit/commands/commit.py b/stgit/commands/commit.py\nindex e56f5a0..f822181 100644\n--- a/stgit/commands/commit.py\n+++ b/stgit/commands/commit.py\n@@ -15,13 +15,9 @@ along with this program; if not, write to the Free Software\n Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\n \"\"\"\n \n-import sys, os\n-from optparse import OptionParser, make_option\n-\n-from stgit.commands.common import *\n-from stgit.utils import *\n+from stgit.commands import common\n+from stgit.lib import transaction\n from stgit.out import *\n-from stgit import stack, git\n \n help = 'permanently store the applied patches into stack base'\n usage = \"\"\"%prog [options]\n@@ -32,7 +28,7 @@ remove them from the series while advancing the base.\n Use this command only if you want to permanently store the applied\n patches and no longer manage them with StGIT.\"\"\"\n \n-directory = DirectoryGotoToplevel()\n+directory = common.DirectoryHasRepositoryLib()\n options = []\n \n \n@@ -43,25 +39,15 @@ def func(parser, options, args):\n     if len(args) != 0:\n         parser.error('incorrect number of arguments')\n \n-    check_local_changes()\n-    check_conflicts()\n-    check_head_top_equal(crt_series)\n-\n-    applied = crt_series.get_applied()\n-    if not applied:\n-        raise CmdException, 'No patches applied'\n-\n-    if crt_series.get_protected():\n-        raise CmdException, 'This branch is protected.  Commit is not permitted'\n-\n-    crt_head = git.get_head()\n-\n-    out.start('Committing %d patches' % len(applied))\n-\n-    crt_series.pop_patch(applied[0])\n-    git.switch(crt_head)\n-\n-    for patch in applied:\n-        crt_series.delete_patch(patch)\n-\n+    stack = directory.repository.current_stack\n+    patches = stack.patchorder.applied\n+    if not patches:\n+        raise CmdException('No patches to commit')\n+    out.start('Committing %d patches' % len(patches))\n+    trans = transaction.StackTransaction(stack, 'stg commit')\n+    for pn in patches:\n+        trans.patches[pn] = None\n+    trans.applied = []\n+    trans.base = stack.head\n+    trans.run()\n     out.done()\ndiff --git a/stgit/lib/transaction.py b/stgit/lib/transaction.py\nindex 0ca647e..a7c4f7e 100644\n--- a/stgit/lib/transaction.py\n+++ b/stgit/lib/transaction.py\n@@ -41,6 +41,7 @@ class StackTransaction(object):\n         self.__unapplied = list(self.__stack.patchorder.unapplied)\n         self.__error = None\n         self.__current_tree = self.__stack.head.data.tree\n+        self.__base = self.__stack.base\n     stack = property(lambda self: self.__stack)\n     patches = property(lambda self: self.__patches)\n     def __set_applied(self, val):\n@@ -49,6 +50,10 @@ class StackTransaction(object):\n     def __set_unapplied(self, val):\n         self.__unapplied = list(val)\n     unapplied = property(lambda self: self.__unapplied, __set_unapplied)\n+    def __set_base(self, val):\n+        assert not self.__applied\n+        self.__base = val\n+    base = property(lambda self: self.__base, __set_base)\n     def __checkout(self, tree, iw):\n         if not self.__stack.head_top_equal():\n             out.error(\n@@ -76,7 +81,7 @@ class StackTransaction(object):\n         if self.__applied:\n             return self.__patches[self.__applied[-1]]\n         else:\n-            return self.__stack.base\n+            return self.__base\n     def abort(self, iw = None):\n         # The only state we need to restore is index+worktree.\n         if iw:\n"},{"id":"63108","messageId":"20071214063236.29290.77674.stgit@yoghurt","threadId":"11285","inReplyTo":"20071214062618.29290.70792.stgit@yoghurt","subject":"[StGit PATCH 5/5] Make \"stg commit\" fancier","fromName":"Karl Hasselström","fromEmail":"kha@treskal.com","sentAt":"2007-12-14T06:32:36Z","receivedAt":"2007-12-14T06:32:36Z","isPatch":true,"sender":{"key":"kha@treskal.com","avatar":"https://gravatar.com/avatar/f0120c734b5279b345075a28521e1ac66acb20c9913ffe9bf6ae97e53f7f3f13?d=mp&s=160"},"body":"Allow the user to commit any patch. Changed behavior: with no\nparameters, commit one applied patch, not all applied patches -- this\nis what uncommit does.\n\nSigned-off-by: Karl Hasselström <kha@treskal.com>\n\n---\n\n stgit/commands/commit.py   |   87 +++++++++++++++++++++++++++++++++-----------\n stgit/commands/uncommit.py |    2 +\n stgit/lib/transaction.py   |    3 +-\n t/t1300-uncommit.sh        |   12 +++---\n 4 files changed, 74 insertions(+), 30 deletions(-)\n\n\ndiff --git a/stgit/commands/commit.py b/stgit/commands/commit.py\nindex f822181..1d741b3 100644\n--- a/stgit/commands/commit.py\n+++ b/stgit/commands/commit.py\n@@ -15,39 +15,82 @@ along with this program; if not, write to the Free Software\n Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\n \"\"\"\n \n+from optparse import make_option\n from stgit.commands import common\n from stgit.lib import transaction\n from stgit.out import *\n \n help = 'permanently store the applied patches into stack base'\n-usage = \"\"\"%prog [options]\n+usage = \"\"\"%prog [<patchnames>] | -n NUM | --all\n \n-Merge the applied patches into the base of the current stack and\n-remove them from the series while advancing the base.\n+Merge one or more patches into the base of the current stack and\n+remove them from the series while advancing the base. This is the\n+opposite of 'stg uncommit'. Use this command if you no longer want to\n+manage a patch with StGIT.\n \n-Use this command only if you want to permanently store the applied\n-patches and no longer manage them with StGIT.\"\"\"\n+By default, the bottommost patch is committed. If patch names are\n+given, the stack is rearranged so that those patches are at the\n+bottom, and then they are committed.\n \n-directory = common.DirectoryHasRepositoryLib()\n-options = []\n+The -n/--number option specifies the number of applied patches to\n+commit (counting from the bottom of the stack). If -a/--all is given,\n+all applied patches are committed.\"\"\"\n \n+directory = common.DirectoryHasRepositoryLib()\n+options = [make_option('-n', '--number', type = 'int',\n+                       help = 'commit the specified number of patches'),\n+           make_option('-a', '--all', action = 'store_true',\n+                       help = 'commit all applied patches')]\n \n def func(parser, options, args):\n-    \"\"\"Merge the applied patches into the base of the current stack\n-       and remove them from the series while advancing the base\n-    \"\"\"\n-    if len(args) != 0:\n-        parser.error('incorrect number of arguments')\n-\n+    \"\"\"Commit a number of patches.\"\"\"\n     stack = directory.repository.current_stack\n-    patches = stack.patchorder.applied\n+    args = common.parse_patches(args, (list(stack.patchorder.applied)\n+                                       + list(stack.patchorder.unapplied)))\n+    if len([x for x in [args, options.number != None, options.all] if x]) > 1:\n+        parser.error('too many options')\n+    if args:\n+        patches = [pn for pn in (stack.patchorder.applied\n+                                 + stack.patchorder.unapplied) if pn in args]\n+        bad = set(args) - set(patches)\n+        if bad:\n+            raise common.CmdException('Bad patch names: %s'\n+                                      % ', '.join(sorted(bad)))\n+    elif options.number != None:\n+        if options.number <= len(stack.patchorder.applied):\n+            patches = stack.patchorder.applied[:options.number]\n+        else:\n+            raise common.CmdException('There are not that many applied patches')\n+    elif options.all:\n+        patches = stack.patchorder.applied\n+    else:\n+        patches = stack.patchorder.applied[:1]\n     if not patches:\n-        raise CmdException('No patches to commit')\n-    out.start('Committing %d patches' % len(patches))\n+        raise common.CmdException('No patches to commit')\n+\n+    iw = stack.repository.default_iw()\n     trans = transaction.StackTransaction(stack, 'stg commit')\n-    for pn in patches:\n-        trans.patches[pn] = None\n-    trans.applied = []\n-    trans.base = stack.head\n-    trans.run()\n-    out.done()\n+    try:\n+        common_prefix = 0\n+        for i in xrange(min(len(stack.patchorder.applied), len(patches))):\n+            if stack.patchorder.applied[i] == patches[i]:\n+                common_prefix += 1\n+        if common_prefix < len(patches):\n+            to_push = trans.pop_patches(\n+                lambda pn: pn in stack.patchorder.applied[common_prefix:])\n+            for pn in patches[common_prefix:]:\n+                trans.push_patch(pn, iw)\n+        else:\n+            to_push = []\n+        new_base = trans.patches[patches[-1]]\n+        for pn in patches:\n+            trans.patches[pn] = None\n+        trans.applied = [pn for pn in trans.applied if pn not in patches]\n+        trans.base = new_base\n+        out.info('Committed %d patch%s' % (len(patches),\n+                                           ['es', ''][len(patches) == 1]))\n+        for pn in to_push:\n+            trans.push_patch(pn, iw)\n+    except transaction.TransactionHalted:\n+        pass\n+    return trans.run(iw)\ndiff --git a/stgit/commands/uncommit.py b/stgit/commands/uncommit.py\nindex 8422952..933ec60 100644\n--- a/stgit/commands/uncommit.py\n+++ b/stgit/commands/uncommit.py\n@@ -28,7 +28,7 @@ usage = \"\"\"%prog [<patchnames>] | -n NUM [<prefix>]] | -t <committish> [-x]\n \n Take one or more git commits at the base of the current stack and turn\n them into StGIT patches. The new patches are created as applied patches\n-at the bottom of the stack. This is the exact opposite of 'stg commit'.\n+at the bottom of the stack. This is the opposite of 'stg commit'.\n \n By default, the number of patches to uncommit is determined by the\n number of patch names provided on the command line. First name is used\ndiff --git a/stgit/lib/transaction.py b/stgit/lib/transaction.py\nindex a7c4f7e..a60c5ff 100644\n--- a/stgit/lib/transaction.py\n+++ b/stgit/lib/transaction.py\n@@ -51,7 +51,8 @@ class StackTransaction(object):\n         self.__unapplied = list(val)\n     unapplied = property(lambda self: self.__unapplied, __set_unapplied)\n     def __set_base(self, val):\n-        assert not self.__applied\n+        assert (not self.__applied\n+                or self.patches[self.applied[0]].data.parent == val)\n         self.__base = val\n     base = property(lambda self: self.__base, __set_base)\n     def __checkout(self, tree, iw):\ndiff --git a/t/t1300-uncommit.sh b/t/t1300-uncommit.sh\nindex 85408fd..d86e579 100755\n--- a/t/t1300-uncommit.sh\n+++ b/t/t1300-uncommit.sh\n@@ -35,7 +35,7 @@ test_expect_success \\\n test_expect_success \\\n \t'Commit the patches' \\\n \t'\n-\tstg commit\n+\tstg commit --all\n \t'\n \n test_expect_success \\\n@@ -43,7 +43,7 @@ test_expect_success \\\n \t'\n \tstg uncommit bar foo &&\n \t[ \"$(stg id foo//top)\" = \"$(stg id bar//bottom)\" ] &&\n-\tstg commit\n+\tstg commit --all\n \t'\n \n test_expect_success \\\n@@ -51,7 +51,7 @@ test_expect_success \\\n \t'\n \tstg uncommit --number=2 foobar &&\n \t[ \"$(stg id foobar1//top)\" = \"$(stg id foobar2//bottom)\" ] &&\n-\tstg commit\n+\tstg commit --all\n \t'\n \n test_expect_success \\\n@@ -59,7 +59,7 @@ test_expect_success \\\n \t'\n \tstg uncommit --number=2 &&\n \t[ \"$(stg id foo-patch//top)\" = \"$(stg id bar-patch//bottom)\" ] &&\n-\tstg commit\n+\tstg commit --all\n \t'\n \n test_expect_success \\\n@@ -68,14 +68,14 @@ test_expect_success \\\n \tstg uncommit &&\n \tstg uncommit &&\n \t[ \"$(stg id foo-patch//top)\" = \"$(stg id bar-patch//bottom)\" ] &&\n-\tstg commit\n+\tstg commit --all\n \t'\n \n test_expect_success \\\n     'Uncommit the patches with --to' '\n     stg uncommit --to HEAD^ &&\n     [ \"$(stg id foo-patch//top)\" = \"$(stg id bar-patch//bottom)\" ] &&\n-    stg commit\n+    stg commit --all\n '\n \n test_done\n"}]}