{"thread":{"id":"14045","subject":"[StGIT PATCH 2/4] Implement a new patch identification scheme and id command","startedAt":"2008-06-19T21:41:53Z","lastAt":"2008-07-14T06:44:34Z","messageCount":13,"participants":["Catalin Marinas","Karl Hasselström"],"isPatch":true,"patchVersion":1,"patchTotal":4},"messages":[{"id":"80381","messageId":"20080619214023.27794.97039.stgit@localhost.localdomain","threadId":"14045","inReplyTo":null,"subject":"[StGIT PATCH 0/4] Proposed patches","fromName":"Catalin Marinas","fromEmail":"catalin.marinas@gmail.com","sentAt":"2008-06-19T21:41:53Z","receivedAt":"2008-06-19T21:41:53Z","isPatch":true,"sender":{"key":"catalin.marinas@gmail.com","avatar":null},"body":"A short series of proposed patches for merging into the StGIT master\nbranch. The most important is the new patch identification scheme.\n\n---\n\nCatalin Marinas (4):\n      Remove the applied/unapplied commands\n      Convert git_id() to the new id format\n      Implement a new patch identification scheme and id command\n      Allow e-mails to be sent with the Unix sendmail tool\n\n\n examples/gitconfig          |    1 \n stgit/commands/applied.py   |   51 --------------------\n stgit/commands/common.py    |  107 +++++++++++++++----------------------------\n stgit/commands/diff.py      |   21 ++++----\n stgit/commands/files.py     |   10 ++--\n stgit/commands/id.py        |   28 +++++------\n stgit/commands/mail.py      |   54 +++++++++++++++-------\n stgit/commands/pick.py      |   10 ++--\n stgit/commands/refresh.py   |    4 +-\n stgit/commands/series.py    |   17 +++++--\n stgit/commands/unapplied.py |   50 --------------------\n stgit/config.py             |    2 -\n stgit/lib/git.py            |    4 +-\n stgit/main.py               |    4 --\n t/t0001-subdir-branches.sh  |   24 ++++------\n t/t1002-branch-clone.sh     |    6 +-\n t/t1003-new.sh              |    4 +-\n t/t1200-push-modified.sh    |   14 +++---\n t/t1201-pull-trailing.sh    |    2 -\n t/t1203-pop.sh              |   12 ++---\n t/t1204-pop-keep.sh         |   12 ++---\n t/t1205-push-subdir.sh      |    4 +-\n t/t1301-repair.sh           |   12 ++---\n t/t1302-repair-interop.sh   |   20 ++++----\n t/t1500-float.sh            |   14 +++---\n t/t1600-delete-one.sh       |   28 ++++++-----\n t/t1601-delete-many.sh      |   24 +++++-----\n t/t2000-sync.sh             |   50 ++++++++++----------\n t/t2200-rebase.sh           |    6 +-\n t/t2500-clean.sh            |   12 ++---\n t/t2600-coalesce.sh         |   12 ++---\n t/t3000-dirty-merge.sh      |    8 ++-\n t/t4000-upgrade.sh          |    4 +-\n 33 files changed, 256 insertions(+), 375 deletions(-)\n delete mode 100644 stgit/commands/applied.py\n delete mode 100644 stgit/commands/unapplied.py\n\n-- \nCatalin\n"},{"id":"80380","messageId":"20080619214201.27794.18891.stgit@localhost.localdomain","threadId":"14045","inReplyTo":"20080619214023.27794.97039.stgit@localhost.localdomain","subject":"[StGIT PATCH 1/4] Allow e-mails to be sent with the Unix sendmail tool","fromName":"Catalin Marinas","fromEmail":"catalin.marinas@gmail.com","sentAt":"2008-06-19T21:42:01Z","receivedAt":"2008-06-19T21:42:01Z","isPatch":true,"sender":{"key":"catalin.marinas@gmail.com","avatar":null},"body":"If the stgit.smtpserver configuration option does not have a host:port\nformat, it is assumed to be an external tool. For example, to use\nsendmail just set this variable to \"/usr/sbin/sendmail -t -i\" (see the\nexamples/gitconfig file).\n\nSigned-off-by: Catalin Marinas <catalin.marinas@gmail.com>\n---\n\n examples/gitconfig     |    1 +\n stgit/commands/mail.py |   46 ++++++++++++++++++++++++++++++++++------------\n stgit/config.py        |    2 +-\n 3 files changed, 36 insertions(+), 13 deletions(-)\n\ndiff --git a/examples/gitconfig b/examples/gitconfig\nindex c16f786..28d94af 100644\n--- a/examples/gitconfig\n+++ b/examples/gitconfig\n@@ -19,6 +19,7 @@\n \t#autoresolved = no\n \n \t# SMTP server for sending patches\n+\t#smtpserver = /usr/sbin/sendmail -t -i\n \t#smtpserver = localhost:25\n \n \t# Set to 'yes' to use SMTP over TLS\ndiff --git a/stgit/commands/mail.py b/stgit/commands/mail.py\nindex b4d4e18..c87d67e 100644\n--- a/stgit/commands/mail.py\n+++ b/stgit/commands/mail.py\n@@ -24,6 +24,7 @@ from stgit.utils import *\n from stgit.out import *\n from stgit import stack, git, version, templates\n from stgit.config import config\n+from stgit.run import Run\n \n \n help = 'send a patch or series of patches by e-mail'\n@@ -31,13 +32,15 @@ usage = r\"\"\"%prog [options] [<patch1>] [<patch2>] [<patch3>..<patch4>]\n \n Send a patch or a range of patches by e-mail using the SMTP server\n specified by the 'stgit.smtpserver' configuration option, or the\n-'--smtp-server' command line option. The From address and the e-mail\n-format are generated from the template file passed as argument to\n-'--template' (defaulting to '.git/patchmail.tmpl' or\n-'~/.stgit/templates/patchmail.tmpl' or\n+'--smtp-server' command line option. This option can also be an\n+absolute path to 'sendmail' followed by command line arguments.\n+\n+The From address and the e-mail format are generated from the template\n+file passed as argument to '--template' (defaulting to\n+'.git/patchmail.tmpl' or '~/.stgit/templates/patchmail.tmpl' or\n '/usr/share/stgit/templates/patchmail.tmpl'). A patch can be sent as\n-attachment using the --attach option in which case the 'mailattch.tmpl'\n-template will be used instead of 'patchmail.tmpl'.\n+attachment using the --attach option in which case the\n+'mailattch.tmpl' template will be used instead of 'patchmail.tmpl'.\n \n The To/Cc/Bcc addresses can either be added to the template file or\n passed via the corresponding command line options. They can be e-mail\n@@ -133,8 +136,9 @@ options = [make_option('-a', '--all',\n                        help = 'sleep for SECONDS between e-mails sending'),\n            make_option('--refid',\n                        help = 'use REFID as the reference id'),\n-           make_option('--smtp-server', metavar = 'HOST[:PORT]',\n-                       help = 'SMTP server to use for sending mail'),\n+           make_option('--smtp-server',\n+                       metavar = 'HOST[:PORT] or \"/path/to/sendmail -t -i\"',\n+                       help = 'SMTP server or command to use for sending mail'),\n            make_option('-u', '--smtp-user', metavar = 'USER',\n                        help = 'username for SMTP authentication'),\n            make_option('-p', '--smtp-password', metavar = 'PASSWORD',\n@@ -184,8 +188,14 @@ def __parse_addresses(msg):\n \n     return (from_addr_list[0], to_addr_list)\n \n-def __send_message(smtpserver, from_addr, to_addr_list, msg, sleep,\n-                   smtpuser, smtppassword, use_tls):\n+def __send_message_sendmail(sendmail, msg):\n+    \"\"\"Send the message using the sendmail command.\n+    \"\"\"\n+    cmd = sendmail.split()\n+    Run(*cmd).raw_input(msg).discard_output()\n+\n+def __send_message_smtp(smtpserver, from_addr, to_addr_list, msg,\n+                        smtpuser, smtppassword, use_tls):\n     \"\"\"Send the message using the given SMTP server\n     \"\"\"\n     try:\n@@ -207,13 +217,25 @@ def __send_message(smtpserver, from_addr, to_addr_list, msg, sleep,\n         result = s.sendmail(from_addr, to_addr_list, msg)\n         if len(result):\n             print \"mail server refused delivery for the following recipients: %s\" % result\n-        # give recipients a chance of receiving patches in the correct order\n-        time.sleep(sleep)\n     except Exception, err:\n         raise CmdException, str(err)\n \n     s.quit()\n \n+def __send_message(smtpserver, from_addr, to_addr_list, msg,\n+                   sleep, smtpuser, smtppassword, use_tls):\n+    \"\"\"Message sending dispatcher.\n+    \"\"\"\n+    if smtpserver.startswith('/'):\n+        # Use the sendmail tool\n+        __send_message_sendmail(smtpserver, msg)\n+    else:\n+        # Use the SMTP server (we have host and port information)\n+        __send_message_smtp(smtpserver, from_addr, to_addr_list, msg,\n+                            smtpuser, smtppassword, use_tls)\n+    # give recipients a chance of receiving patches in the correct order\n+    time.sleep(sleep)\n+\n def __build_address_headers(msg, options, extra_cc = []):\n     \"\"\"Build the address headers and check existing headers in the\n     template.\ndiff --git a/stgit/config.py b/stgit/config.py\nindex 9bfdd52..9b26fa6 100644\n--- a/stgit/config.py\n+++ b/stgit/config.py\n@@ -29,7 +29,7 @@ class GitConfigException(StgException):\n class GitConfig:\n     __defaults={\n         'stgit.autoresolved':\t'no',\n-        'stgit.smtpserver':\t'localhost:25',\n+        'stgit.smtpserver':\t'/usr/sbin/sendmail -t -i',\n         'stgit.smtpdelay':\t'5',\n         'stgit.pullcmd':\t'git pull',\n         'stgit.fetchcmd':\t'git fetch',\n"},{"id":"80379","messageId":"20080619214210.27794.76950.stgit@localhost.localdomain","threadId":"14045","inReplyTo":"20080619214023.27794.97039.stgit@localhost.localdomain","subject":"[StGIT PATCH 2/4] Implement a new patch identification scheme and id command","fromName":"Catalin Marinas","fromEmail":"catalin.marinas@gmail.com","sentAt":"2008-06-19T21:42:10Z","receivedAt":"2008-06-19T21:42:10Z","isPatch":true,"sender":{"key":"catalin.marinas@gmail.com","avatar":null},"body":"The new scheme allows '[<branch>:]<patch>' and '[<branch>:]{base}'\n(the latter showing the base of a stack). The former format allows\nsymbols like ^ and ^{...}.\n\nSigned-off-by: Catalin Marinas <catalin.marinas@gmail.com>\n---\n\n stgit/commands/common.py   |   32 ++++++++++++++++++++++++++++++++\n stgit/commands/id.py       |   28 ++++++++++++----------------\n stgit/lib/git.py           |    4 ++--\n t/t0001-subdir-branches.sh |   24 ++++++++++--------------\n t/t1200-push-modified.sh   |    2 +-\n t/t1201-pull-trailing.sh   |    2 +-\n t/t2200-rebase.sh          |    2 +-\n 7 files changed, 59 insertions(+), 35 deletions(-)\n\ndiff --git a/stgit/commands/common.py b/stgit/commands/common.py\nindex 029ec65..349389f 100644\n--- a/stgit/commands/common.py\n+++ b/stgit/commands/common.py\n@@ -28,6 +28,7 @@ from stgit.run import *\n from stgit import stack, git, basedir\n from stgit.config import config, file_extensions\n from stgit.lib import stack as libstack\n+from stgit.lib import git as libgit\n \n # Command exception class\n class CmdException(StgException):\n@@ -116,6 +117,37 @@ def git_id(crt_series, rev):\n \n     raise CmdException, 'Unknown patch or revision: %s' % rev\n \n+def git_commit(name, repository, branch = None):\n+    \"\"\"Return the a Commit object if 'name' is a patch name or Git commit.\n+    The patch names allowed are in the form '<branch>:<patch>' and can be\n+    followed by standard symbols used by git-rev-parse. If <patch> is '{base}',\n+    it represents the bottom of the stack.\n+    \"\"\"\n+    # Try a [branch:]patch name first\n+    try:\n+        branch, patch = name.split(':', 1)\n+    except ValueError:\n+        patch = name\n+    if not branch:\n+        branch = repository.current_branch_name\n+\n+    # The stack base\n+    if patch == '{base}':\n+        return repository.get_stack(branch).base\n+\n+    # Other combination of branch and patch\n+    try:\n+        return repository.rev_parse('patches/%s/%s' % (branch, patch),\n+                                    discard_stderr = True)\n+    except libgit.RepositoryException:\n+        pass\n+\n+    # Try a Git commit\n+    try:\n+        return repository.rev_parse(name, discard_stderr = True)\n+    except libgit.RepositoryException:\n+        raise CmdException('%s: Unknown patch or revision name' % name)\n+\n def check_local_changes():\n     if git.local_changes():\n         raise CmdException('local changes in the tree. Use \"refresh\" or'\ndiff --git a/stgit/commands/id.py b/stgit/commands/id.py\nindex 94b0229..3819acc 100644\n--- a/stgit/commands/id.py\n+++ b/stgit/commands/id.py\n@@ -15,28 +15,24 @@ 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.out import *\n-from stgit import stack, git\n-\n+from stgit.out import out\n+from stgit.commands import common\n+from stgit.lib import stack\n \n help = 'print the GIT hash value of a StGIT reference'\n usage = \"\"\"%prog [options] [id]\n \n-Print the hash value of a GIT id (defaulting to HEAD). In addition to\n-the standard GIT id's like heads and tags, this command also accepts\n-'base[@<branch>]' and '[<patch>[@<branch>]][//[bottom | top]]'. If no\n-'top' or 'bottom' are passed and <patch> is a valid patch name, 'top'\n-will be used by default.\"\"\"\n-\n-directory = DirectoryHasRepository()\n-options = [make_option('-b', '--branch',\n-                       help = 'use BRANCH instead of the default one')]\n+Print the SHA1 value of a Git id (defaulting to HEAD). In addition to\n+the standard Git id's like heads and tags, this command also accepts\n+'[<branch>:]<patch>' and '[<branch>:]{base}' showing the id of a patch\n+or the base of the stack. If no branch is specified, it defaults to the\n+current one. The bottom of a patch is accessible with the\n+'[<branch>:]<patch>^' format.\"\"\"\n \n+directory = common.DirectoryHasRepositoryLib()\n+options = []\n \n def func(parser, options, args):\n     \"\"\"Show the applied patches\n@@ -48,4 +44,4 @@ def func(parser, options, args):\n     else:\n         parser.error('incorrect number of arguments')\n \n-    out.stdout(git_id(crt_series, id_str))\n+    out.stdout(common.git_commit(id_str, directory.repository).sha1)\ndiff --git a/stgit/lib/git.py b/stgit/lib/git.py\nindex 6ccdfa7..4746da3 100644\n--- a/stgit/lib/git.py\n+++ b/stgit/lib/git.py\n@@ -422,11 +422,11 @@ class Repository(RunWithEnv):\n     refs = property(lambda self: self.__refs)\n     def cat_object(self, sha1):\n         return self.run(['git', 'cat-file', '-p', sha1]).raw_output()\n-    def rev_parse(self, rev):\n+    def rev_parse(self, rev, discard_stderr = False):\n         try:\n             return self.get_commit(self.run(\n                     ['git', 'rev-parse', '%s^{commit}' % rev]\n-                    ).output_one_line())\n+                    ).discard_stderr(discard_stderr).output_one_line())\n         except run.RunException:\n             raise RepositoryException('%s: No such revision' % rev)\n     def get_tree(self, sha1):\ndiff --git a/t/t0001-subdir-branches.sh b/t/t0001-subdir-branches.sh\nindex 0eed3a4..4df0481 100755\n--- a/t/t0001-subdir-branches.sh\n+++ b/t/t0001-subdir-branches.sh\n@@ -18,25 +18,21 @@ test_expect_success 'Create a patch' \\\n    stg new foo -m \"Add foo.txt\" &&\n    stg refresh'\n \n-test_expect_success 'Old and new id with non-slashy branch' \\\n-  'stg id foo &&\n-   stg id foo// &&\n-   stg id foo/ &&\n-   stg id foo//top &&\n-   stg id foo/top &&\n-   stg id foo@master &&\n-   stg id foo@master//top &&\n-   stg id foo@master/top'\n+test_expect_success 'Try id with non-slashy branch' \\\n+  'stg id &&\n+   stg id foo &&\n+   stg id foo^ &&\n+   stg id master:foo &&\n+   stg id master:foo^'\n \n test_expect_success 'Clone branch to slashier name' \\\n   'stg branch --clone x/y/z'\n \n-test_expect_success 'Try new form of id with slashy branch' \\\n+test_expect_success 'Try new id with slashy branch' \\\n   'stg id foo &&\n-   stg id foo// &&\n-   stg id foo//top &&\n-   stg id foo@x/y/z &&\n-   stg id foo@x/y/z//top'\n+   stg id foo^ &&\n+   stg id x/y/z:foo &&\n+   stg id x/y/z:foo^'\n \n test_expect_success 'Try old id with slashy branch' '\n    ! stg id foo/ &&\ndiff --git a/t/t1200-push-modified.sh b/t/t1200-push-modified.sh\nindex ba4f70c..e3c6425 100755\n--- a/t/t1200-push-modified.sh\n+++ b/t/t1200-push-modified.sh\n@@ -36,7 +36,7 @@ test_expect_success \\\n     (\n         cd foo &&\n         GIT_DIR=../bar/.git git-format-patch --stdout \\\n-          $(cd ../bar && stg id base@master)..HEAD | git-am -3 -k\n+          $(cd ../bar && stg id master:{base})..HEAD | git-am -3 -k\n     )\n '\n \ndiff --git a/t/t1201-pull-trailing.sh b/t/t1201-pull-trailing.sh\nindex 9d70fe0..8a74873 100755\n--- a/t/t1201-pull-trailing.sh\n+++ b/t/t1201-pull-trailing.sh\n@@ -30,7 +30,7 @@ test_expect_success \\\n     'Port those patches to orig tree' \\\n     '(cd foo &&\n       GIT_DIR=../bar/.git git-format-patch --stdout \\\n-          $(cd ../bar && stg id base@master)..HEAD |\n+          $(cd ../bar && stg id master:{base})..HEAD |\n       git-am -3 -k\n      )\n     '\ndiff --git a/t/t2200-rebase.sh b/t/t2200-rebase.sh\nindex ec2a104..cd43c41 100755\n--- a/t/t2200-rebase.sh\n+++ b/t/t2200-rebase.sh\n@@ -27,7 +27,7 @@ test_expect_success \\\n \t'Rebase to previous commit' \\\n \t'\n \tstg rebase master~1 &&\n-\ttest `stg id base@stack` = `git rev-parse master~1` &&\n+\ttest `stg id stack:{base}` = `git rev-parse master~1` &&\n \ttest `stg applied | wc -l` = 1\n \t'\n \n"},{"id":"80382","messageId":"20080619214222.27794.74083.stgit@localhost.localdomain","threadId":"14045","inReplyTo":"20080619214023.27794.97039.stgit@localhost.localdomain","subject":"[StGIT PATCH 3/4] Convert git_id() to the new id format","fromName":"Catalin Marinas","fromEmail":"catalin.marinas@gmail.com","sentAt":"2008-06-19T21:42:22Z","receivedAt":"2008-06-19T21:42:22Z","isPatch":true,"sender":{"key":"catalin.marinas@gmail.com","avatar":null},"body":"The patch rewrites git_id() to use the new id format and coverts the\ncommands using this function. The git_id() will be removed once all the\ncommands are converted to the new infrastructure where git_commit() will\nbe used instead.\n\nSigned-off-by: Catalin Marinas <catalin.marinas@gmail.com>\n---\n\n stgit/commands/common.py  |   97 ++++++++-------------------------------------\n stgit/commands/diff.py    |   21 ++++------\n stgit/commands/files.py   |   10 ++---\n stgit/commands/mail.py    |    8 ++--\n stgit/commands/pick.py    |   10 ++---\n stgit/commands/refresh.py |    4 +-\n stgit/commands/series.py  |    4 +-\n t/t2000-sync.sh           |    2 -\n 8 files changed, 43 insertions(+), 113 deletions(-)\n\ndiff --git a/stgit/commands/common.py b/stgit/commands/common.py\nindex 349389f..3e1d2d0 100644\n--- a/stgit/commands/common.py\n+++ b/stgit/commands/common.py\n@@ -35,101 +35,38 @@ class CmdException(StgException):\n     pass\n \n # Utility functions\n-class RevParseException(StgException):\n-    \"\"\"Revision spec parse error.\"\"\"\n-    pass\n-\n def parse_rev(rev):\n-    \"\"\"Parse a revision specification into its\n-    patchname@branchname//patch_id parts. If no branch name has a slash\n-    in it, also accept / instead of //.\"\"\"\n-    if '/' in ''.join(git.get_heads()):\n-        # We have branch names with / in them.\n-        branch_chars = r'[^@]'\n-        patch_id_mark = r'//'\n-    else:\n-        # No / in branch names.\n-        branch_chars = r'[^@/]'\n-        patch_id_mark = r'(/|//)'\n-    patch_re = r'(?P<patch>[^@/]+)'\n-    branch_re = r'@(?P<branch>%s+)' % branch_chars\n-    patch_id_re = r'%s(?P<patch_id>[a-z.]*)' % patch_id_mark\n-\n-    # Try //patch_id.\n-    m = re.match(r'^%s$' % patch_id_re, rev)\n-    if m:\n-        return None, None, m.group('patch_id')\n-\n-    # Try path[@branch]//patch_id.\n-    m = re.match(r'^%s(%s)?%s$' % (patch_re, branch_re, patch_id_re), rev)\n-    if m:\n-        return m.group('patch'), m.group('branch'), m.group('patch_id')\n-\n-    # Try patch[@branch].\n-    m = re.match(r'^%s(%s)?$' % (patch_re, branch_re), rev)\n-    if m:\n-        return m.group('patch'), m.group('branch'), None\n-\n-    # No, we can't parse that.\n-    raise RevParseException\n+    \"\"\"Parse a revision specification into its branch:patch parts.\n+    \"\"\"\n+    try:\n+        branch, patch = rev.split(':', 1)\n+    except ValueError:\n+        branch = None\n+        patch = rev\n+\n+    return (branch, patch)\n \n def git_id(crt_series, rev):\n     \"\"\"Return the GIT id\n     \"\"\"\n+    # TODO: remove this function once all the occurrences were converted\n+    # to git_commit()\n     if not rev:\n+        # backwards compatibility\n         return None\n+    repository = libstack.Repository.default()\n+    return git_commit(rev, repository, crt_series.get_name()).sha1\n \n-    # try a GIT revision first\n-    try:\n-        return git.rev_parse(rev + '^{commit}')\n-    except git.GitException:\n-        pass\n-\n-    # try an StGIT patch name\n-    try:\n-        patch, branch, patch_id = parse_rev(rev)\n-        if branch == None:\n-            series = crt_series\n-        else:\n-            series = stack.Series(branch)\n-        if patch == None:\n-            patch = series.get_current()\n-            if not patch:\n-                raise CmdException, 'No patches applied'\n-        if patch in series.get_applied() or patch in series.get_unapplied() or \\\n-               patch in series.get_hidden():\n-            if patch_id in ['top', '', None]:\n-                return series.get_patch(patch).get_top()\n-            elif patch_id == 'bottom':\n-                return series.get_patch(patch).get_bottom()\n-            elif patch_id == 'top.old':\n-                return series.get_patch(patch).get_old_top()\n-            elif patch_id == 'bottom.old':\n-                return series.get_patch(patch).get_old_bottom()\n-            elif patch_id == 'log':\n-                return series.get_patch(patch).get_log()\n-        if patch == 'base' and patch_id == None:\n-            return series.get_base()\n-    except RevParseException:\n-        pass\n-    except stack.StackException:\n-        pass\n-\n-    raise CmdException, 'Unknown patch or revision: %s' % rev\n-\n-def git_commit(name, repository, branch = None):\n+def git_commit(name, repository, branch_name = None):\n     \"\"\"Return the a Commit object if 'name' is a patch name or Git commit.\n     The patch names allowed are in the form '<branch>:<patch>' and can be\n     followed by standard symbols used by git-rev-parse. If <patch> is '{base}',\n     it represents the bottom of the stack.\n     \"\"\"\n     # Try a [branch:]patch name first\n-    try:\n-        branch, patch = name.split(':', 1)\n-    except ValueError:\n-        patch = name\n+    branch, patch = parse_rev(name)\n     if not branch:\n-        branch = repository.current_branch_name\n+        branch = branch_name or repository.current_branch_name\n \n     # The stack base\n     if patch == '{base}':\ndiff --git a/stgit/commands/diff.py b/stgit/commands/diff.py\nindex fd6be34..4ae9b49 100644\n--- a/stgit/commands/diff.py\n+++ b/stgit/commands/diff.py\n@@ -30,17 +30,14 @@ help = 'show the tree diff'\n usage = \"\"\"%prog [options] [<files or dirs>]\n \n Show the diff (default) or diffstat between the current working copy\n-or a tree-ish object and another tree-ish object. File names can also\n-be given to restrict the diff output. The tree-ish object can be a\n-standard git commit, tag or tree. In addition to these, the command\n-also supports 'base', representing the bottom of the current stack,\n-and '[patch][//[bottom | top]]' for the patch boundaries (defaulting to\n-the current one):\n+or a tree-ish object and another tree-ish object (defaulting to HEAD).\n+File names can also be given to restrict the diff output. The\n+tree-ish object can be an StGIT patch, a standard git commit, tag or\n+tree. In addition to these, the command also supports '{base}',\n+representing the bottom of the current stack.\n \n-rev = '([patch][//[bottom | top]]) | <tree-ish> | base'\n-\n-If neither bottom nor top are given but a '//' is present, the command\n-shows the specified patch (defaulting to the current one).\"\"\"\n+rev = '([branch:]patch) | <tree-ish> | base'\n+\"\"\"\n \n directory = DirectoryHasRepository()\n options = [make_option('-r', '--range',\n@@ -67,8 +64,8 @@ def func(parser, options, args):\n                 rev = strip_suffix('/', rev)\n                 if rev.endswith('/'):\n                     rev = strip_suffix('/', rev)\n-                rev1 = rev + '//bottom'\n-                rev2 = rev + '//top'\n+                rev1 = rev + 'HEAD^'\n+                rev2 = rev + 'HEAD'\n             else:\n                 rev1 = rev_list[0]\n                 rev2 = None\ndiff --git a/stgit/commands/files.py b/stgit/commands/files.py\nindex b43b12f..d240872 100644\n--- a/stgit/commands/files.py\n+++ b/stgit/commands/files.py\n@@ -26,7 +26,7 @@ from stgit import stack, git\n \n \n help = 'show the files modified by a patch (or the current patch)'\n-usage = \"\"\"%prog [options] [<patch>]\n+usage = \"\"\"%prog [options] [[<branch>:]<patch>]\n \n List the files modified by the given patch (defaulting to the current\n one). Passing the '--stat' option shows the diff statistics for the\n@@ -38,8 +38,6 @@ directory = DirectoryHasRepository()\n options = [make_option('-s', '--stat',\n                        help = 'show the diff stat',\n                        action = 'store_true'),\n-           make_option('-b', '--branch',\n-                       help = 'use BRANCH instead of the default one'),\n            make_option('--bare',\n                        help = 'bare file names (useful for scripting)',\n                        action = 'store_true')\n@@ -50,14 +48,14 @@ def func(parser, options, args):\n     \"\"\"Show the files modified by a patch (or the current patch)\n     \"\"\"\n     if len(args) == 0:\n-        patch = ''\n+        patch = 'HEAD'\n     elif len(args) == 1:\n         patch = args[0]\n     else:\n         parser.error('incorrect number of arguments')\n \n-    rev1 = git_id(crt_series, '%s//bottom' % patch)\n-    rev2 = git_id(crt_series, '%s//top' % patch)\n+    rev1 = git_id(crt_series, '%s^' % patch)\n+    rev2 = git_id(crt_series, '%s' % patch)\n \n     if options.stat:\n         out.stdout_raw(git.diffstat(git.diff(rev1 = rev1, rev2 = rev2)) + '\\n')\ndiff --git a/stgit/commands/mail.py b/stgit/commands/mail.py\nindex c87d67e..e04dc2f 100644\n--- a/stgit/commands/mail.py\n+++ b/stgit/commands/mail.py\n@@ -383,8 +383,8 @@ def __build_cover(tmpl, patches, msg_id, options):\n                  'shortlog':     stack.shortlog(crt_series.get_patch(p)\n                                                 for p in patches),\n                  'diffstat':     git.diffstat(git.diff(\n-                     rev1 = git_id(crt_series, '%s//bottom' % patches[0]),\n-                     rev2 = git_id(crt_series, '%s//top' % patches[-1])))}\n+                     rev1 = git_id(crt_series, '%s^' % patches[0]),\n+                     rev2 = git_id(crt_series, '%s' % patches[-1])))}\n \n     try:\n         msg_string = tmpl % tmpl_dict\n@@ -460,8 +460,8 @@ def __build_message(tmpl, patch, patch_nr, total_nr, msg_id, ref_id, options):\n     else:\n         number_str = ''\n \n-    diff = git.diff(rev1 = git_id(crt_series, '%s//bottom' % patch),\n-                    rev2 = git_id(crt_series, '%s//top' % patch),\n+    diff = git.diff(rev1 = git_id(crt_series, '%s^' % patch),\n+                    rev2 = git_id(crt_series, '%s' % patch),\n                     diff_flags = options.diff_flags)\n     tmpl_dict = {'patch':        patch,\n                  'sender':       sender,\ndiff --git a/stgit/commands/pick.py b/stgit/commands/pick.py\nindex 1f7c84b..2a670e8 100644\n--- a/stgit/commands/pick.py\n+++ b/stgit/commands/pick.py\n@@ -87,8 +87,8 @@ def __pick_commit(commit_id, patchname, options):\n \n         out.done()\n     elif options.update:\n-        rev1 = git_id(crt_series, '//bottom')\n-        rev2 = git_id(crt_series, '//top')\n+        rev1 = git_id(crt_series, 'HEAD^')\n+        rev2 = git_id(crt_series, 'HEAD')\n         files = git.barefiles(rev1, rev2).split('\\n')\n \n         out.start('Updating with commit %s' % commit_id)\n@@ -115,10 +115,8 @@ def __pick_commit(commit_id, patchname, options):\n         patchname = newpatch.get_name()\n \n         # find a patchlog to fork from\n-        (refpatchname, refbranchname, refpatchid) = parse_rev(patchname)\n-        if refpatchname and not refpatchid and \\\n-               (not refpatchid or refpatchid == 'top'):\n-            # FIXME: should also support picking //top.old\n+        refbranchname, refpatchname = parse_rev(patchname)\n+        if refpatchname:\n             if refbranchname:\n                 # assume the refseries is OK, since we already resolved\n                 # commit_str to a git_id\ndiff --git a/stgit/commands/refresh.py b/stgit/commands/refresh.py\nindex 4695c62..73e4ee0 100644\n--- a/stgit/commands/refresh.py\n+++ b/stgit/commands/refresh.py\n@@ -103,8 +103,8 @@ def func(parser, options, args):\n             between = applied[:applied.index(patch):-1]\n             pop_patches(crt_series, between, keep = True)\n         elif options.update:\n-            rev1 = git_id(crt_series, '//bottom')\n-            rev2 = git_id(crt_series, '//top')\n+            rev1 = git_id(crt_series, 'HEAD^')\n+            rev2 = git_id(crt_series, 'HEAD')\n             patch_files = git.barefiles(rev1, rev2).split('\\n')\n             files = [f for f in files if f in patch_files]\n             if not files:\ndiff --git a/stgit/commands/series.py b/stgit/commands/series.py\nindex 04183bd..c11c74f 100644\n--- a/stgit/commands/series.py\n+++ b/stgit/commands/series.py\n@@ -88,7 +88,7 @@ def __print_patch(stack, patch, branch_str, prefix, empty_prefix, length, option\n     elif options.empty and stack.patches.get(patch).is_empty():\n         prefix = empty_prefix\n \n-    patch_str = patch + branch_str\n+    patch_str = branch_str + patch\n \n     if options.description or options.author:\n         patch_str = patch_str.ljust(length)\n@@ -164,7 +164,7 @@ def func(parser, options, args):\n         return\n \n     if options.showbranch:\n-        branch_str = '@' + stack.name\n+        branch_str = stack.name + ':'\n     else:\n         branch_str = ''\n \ndiff --git a/t/t2000-sync.sh b/t/t2000-sync.sh\nindex e489603..4a00c56 100755\n--- a/t/t2000-sync.sh\n+++ b/t/t2000-sync.sh\n@@ -37,7 +37,7 @@ test_expect_success \\\n test_expect_success \\\n     'Create a branch with empty patches' \\\n     '\n-    stg branch -c foo base &&\n+    stg branch -c foo {base} &&\n     stg new p1 -m p1 &&\n     stg new p2 -m p2 &&\n     stg new p3 -m p3 &&\n"},{"id":"80383","messageId":"20080619214233.27794.98487.stgit@localhost.localdomain","threadId":"14045","inReplyTo":"20080619214023.27794.97039.stgit@localhost.localdomain","subject":"[StGIT PATCH 4/4] Remove the applied/unapplied commands","fromName":"Catalin Marinas","fromEmail":"catalin.marinas@gmail.com","sentAt":"2008-06-19T21:42:33Z","receivedAt":"2008-06-19T21:42:33Z","isPatch":true,"sender":{"key":"catalin.marinas@gmail.com","avatar":null},"body":"This patch moves the applied/unapplied functionality to the 'series'\ncommand via the corresponding options.\n\nSigned-off-by: Catalin Marinas <catalin.marinas@gmail.com>\n---\n\n stgit/commands/applied.py   |   51 -------------------------------------------\n stgit/commands/series.py    |   13 +++++++++--\n stgit/commands/unapplied.py |   50 ------------------------------------------\n stgit/main.py               |    4 ---\n t/t1002-branch-clone.sh     |    6 +++--\n t/t1003-new.sh              |    4 ++-\n t/t1200-push-modified.sh    |   12 +++++-----\n t/t1203-pop.sh              |   12 +++++-----\n t/t1204-pop-keep.sh         |   12 +++++-----\n t/t1205-push-subdir.sh      |    4 ++-\n t/t1301-repair.sh           |   12 +++++-----\n t/t1302-repair-interop.sh   |   20 ++++++++---------\n t/t1500-float.sh            |   14 ++++++------\n t/t1600-delete-one.sh       |   28 ++++++++++++------------\n t/t1601-delete-many.sh      |   24 ++++++++++----------\n t/t2000-sync.sh             |   48 ++++++++++++++++++++--------------------\n t/t2200-rebase.sh           |    4 ++-\n t/t2500-clean.sh            |   12 +++++-----\n t/t2600-coalesce.sh         |   12 +++++-----\n t/t3000-dirty-merge.sh      |    8 +++----\n t/t4000-upgrade.sh          |    4 ++-\n 21 files changed, 129 insertions(+), 225 deletions(-)\n delete mode 100644 stgit/commands/applied.py\n delete mode 100644 stgit/commands/unapplied.py\n\ndiff --git a/stgit/commands/applied.py b/stgit/commands/applied.py\ndeleted file mode 100644\nindex e57c796..0000000\n--- a/stgit/commands/applied.py\n+++ /dev/null\n@@ -1,51 +0,0 @@\n-\n-__copyright__ = \"\"\"\n-Copyright (C) 2005, Catalin Marinas <catalin.marinas@gmail.com>\n-\n-This program is free software; you can redistribute it and/or modify\n-it under the terms of the GNU General Public License version 2 as\n-published by the Free Software Foundation.\n-\n-This program is distributed in the hope that it will be useful,\n-but WITHOUT ANY WARRANTY; without even the implied warranty of\n-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n-GNU General Public License for more details.\n-\n-You should have received a copy of the GNU General Public License\n-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.out import *\n-from stgit.commands import common\n-\n-\n-help = 'print the applied patches'\n-usage = \"\"\"%prog [options]\n-\n-List the patches from the series which have already been pushed onto\n-the stack. They are listed in the order in which they were pushed, the\n-last one being the current (topmost) patch.\"\"\"\n-\n-directory = common.DirectoryHasRepositoryLib()\n-options = [make_option('-b', '--branch',\n-                       help = 'use BRANCH instead of the default branch'),\n-           make_option('-c', '--count',\n-                       help = 'print the number of applied patches',\n-                       action = 'store_true')]\n-\n-\n-def func(parser, options, args):\n-    \"\"\"Show the applied patches\n-    \"\"\"\n-    if len(args) != 0:\n-        parser.error('incorrect number of arguments')\n-\n-    s = directory.repository.get_stack(options.branch)\n-\n-    if options.count:\n-        out.stdout(len(s.patchorder.applied))\n-    else:\n-        for pn in s.patchorder.applied:\n-            out.stdout(pn)\ndiff --git a/stgit/commands/series.py b/stgit/commands/series.py\nindex c11c74f..24d6ffa 100644\n--- a/stgit/commands/series.py\n+++ b/stgit/commands/series.py\n@@ -37,6 +37,12 @@ options = [make_option('-b', '--branch',\n            make_option('-a', '--all',\n                        help = 'show all patches, including the hidden ones',\n                        action = 'store_true'),\n+           make_option('--applied',\n+                       help = 'show the applied patches only',\n+                       action = 'store_true'),\n+           make_option('--unapplied',\n+                       help = 'show the unapplied patches only',\n+                       action = 'store_true'),\n            make_option('--hidden',\n                        help = 'show the hidden patches only',\n                        action = 'store_true'),\n@@ -112,17 +118,20 @@ def func(parser, options, args):\n         stack = directory.repository.get_stack(options.missing)\n \n     # current series patches\n+    applied = unapplied = hidden = ()\n     if options.all:\n         applied = stack.patchorder.applied\n         unapplied = stack.patchorder.unapplied\n         hidden = stack.patchorder.hidden\n+    elif options.applied:\n+        applied = stack.patchorder.applied\n+    elif options.unapplied:\n+        unapplied = stack.patchorder.unapplied\n     elif options.hidden:\n-        applied = unapplied = ()\n         hidden = stack.patchorder.hidden\n     else:\n         applied = stack.patchorder.applied\n         unapplied = stack.patchorder.unapplied\n-        hidden = ()\n \n     if options.missing:\n         cmp_patches = cmp_stack.patchorder.all\ndiff --git a/stgit/commands/unapplied.py b/stgit/commands/unapplied.py\ndeleted file mode 100644\nindex 7323346..0000000\n--- a/stgit/commands/unapplied.py\n+++ /dev/null\n@@ -1,50 +0,0 @@\n-\n-__copyright__ = \"\"\"\n-Copyright (C) 2005, Catalin Marinas <catalin.marinas@gmail.com>\n-\n-This program is free software; you can redistribute it and/or modify\n-it under the terms of the GNU General Public License version 2 as\n-published by the Free Software Foundation.\n-\n-This program is distributed in the hope that it will be useful,\n-but WITHOUT ANY WARRANTY; without even the implied warranty of\n-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n-GNU General Public License for more details.\n-\n-You should have received a copy of the GNU General Public License\n-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.out import *\n-from stgit.commands import common\n-\n-\n-help = 'print the unapplied patches'\n-usage = \"\"\"%prog [options]\n-\n-List the patches from the series which are not pushed onto the stack.\n-They are listed in the reverse order in which they were popped.\"\"\"\n-\n-directory = common.DirectoryHasRepositoryLib()\n-options = [make_option('-b', '--branch',\n-                       help = 'use BRANCH instead of the default branch'),\n-           make_option('-c', '--count',\n-                       help = 'print the number of unapplied patches',\n-                       action = 'store_true')]\n-\n-\n-def func(parser, options, args):\n-    \"\"\"Show the unapplied patches\n-    \"\"\"\n-    if len(args) != 0:\n-        parser.error('incorrect number of arguments')\n-\n-    s = directory.repository.get_stack(options.branch)\n-\n-    if options.count:\n-        out.stdout(len(s.patchorder.unapplied))\n-    else:\n-        for pn in s.patchorder.unapplied:\n-            out.stdout(pn)\ndiff --git a/stgit/main.py b/stgit/main.py\nindex aa1f8ef..7be8e14 100644\n--- a/stgit/main.py\n+++ b/stgit/main.py\n@@ -59,7 +59,6 @@ class Commands(dict):\n         return getattr(stgit.commands, cmd_mod)\n \n commands = Commands({\n-    'applied':          'applied',\n     'branch':           'branch',\n     'delete':           'delete',\n     'diff':             'diff',\n@@ -96,7 +95,6 @@ commands = Commands({\n     'status':           'status',\n     'sync':             'sync',\n     'top':              'top',\n-    'unapplied':        'unapplied',\n     'uncommit':         'uncommit',\n     'unhide':           'unhide'\n     })\n@@ -107,7 +105,6 @@ repocommands = (\n     'id',\n     )\n stackcommands = (\n-    'applied',\n     'branch',\n     'clean',\n     'coalesce',\n@@ -125,7 +122,6 @@ stackcommands = (\n     'series',\n     'sink',\n     'top',\n-    'unapplied',\n     'uncommit',\n     'unhide',\n     )\ndiff --git a/t/t1002-branch-clone.sh b/t/t1002-branch-clone.sh\nindex b0087e9..7f3f913 100755\n--- a/t/t1002-branch-clone.sh\n+++ b/t/t1002-branch-clone.sh\n@@ -29,16 +29,16 @@ test_expect_success \\\n     '\n     stg branch --clone foo &&\n     stg new p1 -m \"p1\" &&\n-    test $(stg applied -c) -eq 1\n+    test $(stg series --applied -c) -eq 1\n     '\n \n test_expect_success \\\n     'Clone the current StGIT branch' \\\n     '\n     stg branch --clone bar &&\n-    test $(stg applied -c) -eq 1 &&\n+    test $(stg series --applied -c) -eq 1 &&\n     stg new p2 -m \"p2\" &&\n-    test $(stg applied -c) -eq 2\n+    test $(stg series --applied -c) -eq 2\n     '\n \n test_done\ndiff --git a/t/t1003-new.sh b/t/t1003-new.sh\nindex 0be5d9b..826e41d 100755\n--- a/t/t1003-new.sh\n+++ b/t/t1003-new.sh\n@@ -17,13 +17,13 @@ test_expect_success \\\n test_expect_success \\\n     'Create a named patch' '\n     stg new foo -m foobar &&\n-    [ $(stg applied -c) -eq 1 ]\n+    [ $(stg series --applied -c) -eq 1 ]\n '\n \n test_expect_success \\\n     'Create a patch without giving a name' '\n     stg new -m yo &&\n-    [ $(stg applied -c) -eq 2 ]\n+    [ $(stg series --applied -c) -eq 2 ]\n '\n \n test_done\ndiff --git a/t/t1200-push-modified.sh b/t/t1200-push-modified.sh\nindex e3c6425..b8ca4cc 100755\n--- a/t/t1200-push-modified.sh\n+++ b/t/t1200-push-modified.sh\n@@ -26,8 +26,8 @@ test_expect_success \\\n         printf \"a\\nc\\n\" > file && git add file && stg refresh &&\n         stg new p2 -m p2 &&\n         printf \"a\\nb\\nc\\n\" > file && stg refresh &&\n-        [ \"$(echo $(stg applied))\" = \"p1 p2\" ] &&\n-        [ \"$(echo $(stg unapplied))\" = \"\" ]\n+        [ \"$(echo $(stg series --applied --noprefix))\" = \"p1 p2\" ] &&\n+        [ \"$(echo $(stg series --unapplied --noprefix))\" = \"\" ]\n     )\n '\n \n@@ -57,8 +57,8 @@ test_expect_success \\\n     'Rollback the push' '\n     (\n         cd bar && stg push --undo &&\n-        [ \"$(echo $(stg applied))\" = \"\" ] &&\n-        [ \"$(echo $(stg unapplied))\" = \"p1 p2\" ]\n+        [ \"$(echo $(stg series --applied --noprefix))\" = \"\" ] &&\n+        [ \"$(echo $(stg series --unapplied --noprefix))\" = \"p1 p2\" ]\n     )\n '\n \n@@ -66,8 +66,8 @@ test_expect_success \\\n     'Push those patches while checking they were merged upstream' '\n     (\n         cd bar && stg push --merged --all\n-        [ \"$(echo $(stg applied))\" = \"p1 p2\" ] &&\n-        [ \"$(echo $(stg unapplied))\" = \"\" ]\n+        [ \"$(echo $(stg series --applied --noprefix))\" = \"p1 p2\" ] &&\n+        [ \"$(echo $(stg series --unapplied --noprefix))\" = \"\" ]\n     )\n '\n \ndiff --git a/t/t1203-pop.sh b/t/t1203-pop.sh\nindex 6e49b4d..e1ed577 100755\n--- a/t/t1203-pop.sh\n+++ b/t/t1203-pop.sh\n@@ -12,22 +12,22 @@ test_expect_success \\\n     for i in 0 1 2 3 4 5 6 7 8 9; do\n         stg new p$i -m p$i;\n     done &&\n-    [ \"$(echo $(stg applied))\" = \"p0 p1 p2 p3 p4 p5 p6 p7 p8 p9\" ] &&\n-    [ \"$(echo $(stg unapplied))\" = \"\" ]\n+    [ \"$(echo $(stg series --applied --noprefix))\" = \"p0 p1 p2 p3 p4 p5 p6 p7 p8 p9\" ] &&\n+    [ \"$(echo $(stg series --unapplied --noprefix))\" = \"\" ]\n '\n \n test_expect_success \\\n     'Pop half the patches' '\n     stg pop -n 5 &&\n-    [ \"$(echo $(stg applied))\" = \"p0 p1 p2 p3 p4\" ] &&\n-    [ \"$(echo $(stg unapplied))\" = \"p5 p6 p7 p8 p9\" ]\n+    [ \"$(echo $(stg series --applied --noprefix))\" = \"p0 p1 p2 p3 p4\" ] &&\n+    [ \"$(echo $(stg series --unapplied --noprefix))\" = \"p5 p6 p7 p8 p9\" ]\n '\n \n test_expect_success \\\n     'Pop the remaining patches' '\n     stg pop -a &&\n-    [ \"$(echo $(stg applied))\" = \"\" ] &&\n-    [ \"$(echo $(stg unapplied))\" = \"p0 p1 p2 p3 p4 p5 p6 p7 p8 p9\" ]\n+    [ \"$(echo $(stg series --applied --noprefix))\" = \"\" ] &&\n+    [ \"$(echo $(stg series --unapplied --noprefix))\" = \"p0 p1 p2 p3 p4 p5 p6 p7 p8 p9\" ]\n '\n \n test_done\ndiff --git a/t/t1204-pop-keep.sh b/t/t1204-pop-keep.sh\nindex 35f4ec0..db473f2 100755\n--- a/t/t1204-pop-keep.sh\n+++ b/t/t1204-pop-keep.sh\n@@ -11,8 +11,8 @@ test_expect_success 'Create a few patches' '\n         git add patch$i.txt &&\n         stg refresh\n     done &&\n-    [ \"$(echo $(stg applied))\" = \"p0 p1 p2\" ] &&\n-    [ \"$(echo $(stg unapplied))\" = \"\" ]\n+    [ \"$(echo $(stg series --applied --noprefix))\" = \"p0 p1 p2\" ] &&\n+    [ \"$(echo $(stg series --unapplied --noprefix))\" = \"\" ]\n '\n \n test_expect_success 'Make some non-conflicting local changes' '\n@@ -21,8 +21,8 @@ test_expect_success 'Make some non-conflicting local changes' '\n \n test_expect_success 'Pop two patches, keeping local changes' '\n     stg pop -n 2 --keep &&\n-    [ \"$(echo $(stg applied))\" = \"p0\" ] &&\n-    [ \"$(echo $(stg unapplied))\" = \"p1 p2\" ] &&\n+    [ \"$(echo $(stg series --applied --noprefix))\" = \"p0\" ] &&\n+    [ \"$(echo $(stg series --unapplied --noprefix))\" = \"p1 p2\" ] &&\n     [ \"$(echo $(ls patch?.txt))\" = \"patch0.txt\" ] &&\n     [ \"$(echo $(cat patch0.txt))\" = \"patch0 local\" ]\n '\n@@ -34,8 +34,8 @@ test_expect_success 'Reset and push patches again' '\n \n test_expect_success 'Pop a patch without local changes' '\n     stg pop --keep &&\n-    [ \"$(echo $(stg applied))\" = \"p0 p1\" ] &&\n-    [ \"$(echo $(stg unapplied))\" = \"p2\" ] &&\n+    [ \"$(echo $(stg series --applied --noprefix))\" = \"p0 p1\" ] &&\n+    [ \"$(echo $(stg series --unapplied --noprefix))\" = \"p2\" ] &&\n     [ \"$(echo $(ls patch?.txt))\" = \"patch0.txt patch1.txt\" ]\n '\n \ndiff --git a/t/t1205-push-subdir.sh b/t/t1205-push-subdir.sh\nindex 175d36d..27d93da 100755\n--- a/t/t1205-push-subdir.sh\n+++ b/t/t1205-push-subdir.sh\n@@ -12,8 +12,8 @@ test_expect_success 'Create some patches' '\n         git add x.txt foo/y.txt &&\n         stg refresh\n     done &&\n-    [ \"$(echo $(stg applied))\" = \"p0 p1 p2\" ] &&\n-    [ \"$(echo $(stg unapplied))\" = \"\" ]\n+    [ \"$(echo $(stg series --applied --noprefix))\" = \"p0 p1 p2\" ] &&\n+    [ \"$(echo $(stg series --unapplied --noprefix))\" = \"\" ]\n '\n \n test_expect_success 'Fast-forward push from a subdir' '\ndiff --git a/t/t1301-repair.sh b/t/t1301-repair.sh\nindex b555b93..bf4382e 100755\n--- a/t/t1301-repair.sh\n+++ b/t/t1301-repair.sh\n@@ -37,9 +37,9 @@ test_expect_success \\\n     '\n \n test_expect_success 'Turn one GIT commit into a patch' '\n-    [ $(stg applied | wc -l) -eq 1 ] &&\n+    [ $(stg series --applied -c) -eq 1 ] &&\n     stg repair &&\n-    [ $(stg applied | wc -l) -eq 2 ]\n+    [ $(stg series --applied -c) -eq 2 ]\n     '\n \n test_expect_success \\\n@@ -55,9 +55,9 @@ test_expect_success \\\n     '\n \n test_expect_success 'Turn three GIT commits into patches' '\n-    [ $(stg applied | wc -l) -eq 2 ] &&\n+    [ $(stg series --applied -c) -eq 2 ] &&\n     stg repair &&\n-    [ $(stg applied | wc -l) -eq 5 ]\n+    [ $(stg series --applied -c) -eq 5 ]\n     '\n \n test_expect_success \\\n@@ -72,9 +72,9 @@ test_expect_success \\\n     '\n \n test_expect_success 'Repair in the presence of a merge commit' '\n-    [ $(stg applied | wc -l) -eq 5 ] &&\n+    [ $(stg series --applied -c) -eq 5 ] &&\n     stg repair &&\n-    [ $(stg applied | wc -l) -eq 0 ]\n+    [ $(stg series --applied -c) -eq 0 ]\n '\n \n test_done\ndiff --git a/t/t1302-repair-interop.sh b/t/t1302-repair-interop.sh\nindex 82c5ed2..5762111 100755\n--- a/t/t1302-repair-interop.sh\n+++ b/t/t1302-repair-interop.sh\n@@ -21,8 +21,8 @@ test_expect_success 'Create five patches' '\n     for i in 0 1 2 3 4; do\n         stg new p$i -m p$i;\n     done &&\n-    [ \"$(echo $(stg applied))\" = \"p0 p1 p2 p3 p4\" ] &&\n-    [ \"$(echo $(stg unapplied))\" = \"\" ]\n+    [ \"$(echo $(stg series --applied --noprefix))\" = \"p0 p1 p2 p3 p4\" ] &&\n+    [ \"$(echo $(stg series --unapplied --noprefix))\" = \"\" ]\n '\n \n test_expect_success 'Pop two patches with git-reset' '\n@@ -30,14 +30,14 @@ test_expect_success 'Pop two patches with git-reset' '\n     ! stg refresh &&\n     stg repair &&\n     stg refresh &&\n-    [ \"$(echo $(stg applied))\" = \"p0 p1 p2\" ] &&\n-    [ \"$(echo $(stg unapplied))\" = \"p3 p4\" ]\n+    [ \"$(echo $(stg series --applied --noprefix))\" = \"p0 p1 p2\" ] &&\n+    [ \"$(echo $(stg series --unapplied --noprefix))\" = \"p3 p4\" ]\n '\n \n test_expect_success 'Create a new patch' '\n     stg new q0 -m q0 &&\n-    [ \"$(echo $(stg applied))\" = \"p0 p1 p2 q0\" ] &&\n-    [ \"$(echo $(stg unapplied))\" = \"p3 p4\" ]\n+    [ \"$(echo $(stg series --applied --noprefix))\" = \"p0 p1 p2 q0\" ] &&\n+    [ \"$(echo $(stg series --unapplied --noprefix))\" = \"p3 p4\" ]\n '\n \n test_expect_success 'Go to an unapplied patch with with git-reset' '\n@@ -45,15 +45,15 @@ test_expect_success 'Go to an unapplied patch with with git-reset' '\n     ! stg refresh &&\n     stg repair &&\n     stg refresh &&\n-    [ \"$(echo $(stg applied))\" = \"p0 p1 p2 p3\" ] &&\n-    [ \"$(echo $(stg unapplied))\" = \"q0 p4\" ]\n+    [ \"$(echo $(stg series --applied --noprefix))\" = \"p0 p1 p2 p3\" ] &&\n+    [ \"$(echo $(stg series --unapplied --noprefix))\" = \"q0 p4\" ]\n '\n \n test_expect_success 'Go back to below the stack base with git-reset' '\n     git reset --hard foo-tag &&\n     stg repair &&\n-    [ \"$(echo $(stg applied))\" = \"\" ] &&\n-    [ \"$(echo $(stg unapplied))\" = \"p0 p1 p2 p3 q0 p4\" ]\n+    [ \"$(echo $(stg series --applied --noprefix))\" = \"\" ] &&\n+    [ \"$(echo $(stg series --unapplied --noprefix))\" = \"p0 p1 p2 p3 q0 p4\" ]\n '\n \n test_done\ndiff --git a/t/t1500-float.sh b/t/t1500-float.sh\nindex 778fde4..e44af3a 100755\n--- a/t/t1500-float.sh\n+++ b/t/t1500-float.sh\n@@ -20,37 +20,37 @@ test_expect_success \\\n \t stg new F -m \"f\" && echo F >f.txt && git add f.txt && stg refresh &&\n \t stg new G -m \"g\" && echo G >g.txt && git add g.txt && stg refresh &&\n \t stg pop &&\n-\t test \"$(echo $(stg applied))\" = \"A B C D E F\"\n+\t test \"$(echo $(stg series --applied --noprefix))\" = \"A B C D E F\"\n \t'\n \n test_expect_success \\\n \t'Float A to top' \\\n \t'stg float A &&\n-\t test \"$(echo $(stg applied))\" = \"B C D E F A\"\n+\t test \"$(echo $(stg series --applied --noprefix))\" = \"B C D E F A\"\n \t'\n test_expect_success \\\n \t'Float A to top (noop)' \\\n \t'stg float A &&\n-\t test \"$(echo $(stg applied))\" = \"B C D E F A\"\n+\t test \"$(echo $(stg series --applied --noprefix))\" = \"B C D E F A\"\n \t'\n test_expect_success \\\n \t'Float B C to top' \\\n \t'stg float B C &&\n-\t test \"$(echo $(stg applied))\" = \"D E F A B C\"\n+\t test \"$(echo $(stg series --applied --noprefix))\" = \"D E F A B C\"\n \t'\n test_expect_success \\\n \t'Float E A to top' \\\n \t'stg float E A &&\n-\t test \"$(echo $(stg applied))\" = \"D F B C E A\"\n+\t test \"$(echo $(stg series --applied --noprefix))\" = \"D F B C E A\"\n \t'\n test_expect_success \\\n \t'Float E to top' \\\n \t'stg float E &&\n-\t test \"$(echo $(stg applied))\" = \"D F B C A E\"\n+\t test \"$(echo $(stg series --applied --noprefix))\" = \"D F B C A E\"\n \t'\n test_expect_success \\\n \t'Float G F to top' \\\n \t'stg float G F &&\n-\t test \"$(echo $(stg applied))\" = \"D B C A E G F\"\n+\t test \"$(echo $(stg series --applied --noprefix))\" = \"D B C A E G F\"\n \t'\n test_done\ndiff --git a/t/t1600-delete-one.sh b/t/t1600-delete-one.sh\nindex c3451d8..51e4d5b 100755\n--- a/t/t1600-delete-one.sh\n+++ b/t/t1600-delete-one.sh\n@@ -19,27 +19,27 @@ test_expect_success \\\n test_expect_success \\\n     'Try to delete a non-existing patch' \\\n     '\n-    [ $(stg applied | wc -l) -eq 1 ] &&\n+    [ $(stg series --applied -c) -eq 1 ] &&\n     ! stg delete bar &&\n-    [ $(stg applied | wc -l) -eq 1 ]\n+    [ $(stg series --applied -c) -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 series --applied -c) -eq 1 ] &&\n     ! stg delete foo &&\n-    [ $(stg applied | wc -l) -eq 1 ] &&\n+    [ $(stg series --applied -c) -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 series --applied -c) -eq 1 ] &&\n     stg delete foo &&\n-    [ $(stg applied | wc -l) -eq 0 ]\n+    [ $(stg series --applied -c) -eq 0 ]\n     '\n \n test_expect_success \\\n@@ -55,9 +55,9 @@ test_expect_success \\\n test_expect_success \\\n     'Delete an unapplied patch' \\\n     '\n-    [ $(stg unapplied | wc -l) -eq 1 ] &&\n+    [ $(stg series --unapplied -c) -eq 1 ] &&\n     stg delete foo &&\n-    [ $(stg unapplied | wc -l) -eq 0 ]\n+    [ $(stg series --unapplied -c) -eq 0 ]\n     '\n \n test_expect_success \\\n@@ -76,9 +76,9 @@ test_expect_success \\\n test_expect_success \\\n     'Try to delete a non-topmost applied patch' \\\n     '\n-    [ $(stg applied | wc -l) -eq 2 ] &&\n+    [ $(stg series --applied -c) -eq 2 ] &&\n     stg delete foo &&\n-    [ $(stg applied | wc -l) -eq 1 ]\n+    [ $(stg series --applied -c) -eq 1 ]\n     '\n \n test_expect_success \\\n@@ -99,11 +99,11 @@ test_expect_success \\\n test_expect_success \\\n     'Delete a patch in another branch' \\\n     '\n-    [ $(stg applied | wc -l) -eq 2 ] &&\n-    [ $(stg applied -b br | wc -l) -eq 1 ] &&\n+    [ $(stg series --applied -c) -eq 2 ] &&\n+    [ $(stg series --applied -b br -c) -eq 1 ] &&\n     stg delete -b br baz &&\n-    [ $(stg applied | wc -l) -eq 2 ] &&\n-    [ $(stg applied -b br | wc -l) -eq 0 ]\n+    [ $(stg series --applied -c) -eq 2 ] &&\n+    [ $(stg series --applied -b br -c) -eq 0 ]\n     '\n \n test_done\ndiff --git a/t/t1601-delete-many.sh b/t/t1601-delete-many.sh\nindex 30b0a1d..a254980 100755\n--- a/t/t1601-delete-many.sh\n+++ b/t/t1601-delete-many.sh\n@@ -25,31 +25,31 @@ test_expect_success \\\n test_expect_success \\\n     'Delete some patches' \\\n     '\n-    [ \"$(echo $(stg applied))\" = \"p0 p1 p2 p3 p4\" ] &&\n-    [ \"$(echo $(stg unapplied))\" = \"p5 p6 p7 p8 p9\" ] &&\n+    [ \"$(echo $(stg series --applied --noprefix))\" = \"p0 p1 p2 p3 p4\" ] &&\n+    [ \"$(echo $(stg series --unapplied --noprefix))\" = \"p5 p6 p7 p8 p9\" ] &&\n     stg delete p7 p6 p3 p4 &&\n-    [ \"$(echo $(stg applied))\" = \"p0 p1 p2\" ] &&\n-    [ \"$(echo $(stg unapplied))\" = \"p5 p8 p9\" ]\n+    [ \"$(echo $(stg series --applied --noprefix))\" = \"p0 p1 p2\" ] &&\n+    [ \"$(echo $(stg series --unapplied --noprefix))\" = \"p5 p8 p9\" ]\n     '\n \n test_expect_success \\\n     'Delete some more patches, some of which do not exist' \\\n     '\n-    [ \"$(echo $(stg applied))\" = \"p0 p1 p2\" ] &&\n-    [ \"$(echo $(stg unapplied))\" = \"p5 p8 p9\" ] &&\n+    [ \"$(echo $(stg series --applied --noprefix))\" = \"p0 p1 p2\" ] &&\n+    [ \"$(echo $(stg series --unapplied --noprefix))\" = \"p5 p8 p9\" ] &&\n     ! stg delete p7 p8 p2 p0 &&\n-    [ \"$(echo $(stg applied))\" = \"p0 p1 p2\" ] &&\n-    [ \"$(echo $(stg unapplied))\" = \"p5 p8 p9\" ]\n+    [ \"$(echo $(stg series --applied --noprefix))\" = \"p0 p1 p2\" ] &&\n+    [ \"$(echo $(stg series --unapplied --noprefix))\" = \"p5 p8 p9\" ]\n     '\n \n test_expect_success \\\n     'Delete a range of patches' \\\n     '\n-    [ \"$(echo $(stg applied))\" = \"p0 p1 p2\" ] &&\n-    [ \"$(echo $(stg unapplied))\" = \"p5 p8 p9\" ] &&\n+    [ \"$(echo $(stg series --applied --noprefix))\" = \"p0 p1 p2\" ] &&\n+    [ \"$(echo $(stg series --unapplied --noprefix))\" = \"p5 p8 p9\" ] &&\n     stg delete p1..p8 &&\n-    [ \"$(echo $(stg applied))\" = \"p0\" ] &&\n-    [ \"$(echo $(stg unapplied))\" = \"p9\" ]\n+    [ \"$(echo $(stg series --applied --noprefix))\" = \"p0\" ] &&\n+    [ \"$(echo $(stg series --unapplied --noprefix))\" = \"p9\" ]\n     '\n \n test_done\ndiff --git a/t/t2000-sync.sh b/t/t2000-sync.sh\nindex 4a00c56..2049c28 100755\n--- a/t/t2000-sync.sh\n+++ b/t/t2000-sync.sh\n@@ -30,8 +30,8 @@ test_expect_success \\\n     stg refresh &&\n     stg export &&\n     stg pop &&\n-    [ \"$(echo $(stg applied))\" = \"p1 p2\" ] &&\n-    [ \"$(echo $(stg unapplied))\" = \"p3\" ]\n+    [ \"$(echo $(stg series --applied --noprefix))\" = \"p1 p2\" ] &&\n+    [ \"$(echo $(stg series --unapplied --noprefix))\" = \"p3\" ]\n     '\n \n test_expect_success \\\n@@ -41,16 +41,16 @@ test_expect_success \\\n     stg new p1 -m p1 &&\n     stg new p2 -m p2 &&\n     stg new p3 -m p3 &&\n-    [ \"$(echo $(stg applied))\" = \"p1 p2 p3\" ] &&\n-    [ \"$(echo $(stg unapplied))\" = \"\" ]\n+    [ \"$(echo $(stg series --applied --noprefix))\" = \"p1 p2 p3\" ] &&\n+    [ \"$(echo $(stg series --unapplied --noprefix))\" = \"\" ]\n     '\n \n test_expect_success \\\n     'Synchronise second patch with the master branch' \\\n     '\n     stg sync -B master p2 &&\n-    [ \"$(echo $(stg applied))\" = \"p1 p2 p3\" ] &&\n-    [ \"$(echo $(stg unapplied))\" = \"\" ] &&\n+    [ \"$(echo $(stg series --applied --noprefix))\" = \"p1 p2 p3\" ] &&\n+    [ \"$(echo $(stg series --unapplied --noprefix))\" = \"\" ] &&\n     test $(cat foo2.txt) = \"foo2\"\n     '\n \n@@ -58,8 +58,8 @@ test_expect_success \\\n     'Synchronise the first two patches with the master branch' \\\n     '\n     stg sync -B master -a &&\n-    [ \"$(echo $(stg applied))\" = \"p1 p2 p3\" ] &&\n-    [ \"$(echo $(stg unapplied))\" = \"\" ] &&\n+    [ \"$(echo $(stg series --applied --noprefix))\" = \"p1 p2 p3\" ] &&\n+    [ \"$(echo $(stg series --unapplied --noprefix))\" = \"\" ] &&\n     test $(cat foo1.txt) = \"foo1\" &&\n     test $(cat foo2.txt) = \"foo2\"\n     '\n@@ -68,8 +68,8 @@ test_expect_success \\\n     'Synchronise all the patches with the exported series' \\\n     '\n     stg sync -s patches-master/series -a &&\n-    [ \"$(echo $(stg applied))\" = \"p1 p2 p3\" ] &&\n-    [ \"$(echo $(stg unapplied))\" = \"\" ] &&\n+    [ \"$(echo $(stg series --applied --noprefix))\" = \"p1 p2 p3\" ] &&\n+    [ \"$(echo $(stg series --unapplied --noprefix))\" = \"\" ] &&\n     test $(cat foo1.txt) = \"foo1\" &&\n     test $(cat foo2.txt) = \"foo2\" &&\n     test $(cat foo3.txt) = \"foo3\"\n@@ -79,8 +79,8 @@ test_expect_success \\\n     'Modify the master patches' \\\n     '\n     stg branch master &&\n-    [ \"$(echo $(stg applied))\" = \"p1 p2\" ] &&\n-    [ \"$(echo $(stg unapplied))\" = \"p3\" ] &&\n+    [ \"$(echo $(stg series --applied --noprefix))\" = \"p1 p2\" ] &&\n+    [ \"$(echo $(stg series --unapplied --noprefix))\" = \"p3\" ] &&\n     stg goto p1 &&\n     echo bar1 >> foo1.txt &&\n     stg refresh &&\n@@ -91,8 +91,8 @@ test_expect_success \\\n     stg goto p3 &&\n     echo bar3 >> foo3.txt &&\n     stg refresh &&\n-    [ \"$(echo $(stg applied))\" = \"p1 p2 p3\" ] &&\n-    [ \"$(echo $(stg unapplied))\" = \"\" ] &&\n+    [ \"$(echo $(stg series --applied --noprefix))\" = \"p1 p2 p3\" ] &&\n+    [ \"$(echo $(stg series --unapplied --noprefix))\" = \"\" ] &&\n     stg export &&\n     stg branch foo\n     '\n@@ -101,8 +101,8 @@ test_expect_success \\\n     'Synchronise second patch with the master branch' \\\n     '\n     stg sync -B master p2 &&\n-    [ \"$(echo $(stg applied))\" = \"p1 p2 p3\" ] &&\n-    [ \"$(echo $(stg unapplied))\" = \"\" ] &&\n+    [ \"$(echo $(stg series --applied --noprefix))\" = \"p1 p2 p3\" ] &&\n+    [ \"$(echo $(stg series --unapplied --noprefix))\" = \"\" ] &&\n     test $(cat bar2.txt) = \"bar2\"\n     '\n \n@@ -115,13 +115,13 @@ test_expect_success \\\n test_expect_success \\\n     'Restore the stack status after the failed sync' \\\n     '\n-    [ \"$(echo $(stg applied))\" = \"p1\" ] &&\n-    [ \"$(echo $(stg unapplied))\" = \"p2 p3\" ] &&\n+    [ \"$(echo $(stg series --applied --noprefix))\" = \"p1\" ] &&\n+    [ \"$(echo $(stg series --unapplied --noprefix))\" = \"p2 p3\" ] &&\n     stg resolved -a &&\n     stg refresh &&\n     stg goto p3\n-    [ \"$(echo $(stg applied))\" = \"p1 p2 p3\" ] &&\n-    [ \"$(echo $(stg unapplied))\" = \"\" ]\n+    [ \"$(echo $(stg series --applied --noprefix))\" = \"p1 p2 p3\" ] &&\n+    [ \"$(echo $(stg series --unapplied --noprefix))\" = \"\" ]\n     '\n \n test_expect_success \\\n@@ -133,12 +133,12 @@ test_expect_success \\\n test_expect_success \\\n     'Restore the stack status after the failed sync' \\\n     '\n-    [ \"$(echo $(stg applied))\" = \"p1 p2 p3\" ] &&\n-    [ \"$(echo $(stg unapplied))\" = \"\" ] &&\n+    [ \"$(echo $(stg series --applied --noprefix))\" = \"p1 p2 p3\" ] &&\n+    [ \"$(echo $(stg series --unapplied --noprefix))\" = \"\" ] &&\n     stg resolved -a &&\n     stg refresh &&\n-    [ \"$(echo $(stg applied))\" = \"p1 p2 p3\" ] &&\n-    [ \"$(echo $(stg unapplied))\" = \"\" ]\n+    [ \"$(echo $(stg series --applied --noprefix))\" = \"p1 p2 p3\" ] &&\n+    [ \"$(echo $(stg series --unapplied --noprefix))\" = \"\" ]\n     '\n \n test_done\ndiff --git a/t/t2200-rebase.sh b/t/t2200-rebase.sh\nindex cd43c41..12b4af6 100755\n--- a/t/t2200-rebase.sh\n+++ b/t/t2200-rebase.sh\n@@ -28,7 +28,7 @@ test_expect_success \\\n \t'\n \tstg rebase master~1 &&\n \ttest `stg id stack:{base}` = `git rev-parse master~1` &&\n-\ttest `stg applied | wc -l` = 1\n+\ttest `stg series --applied -c` = 1\n \t'\n \n test_expect_success \\\n@@ -40,7 +40,7 @@ test_expect_success \\\n test_expect_success \\\n \t'Check patches were re-applied' \\\n \t'\n-\ttest $(stg applied | wc -l) = 1\n+\ttest $(stg series --applied -c) = 1\n \t'\n \n test_done\ndiff --git a/t/t2500-clean.sh b/t/t2500-clean.sh\nindex ad8f892..063572b 100755\n--- a/t/t2500-clean.sh\n+++ b/t/t2500-clean.sh\n@@ -17,11 +17,11 @@ test_expect_success 'Initialize StGit stack' '\n '\n \n test_expect_success 'Clean empty patches' '\n-    [ \"$(echo $(stg applied))\" = \"e0 p0 e1\" ] &&\n-    [ \"$(echo $(stg unapplied))\" = \"e2\" ] &&\n+    [ \"$(echo $(stg series --applied --noprefix))\" = \"e0 p0 e1\" ] &&\n+    [ \"$(echo $(stg series --unapplied --noprefix))\" = \"e2\" ] &&\n     stg clean &&\n-    [ \"$(echo $(stg applied))\" = \"p0\" ] &&\n-    [ \"$(echo $(stg unapplied))\" = \"\" ]\n+    [ \"$(echo $(stg series --applied --noprefix))\" = \"p0\" ] &&\n+    [ \"$(echo $(stg series --unapplied --noprefix))\" = \"\" ]\n '\n \n test_expect_success 'Create a conflict' '\n@@ -37,8 +37,8 @@ test_expect_success 'Create a conflict' '\n \n test_expect_success 'Make sure conflicting patches are preserved' '\n     stg clean &&\n-    [ \"$(echo $(stg applied))\" = \"p0 p2 p1\" ] &&\n-    [ \"$(echo $(stg unapplied))\" = \"\" ]\n+    [ \"$(echo $(stg series --applied --noprefix))\" = \"p0 p2 p1\" ] &&\n+    [ \"$(echo $(stg series --unapplied --noprefix))\" = \"\" ]\n '\n \n test_done\ndiff --git a/t/t2600-coalesce.sh b/t/t2600-coalesce.sh\nindex f13a309..ef5bf99 100755\n--- a/t/t2600-coalesce.sh\n+++ b/t/t2600-coalesce.sh\n@@ -15,17 +15,17 @@ test_expect_success 'Initialize StGit stack' '\n '\n \n test_expect_success 'Coalesce some patches' '\n-    [ \"$(echo $(stg applied))\" = \"p0 p1 p2 p3\" ] &&\n-    [ \"$(echo $(stg unapplied))\" = \"\" ] &&\n+    [ \"$(echo $(stg series --applied --noprefix))\" = \"p0 p1 p2 p3\" ] &&\n+    [ \"$(echo $(stg series --unapplied --noprefix))\" = \"\" ] &&\n     stg coalesce --name=q0 --message=\"wee woo\" p1 p2 &&\n-    [ \"$(echo $(stg applied))\" = \"p0 q0 p3\" ] &&\n-    [ \"$(echo $(stg unapplied))\" = \"\" ]\n+    [ \"$(echo $(stg series --applied --noprefix))\" = \"p0 q0 p3\" ] &&\n+    [ \"$(echo $(stg series --unapplied --noprefix))\" = \"\" ]\n '\n \n test_expect_success 'Coalesce at stack top' '\n     stg coalesce --name=q1 --message=\"wee woo wham\" q0 p3 &&\n-    [ \"$(echo $(stg applied))\" = \"p0 q1\" ] &&\n-    [ \"$(echo $(stg unapplied))\" = \"\" ]\n+    [ \"$(echo $(stg series --applied --noprefix))\" = \"p0 q1\" ] &&\n+    [ \"$(echo $(stg series --unapplied --noprefix))\" = \"\" ]\n '\n \n test_done\ndiff --git a/t/t3000-dirty-merge.sh b/t/t3000-dirty-merge.sh\nindex d87bba1..a4e228a 100755\n--- a/t/t3000-dirty-merge.sh\n+++ b/t/t3000-dirty-merge.sh\n@@ -24,11 +24,11 @@ test_expect_success 'Pop one patch and update the other' '\n \n test_expect_success 'Push with dirty worktree' '\n     echo 4 > a &&\n-    [ \"$(echo $(stg applied))\" = \"p1\" ] &&\n-    [ \"$(echo $(stg unapplied))\" = \"p2\" ] &&\n+    [ \"$(echo $(stg series --applied --noprefix))\" = \"p1\" ] &&\n+    [ \"$(echo $(stg series --unapplied --noprefix))\" = \"p2\" ] &&\n     ! stg goto p2 &&\n-    [ \"$(echo $(stg applied))\" = \"p1\" ] &&\n-    [ \"$(echo $(stg unapplied))\" = \"p2\" ] &&\n+    [ \"$(echo $(stg series --applied --noprefix))\" = \"p1\" ] &&\n+    [ \"$(echo $(stg series --unapplied --noprefix))\" = \"p2\" ] &&\n     [ \"$(echo $(cat a))\" = \"4\" ]\n '\n \ndiff --git a/t/t4000-upgrade.sh b/t/t4000-upgrade.sh\nindex 8a308fb..01fe248 100755\n--- a/t/t4000-upgrade.sh\n+++ b/t/t4000-upgrade.sh\n@@ -14,8 +14,8 @@ for ver in 0.12 0.8; do\n \n     test_expect_success \\\n         \"v$ver: Check the list of applied and unapplied patches\" '\n-        [ \"$(echo $(stg applied))\" = \"p0 p1 p2\" ] &&\n-        [ \"$(echo $(stg unapplied))\" = \"p3 p4\" ]\n+        [ \"$(echo $(stg series --applied --noprefix))\" = \"p0 p1 p2\" ] &&\n+        [ \"$(echo $(stg series --unapplied --noprefix))\" = \"p3 p4\" ]\n     '\n \n     test_expect_success \\\n"},{"id":"80623","messageId":"20080622151026.GA4468@diana.vm.bytemark.co.uk","threadId":"14045","inReplyTo":"20080619214201.27794.18891.stgit@localhost.localdomain","subject":"Re: [StGIT PATCH 1/4] Allow e-mails to be sent with the Unix sendmail tool","fromName":"Karl Hasselström","fromEmail":"kha@treskal.com","sentAt":"2008-06-22T15:10:26Z","receivedAt":"2008-06-22T15:10:26Z","isPatch":true,"sender":{"key":"kha@treskal.com","avatar":"https://gravatar.com/avatar/f0120c734b5279b345075a28521e1ac66acb20c9913ffe9bf6ae97e53f7f3f13?d=mp&s=160"},"body":"On 2008-06-19 22:42:01 +0100, Catalin Marinas wrote:\n\n> If the stgit.smtpserver configuration option does not have a\n> host:port format, it is assumed to be an external tool. For example,\n> to use sendmail just set this variable to \"/usr/sbin/sendmail -t -i\"\n> (see the examples/gitconfig file).\n\nSome comments below, but it looks good.\n\n> +def __send_message_sendmail(sendmail, msg):\n> +    \"\"\"Send the message using the sendmail command.\n> +    \"\"\"\n> +    cmd = sendmail.split()\n> +    Run(*cmd).raw_input(msg).discard_output()\n\nYou could've written this without the \"cmd\" variable, but I understand\nwhy you didn't. The * operator (or whatever it is) isn't pretty. I\nsort of regret not making Run take a list argument instead, frankly.\n\n>  class GitConfig:\n>      __defaults={\n>          'stgit.autoresolved':\t'no',\n> -        'stgit.smtpserver':\t'localhost:25',\n> +        'stgit.smtpserver':\t'/usr/sbin/sendmail -t -i',\n\nHmm. I think it's actually more common to have a misconfigured (or\ninsufficiently configured) sendmail program than a misconfigured mail\ndaemon listening to port 25, so I'd argue that the default shouldn't\nbe changed. But it's not that important.\n\n-- \nKarl Hasselström, kha@treskal.com\n      www.treskal.com/kalle\n"},{"id":"80624","messageId":"20080622152758.GB4468@diana.vm.bytemark.co.uk","threadId":"14045","inReplyTo":"20080619214210.27794.76950.stgit@localhost.localdomain","subject":"Re: [StGIT PATCH 2/4] Implement a new patch identification scheme and id command","fromName":"Karl Hasselström","fromEmail":"kha@treskal.com","sentAt":"2008-06-22T15:27:58Z","receivedAt":"2008-06-22T15:27:58Z","isPatch":true,"sender":{"key":"kha@treskal.com","avatar":"https://gravatar.com/avatar/f0120c734b5279b345075a28521e1ac66acb20c9913ffe9bf6ae97e53f7f3f13?d=mp&s=160"},"body":"On 2008-06-19 22:42:10 +0100, Catalin Marinas wrote:\n\n> The new scheme allows '[<branch>:]<patch>' and '[<branch>:]{base}'\n> (the latter showing the base of a stack). The former format allows\n> symbols like ^ and ^{...}.\n\nHmm. Why only the former? Supporting it for the latter should be easy.\n(Though it would take some extra work, I guess.)\n\nOther than that, it looks good to me.\n\n> +def git_commit(name, repository, branch = None):\n> +    \"\"\"Return the a Commit object if 'name' is a patch name or Git commit.\n> +    The patch names allowed are in the form '<branch>:<patch>' and can be\n> +    followed by standard symbols used by git-rev-parse. If <patch> is '{base}',\n\nLong line.\n\n> +    # The stack base\n> +    if patch == '{base}':\n> +        return repository.get_stack(branch).base\n\nShould be a simple matter of\n\n  if patch.startswith('{base}'):\n      foo = repository.get_stack(branch).base + drop_prefix(patch, '{base}')\n      return repository.rev_parse(foo)\n\nor something.\n\n-- \nKarl Hasselström, kha@treskal.com\n      www.treskal.com/kalle\n"},{"id":"80625","messageId":"20080622154854.GC4468@diana.vm.bytemark.co.uk","threadId":"14045","inReplyTo":"20080619214222.27794.74083.stgit@localhost.localdomain","subject":"Re: [StGIT PATCH 3/4] Convert git_id() to the new id format","fromName":"Karl Hasselström","fromEmail":"kha@treskal.com","sentAt":"2008-06-22T15:48:54Z","receivedAt":"2008-06-22T15:48:54Z","isPatch":true,"sender":{"key":"kha@treskal.com","avatar":"https://gravatar.com/avatar/f0120c734b5279b345075a28521e1ac66acb20c9913ffe9bf6ae97e53f7f3f13?d=mp&s=160"},"body":"On 2008-06-19 22:42:22 +0100, Catalin Marinas wrote:\n\n> The patch rewrites git_id() to use the new id format and coverts the\n> commands using this function. The git_id() will be removed once all\n> the commands are converted to the new infrastructure where\n> git_commit() will be used instead.\n\nLooks good. And the code volume reduction is significant.\n\n>      if not rev:\n> +        # backwards compatibility\n>          return None\n\nCould you expand this comment a bit? It's not enough of a clue for me.\n:-/\n\n> -def git_commit(name, repository, branch = None):\n> +def git_commit(name, repository, branch_name = None):\n\nVery nice parameter rename here, now that we have Branch objects (and\nuse a crappy language with no type system).\n\n> -rev = '([patch][//[bottom | top]]) | <tree-ish> | base'\n> -\n> -If neither bottom nor top are given but a '//' is present, the command\n> -shows the specified patch (defaulting to the current one).\"\"\"\n> +rev = '([branch:]patch) | <tree-ish> | base'\n\nYou can remove the parentheses now; they were only needed because they\nused to enclose a complicated expression. Besides, shouldn't it be\n[branch:]{base} instead of base? So something like\n\n  rev = [<branch>:]<patch> | [<branch>:]{base} | <tree-ish>\n\n>  help = 'show the files modified by a patch (or the current patch)'\n> -usage = \"\"\"%prog [options] [<patch>]\n> +usage = \"\"\"%prog [options] [[<branch>:]<patch>]\n\nUnrelated to this patch: I realized last week that it's silly for stg\nfiles to not accept a patch range.\n\n>      if len(args) == 0:\n> -        patch = ''\n> +        patch = 'HEAD'\n\nAh, so this is the backwards compatibility thing -- we used to pass\nthe empty string when we meant HEAD.\n\n> -        (refpatchname, refbranchname, refpatchid) = parse_rev(patchname)\n> -        if refpatchname and not refpatchid and \\\n> -               (not refpatchid or refpatchid == 'top'):\n> -            # FIXME: should also support picking //top.old\n> +        refbranchname, refpatchname = parse_rev(patchname)\n> +        if refpatchname:\n\nThe corresponding TODO comment now would be that pick should be able\nto pick patches from the past, from the stack log.\n\n-- \nKarl Hasselström, kha@treskal.com\n      www.treskal.com/kalle\n"},{"id":"80626","messageId":"20080622161341.GD4468@diana.vm.bytemark.co.uk","threadId":"14045","inReplyTo":"20080619214233.27794.98487.stgit@localhost.localdomain","subject":"Re: [StGIT PATCH 4/4] Remove the applied/unapplied commands","fromName":"Karl Hasselström","fromEmail":"kha@treskal.com","sentAt":"2008-06-22T16:13:41Z","receivedAt":"2008-06-22T16:13:41Z","isPatch":true,"sender":{"key":"kha@treskal.com","avatar":"https://gravatar.com/avatar/f0120c734b5279b345075a28521e1ac66acb20c9913ffe9bf6ae97e53f7f3f13?d=mp&s=160"},"body":"On 2008-06-19 22:42:33 +0100, Catalin Marinas wrote:\n\n> This patch moves the applied/unapplied functionality to the 'series'\n> command via the corresponding options.\n\nNice.\n\n>             make_option('-a', '--all',\n>                         help = 'show all patches, including the hidden ones',\n>                         action = 'store_true'),\n> +           make_option('--applied',\n> +                       help = 'show the applied patches only',\n> +                       action = 'store_true'),\n> +           make_option('--unapplied',\n> +                       help = 'show the unapplied patches only',\n> +                       action = 'store_true'),\n>             make_option('--hidden',\n>                         help = 'show the hidden patches only',\n>                         action = 'store_true'),\n\nMaybe some logic to prohibit the use of more than one of these at\nonce? The current logic is kind of arbitrary.\n\nAlso, we should perhaps invent good single-letter abbreviations for\nthese presumably rather common flags. -a is taken; -A and -U perhaps?\n\n-- \nKarl Hasselström, kha@treskal.com\n      www.treskal.com/kalle\n"},{"id":"81675","messageId":"b0943d9e0806291455j2684514bt5c0cb23e0f4d6c03@mail.gmail.com","threadId":"14045","inReplyTo":"20080622151026.GA4468@diana.vm.bytemark.co.uk","subject":"Re: [StGIT PATCH 1/4] Allow e-mails to be sent with the Unix sendmail tool","fromName":"Catalin Marinas","fromEmail":"catalin.marinas@gmail.com","sentAt":"2008-06-29T21:55:43Z","receivedAt":"2008-06-29T21:55:43Z","isPatch":true,"sender":{"key":"catalin.marinas@gmail.com","avatar":null},"body":"2008/6/22 Karl Hasselström <kha@treskal.com>:\n> On 2008-06-19 22:42:01 +0100, Catalin Marinas wrote:\n>>  class GitConfig:\n>>      __defaults={\n>>          'stgit.autoresolved':        'no',\n>> -        'stgit.smtpserver':  'localhost:25',\n>> +        'stgit.smtpserver':  '/usr/sbin/sendmail -t -i',\n>\n> Hmm. I think it's actually more common to have a misconfigured (or\n> insufficiently configured) sendmail program than a misconfigured mail\n> daemon listening to port 25, so I'd argue that the default shouldn't\n> be changed. But it's not that important.\n\nOK, I'll leave the existing default (but I found in recent years that\nmajor Linux distributions come with pretty sane configuration).\n\n-- \nCatalin\n"},{"id":"83135","messageId":"b0943d9e0807130420v37e36f30sef8b7745fa55b688@mail.gmail.com","threadId":"14045","inReplyTo":"20080622154854.GC4468@diana.vm.bytemark.co.uk","subject":"Re: [StGIT PATCH 3/4] Convert git_id() to the new id format","fromName":"Catalin Marinas","fromEmail":"catalin.marinas@gmail.com","sentAt":"2008-07-13T11:20:25Z","receivedAt":"2008-07-13T11:20:25Z","isPatch":true,"sender":{"key":"catalin.marinas@gmail.com","avatar":null},"body":"2008/6/22 Karl Hasselström <kha@treskal.com>:\n> On 2008-06-19 22:42:22 +0100, Catalin Marinas wrote:\n>\n>> The patch rewrites git_id() to use the new id format and coverts the\n>> commands using this function. The git_id() will be removed once all\n>> the commands are converted to the new infrastructure where\n>> git_commit() will be used instead.\n[...[\n>>      if not rev:\n>> +        # backwards compatibility\n>>          return None\n>\n> Could you expand this comment a bit? It's not enough of a clue for me.\n> :-/\n\nI removed it, the diff command used to pass None as rev2 if the user\nonly passed one boundary of the range. I fixed diff and removed the\nabove.\n\n>> -def git_commit(name, repository, branch = None):\n>> +def git_commit(name, repository, branch_name = None):\n>\n> Very nice parameter rename here, now that we have Branch objects (and\n> use a crappy language with no type system).\n\nIt has a type system but no compile-time checking (I'm more in favour\nof static typing but no time to rewrite stgit :-)).\n\n>> -        (refpatchname, refbranchname, refpatchid) = parse_rev(patchname)\n>> -        if refpatchname and not refpatchid and \\\n>> -               (not refpatchid or refpatchid == 'top'):\n>> -            # FIXME: should also support picking //top.old\n>> +        refbranchname, refpatchname = parse_rev(patchname)\n>> +        if refpatchname:\n>\n> The corresponding TODO comment now would be that pick should be able\n> to pick patches from the past, from the stack log.\n\nHow would the syntax look like?\n\n-- \nCatalin\n"},{"id":"83137","messageId":"b0943d9e0807130431q58a74e95j53458d502c3e7a0a@mail.gmail.com","threadId":"14045","inReplyTo":"20080622161341.GD4468@diana.vm.bytemark.co.uk","subject":"Re: [StGIT PATCH 4/4] Remove the applied/unapplied commands","fromName":"Catalin Marinas","fromEmail":"catalin.marinas@gmail.com","sentAt":"2008-07-13T11:31:20Z","receivedAt":"2008-07-13T11:31:20Z","isPatch":true,"sender":{"key":"catalin.marinas@gmail.com","avatar":null},"body":"2008/6/22 Karl Hasselström <kha@treskal.com>:\n> On 2008-06-19 22:42:33 +0100, Catalin Marinas wrote:\n>\n>> This patch moves the applied/unapplied functionality to the 'series'\n>> command via the corresponding options.\n[...]\n>>             make_option('-a', '--all',\n>>                         help = 'show all patches, including the hidden ones',\n>>                         action = 'store_true'),\n>> +           make_option('--applied',\n>> +                       help = 'show the applied patches only',\n>> +                       action = 'store_true'),\n>> +           make_option('--unapplied',\n>> +                       help = 'show the unapplied patches only',\n>> +                       action = 'store_true'),\n>>             make_option('--hidden',\n>>                         help = 'show the hidden patches only',\n>>                         action = 'store_true'),\n>\n> Maybe some logic to prohibit the use of more than one of these at\n> once? The current logic is kind of arbitrary.\n\nI decided to allow a combination of applied/unapplied/hidden but not\ntogether with all. I'll post the patches again.\n\n-- \nCatalin\n"},{"id":"83222","messageId":"20080714064434.GE20751@diana.vm.bytemark.co.uk","threadId":"14045","inReplyTo":"b0943d9e0807130420v37e36f30sef8b7745fa55b688@mail.gmail.com","subject":"Re: [StGIT PATCH 3/4] Convert git_id() to the new id format","fromName":"Karl Hasselström","fromEmail":"kha@treskal.com","sentAt":"2008-07-14T06:44:34Z","receivedAt":"2008-07-14T06:44:34Z","isPatch":true,"sender":{"key":"kha@treskal.com","avatar":"https://gravatar.com/avatar/f0120c734b5279b345075a28521e1ac66acb20c9913ffe9bf6ae97e53f7f3f13?d=mp&s=160"},"body":"On 2008-07-13 12:20:25 +0100, Catalin Marinas wrote:\n\n> 2008/6/22 Karl Hasselström <kha@treskal.com>:\n>\n> > Very nice parameter rename here, now that we have Branch objects\n> > (and use a crappy language with no type system).\n>\n> It has a type system but no compile-time checking\n\nYeah, that's what I meant.\n\n> (I'm more in favour of static typing but no time to rewrite stgit\n> :-)).\n\nMe too.\n\n> > The corresponding TODO comment now would be that pick should be\n> > able to pick patches from the past, from the stack log.\n>\n> How would the syntax look like?\n\nWe'd want to support <committish>:patch, for any committish that's a\nstack log (either simplified or full). Not sure if we'd want a more\npretty-looking format as well.\n\n-- \nKarl Hasselström, kha@treskal.com\n      www.treskal.com/kalle\n"}]}