{"thread":{"id":"12014","subject":"StGit: kha/safe and kha/experimental updated","startedAt":"2008-02-10T20:36:40Z","lastAt":"2008-02-12T23:08:42Z","messageCount":21,"participants":["Karl Hasselström","David Kågedal","Catalin Marinas","Peter Oberndorfer"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"68260","messageId":"20080210203640.GA19688@diana.vm.bytemark.co.uk","threadId":"12014","inReplyTo":null,"subject":"StGit: kha/safe and kha/experimental updated","fromName":"Karl Hasselström","fromEmail":"kha@treskal.com","sentAt":"2008-02-10T20:36:40Z","receivedAt":"2008-02-10T20:36:40Z","isPatch":false,"sender":{"key":"kha@treskal.com","avatar":"https://gravatar.com/avatar/f0120c734b5279b345075a28521e1ac66acb20c9913ffe9bf6ae97e53f7f3f13?d=mp&s=160"},"body":"Both branches updated. I've promoted some experimental patches to\nsafe, and done some work on new and delete (will post the patches in\nreply to this mail).\n\n                                 -+-\n\nThe following changes since commit a639e7bbf3a6396254af76062ee88c22e4373340:\n  Karl Hasselström (1):\n        Don't clean away patches with conflicts\n\nare available in the git repository at:\n\n  git://repo.or.cz/stgit/kha.git safe\n\nKarl Hasselström (11):\n      Don't check out files if we don't have index+workdir\n      Make documentation less confusing\n      Reduce number of backslashes by using raw strings\n      Let \"stg show\" use the unified --diff-opts handling\n      Read default diff options from the user's config\n      Teach new infrastructure about the default author and committer\n      Teach new infrastructure to apply patches\n      Teach new infrastructure to diff two trees\n      Parse the date instead of treating it as an opaque string\n      Convert \"stg edit\" to the new infrastructure\n      Emacs mode: It's possible to edit unapplied patches now\n\nPeter Oberndorfer (1):\n      Add an --index option to \"stg refresh\"\n\n contrib/stgit.el          |    4 +-\n examples/gitconfig        |    4 +\n stgit/commands/common.py  |    4 +-\n stgit/commands/edit.py    |  309 +++++++++++++++++++++------------------------\n stgit/commands/mail.py    |    4 +-\n stgit/commands/new.py     |    6 +-\n stgit/commands/refresh.py |   25 +++-\n stgit/commands/show.py    |   13 +--\n stgit/lib/git.py          |  126 ++++++++++++++++++-\n stgit/lib/transaction.py  |   13 +-\n stgit/utils.py            |    3 +-\n t/t2700-refresh.sh        |   57 ++++++++-\n 12 files changed, 368 insertions(+), 200 deletions(-)\n\n                                 -+-\n\nThe following changes since commit 8ae7dc9d485fe5f3fee02ead7f25133be7321614:\n  Karl Hasselström (1):\n        Emacs mode: It's possible to edit unapplied patches now\n\nare available in the git repository at:\n\n  git://repo.or.cz/stgit/kha.git experimental\n\nKarl Hasselström (7):\n      Disable patchlog test for \"stg new\"\n      Convert \"stg new\" to the new infrastructure\n      Refactor --author/--committer options\n      Let \"stg new\" support more message options\n      Emacs mode: use \"stg new --file\"\n      Convert \"stg delete\" to the new infrastructure\n      Emacs mode: delete patches\n\n contrib/stgit.el         |   20 +++++----\n stgit/commands/common.py |   33 +++++----------\n stgit/commands/delete.py |   72 +++++++++++-----------------------\n stgit/commands/edit.py   |   25 +----------\n stgit/commands/new.py    |   97 +++++++++++++++++++++++++--------------------\n stgit/lib/git.py         |    8 ++--\n stgit/utils.py           |   50 +++++++++++++++++++++++\n t/t1400-patch-history.sh |    2 -\n t/t1600-delete-one.sh    |    8 ++--\n 9 files changed, 160 insertions(+), 155 deletions(-)\n\n-- \nKarl Hasselström, kha@treskal.com\n      www.treskal.com/kalle\n"},{"id":"68261","messageId":"20080210203846.17683.43153.stgit@yoghurt","threadId":"12014","inReplyTo":"20080210203640.GA19688@diana.vm.bytemark.co.uk","subject":"[StGit PATCH 0/5] Convert \"stg new\" to the new infrastructure","fromName":"Karl Hasselström","fromEmail":"kha@treskal.com","sentAt":"2008-02-10T20:40:56Z","receivedAt":"2008-02-10T20:40:56Z","isPatch":true,"sender":{"key":"kha@treskal.com","avatar":"https://gravatar.com/avatar/f0120c734b5279b345075a28521e1ac66acb20c9913ffe9bf6ae97e53f7f3f13?d=mp&s=160"},"body":"---\n\nKarl Hasselström (5):\n      Emacs mode: use \"stg new --file\"\n      Let \"stg new\" support more message options\n      Refactor --author/--committer options\n      Convert \"stg new\" to the new infrastructure\n      Disable patchlog test for \"stg new\"\n\n\n contrib/stgit.el         |   10 +----\n stgit/commands/common.py |   33 +++++-----------\n stgit/commands/edit.py   |   25 +-----------\n stgit/commands/new.py    |   97 ++++++++++++++++++++++++++--------------------\n stgit/lib/git.py         |    8 ++--\n stgit/utils.py           |   50 ++++++++++++++++++++++++\n t/t1400-patch-history.sh |    2 -\n 7 files changed, 124 insertions(+), 101 deletions(-)\n\n-- \nKarl Hasselström, kha@treskal.com\n      www.treskal.com/kalle\n"},{"id":"68262","messageId":"20080210204102.17683.632.stgit@yoghurt","threadId":"12014","inReplyTo":"20080210203846.17683.43153.stgit@yoghurt","subject":"[StGit PATCH 1/5] Disable patchlog test for \"stg new\"","fromName":"Karl Hasselström","fromEmail":"kha@treskal.com","sentAt":"2008-02-10T20:43:26Z","receivedAt":"2008-02-10T20:43:26Z","isPatch":true,"sender":{"key":"kha@treskal.com","avatar":"https://gravatar.com/avatar/f0120c734b5279b345075a28521e1ac66acb20c9913ffe9bf6ae97e53f7f3f13?d=mp&s=160"},"body":"This will be broken by the \"stg new\" rewrite, so stop testing it.\n\nSigned-off-by: Karl Hasselström <kha@treskal.com>\n\n---\n\nI'm doing this rather than fixing the log since I hope to actually\ncreate \"stg undo\" pretty soon, and that'll involve a new internal log\nformat. But I won't graduate this to kha/safe until it's resolved\neither way.\n\n t/t1400-patch-history.sh |    2 --\n 1 files changed, 0 insertions(+), 2 deletions(-)\n\n\ndiff --git a/t/t1400-patch-history.sh b/t/t1400-patch-history.sh\nindex 879b1a5..a693e75 100755\n--- a/t/t1400-patch-history.sh\n+++ b/t/t1400-patch-history.sh\n@@ -35,9 +35,7 @@ test_expect_success \\\n test_expect_success \\\n \t'Check the \"new\" and \"refresh\" logs' \\\n \t'\n-\tstg log --full foo | grep -q -e \"^new\" &&\n \tstg log --full foo | grep -q -e \"^refresh\" &&\n-\tstg log --full | grep -q -e \"^new\" &&\n \tstg log --full | grep -q -e \"^refresh\"\n \t'\n \n"},{"id":"68263","messageId":"20080210204331.17683.84608.stgit@yoghurt","threadId":"12014","inReplyTo":"20080210203846.17683.43153.stgit@yoghurt","subject":"[StGit PATCH 2/5] Convert \"stg new\" to the new infrastructure","fromName":"Karl Hasselström","fromEmail":"kha@treskal.com","sentAt":"2008-02-10T20:43:53Z","receivedAt":"2008-02-10T20:43:53Z","isPatch":true,"sender":{"key":"kha@treskal.com","avatar":"https://gravatar.com/avatar/f0120c734b5279b345075a28521e1ac66acb20c9913ffe9bf6ae97e53f7f3f13?d=mp&s=160"},"body":"This results in considerable code expansion, which is a sure sign that\nsomething needs to be abstracted away -- but to keep things simple,\nthose transformations come as separate patches.\n\nSigned-off-by: Karl Hasselström <kha@treskal.com>\n\n---\n\n stgit/commands/new.py |   85 ++++++++++++++++++++++++++++++++-----------------\n stgit/lib/git.py      |    8 ++---\n 2 files changed, 60 insertions(+), 33 deletions(-)\n\n\ndiff --git a/stgit/commands/new.py b/stgit/commands/new.py\nindex 6a8f086..dd9f93e 100644\n--- a/stgit/commands/new.py\n+++ b/stgit/commands/new.py\n@@ -16,13 +16,11 @@ 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 import stack, git\n+from optparse import make_option\n \n+from stgit import utils\n+from stgit.commands import common\n+from stgit.lib import git as gitlib, transaction\n \n help = 'create a new patch and make it the topmost one'\n usage = \"\"\"%prog [options] [name]\n@@ -38,12 +36,9 @@ this.\n If no name is given for the new patch, one is generated from the first\n line of the commit message.\"\"\"\n \n-directory = DirectoryGotoToplevel()\n+directory = common.DirectoryHasRepositoryLib()\n options = [make_option('-m', '--message',\n                        help = 'use MESSAGE as the patch description'),\n-           make_option('-s', '--showpatch',\n-                       help = 'show the patch content in the editor buffer',\n-                       action = 'store_true'),\n            make_option('-a', '--author', metavar = '\"NAME <EMAIL>\"',\n                        help = 'use \"NAME <EMAIL>\" as the author details'),\n            make_option('--authname',\n@@ -56,30 +51,62 @@ options = [make_option('-m', '--message',\n                        help = 'use COMMNAME as the committer name'),\n            make_option('--commemail',\n                        help = 'use COMMEMAIL as the committer e-mail')\n-           ] + make_sign_options()\n-\n+           ] + utils.make_sign_options()\n \n def func(parser, options, args):\n-    \"\"\"Creates a new patch\n-    \"\"\"\n+    \"\"\"Create a new patch.\"\"\"\n+    stack = directory.repository.current_stack\n+    if stack.repository.default_index.conflicts():\n+        raise common.CmdException(\n+            'Cannot create a new patch -- resolve conflicts first')\n+\n+    # Choose a name for the new patch -- or None, which means make one\n+    # up later when we've gotten hold of the commit message.\n     if len(args) == 0:\n-        name = None # autogenerate a name\n+        name = None\n     elif len(args) == 1:\n         name = args[0]\n+        if stack.patches.exists(name):\n+            raise common.CmdException('%s: patch already exists' % name)\n     else:\n         parser.error('incorrect number of arguments')\n \n-    check_conflicts()\n-    check_head_top_equal(crt_series)\n-\n-    if options.author:\n-        options.authname, options.authemail = name_email(options.author)\n-\n-    crt_series.new_patch(name, message = options.message,\n-                         show_patch = options.showpatch,\n-                         author_name = options.authname,\n-                         author_email = options.authemail,\n-                         author_date = options.authdate,\n-                         committer_name = options.commname,\n-                         committer_email = options.commemail,\n-                         sign_str = options.sign_str)\n+    head = directory.repository.refs.get(directory.repository.head)\n+    cd = gitlib.Commitdata(tree = head.data.tree, parents = [head],\n+                           message = '')\n+\n+    # Set patch commit message from commandline.\n+    if options.message != None:\n+        cd = cd.set_message(options.message)\n+\n+    # Specify author and committer data.\n+    if options.author != None:\n+        options.authname, options.authemail = common.name_email(options.author)\n+    for p, f, val in [('author', 'name', options.authname),\n+                      ('author', 'email', options.authemail),\n+                      ('author', 'date', gitlib.Date.maybe(options.authdate)),\n+                      ('committer', 'name', options.commname),\n+                      ('committer', 'email', options.commemail)]:\n+        if val != None:\n+            cd = getattr(cd, 'set_' + p)(\n+                getattr(getattr(cd, p), 'set_' + f)(val))\n+\n+    # Add Signed-off-by: or similar.\n+    if options.sign_str != None:\n+        cd = cd.set_message(utils.add_sign_line(\n+                cd.message, options.sign_str, gitlib.Person.committer().name,\n+                gitlib.Person.committer().email))\n+\n+    # Let user edit the commit message manually.\n+    if not options.message:\n+        cd = cd.set_message(utils.edit_string(cd.message, '.stgit-new.txt'))\n+    if name == None:\n+        name = utils.make_patch_name(cd.message,\n+                                     lambda name: stack.patches.exists(name))\n+\n+    # Write the new patch.\n+    iw = stack.repository.default_iw\n+    trans = transaction.StackTransaction(stack, 'stg new')\n+    trans.patches[name] = stack.repository.commit(cd)\n+    trans.applied.append(name)\n+    return trans.run()\ndiff --git a/stgit/lib/git.py b/stgit/lib/git.py\nindex 50dc4f1..6ee8a71 100644\n--- a/stgit/lib/git.py\n+++ b/stgit/lib/git.py\n@@ -24,13 +24,13 @@ class NoValue(object):\n     pass\n \n def make_defaults(defaults):\n-    def d(val, attr):\n+    def d(val, attr, default_fun = lambda: None):\n         if val != NoValue:\n             return val\n         elif defaults != NoValue:\n             return getattr(defaults, attr)\n         else:\n-            return None\n+            return default_fun()\n     return d\n \n class TimeZone(tzinfo, Repr):\n@@ -161,8 +161,8 @@ class Commitdata(Repr):\n         d = make_defaults(defaults)\n         self.__tree = d(tree, 'tree')\n         self.__parents = d(parents, 'parents')\n-        self.__author = d(author, 'author')\n-        self.__committer = d(committer, 'committer')\n+        self.__author = d(author, 'author', Person.author)\n+        self.__committer = d(committer, 'committer', Person.committer)\n         self.__message = d(message, 'message')\n     tree = property(lambda self: self.__tree)\n     parents = property(lambda self: self.__parents)\n"},{"id":"68264","messageId":"20080210204359.17683.41935.stgit@yoghurt","threadId":"12014","inReplyTo":"20080210203846.17683.43153.stgit@yoghurt","subject":"[StGit PATCH 3/5] Refactor --author/--committer options","fromName":"Karl Hasselström","fromEmail":"kha@treskal.com","sentAt":"2008-02-10T20:44:14Z","receivedAt":"2008-02-10T20:44:14Z","isPatch":true,"sender":{"key":"kha@treskal.com","avatar":"https://gravatar.com/avatar/f0120c734b5279b345075a28521e1ac66acb20c9913ffe9bf6ae97e53f7f3f13?d=mp&s=160"},"body":"This refactoring is specific to the new infrastructure, so only new\nand edit use it currently, but other commands can start using it as\nthey are converted.\n\nSigned-off-by: Karl Hasselström <kha@treskal.com>\n\n---\n\n stgit/commands/common.py |   33 ++++++++++--------------------\n stgit/commands/edit.py   |   25 +++--------------------\n stgit/commands/new.py    |   40 ++++++++++---------------------------\n stgit/utils.py           |   50 ++++++++++++++++++++++++++++++++++++++++++++++\n 4 files changed, 75 insertions(+), 73 deletions(-)\n\n\ndiff --git a/stgit/commands/common.py b/stgit/commands/common.py\nindex 5a1952b..d6df813 100644\n--- a/stgit/commands/common.py\n+++ b/stgit/commands/common.py\n@@ -266,30 +266,19 @@ def parse_patches(patch_args, patch_list, boundary = 0, ordered = False):\n     return patches\n \n def name_email(address):\n-    \"\"\"Return a tuple consisting of the name and email parsed from a\n-    standard 'name <email>' or 'email (name)' string\n-    \"\"\"\n-    address = re.sub(r'[\\\\\"]', r'\\\\\\g<0>', address)\n-    str_list = re.findall('^(.*)\\s*<(.*)>\\s*$', address)\n-    if not str_list:\n-        str_list = re.findall('^(.*)\\s*\\((.*)\\)\\s*$', address)\n-        if not str_list:\n-            raise CmdException('Incorrect \"name <email>\"/\"email (name)\"'\n-                               ' string: %s' % address)\n-        return ( str_list[0][1], str_list[0][0] )\n-\n-    return str_list[0]\n+    p = parse_name_email(address)\n+    if p:\n+        return p\n+    else:\n+        raise CmdException('Incorrect \"name <email>\"/\"email (name)\" string: %s'\n+                           % address)\n \n def name_email_date(address):\n-    \"\"\"Return a tuple consisting of the name, email and date parsed\n-    from a 'name <email> date' string\n-    \"\"\"\n-    address = re.sub(r'[\\\\\"]', r'\\\\\\g<0>', address)\n-    str_list = re.findall('^(.*)\\s*<(.*)>\\s*(.*)\\s*$', address)\n-    if not str_list:\n-        raise CmdException, 'Incorrect \"name <email> date\" string: %s' % address\n-\n-    return str_list[0]\n+    p = parse_name_email_date(address)\n+    if p:\n+        return p\n+    else:\n+        raise CmdException('Incorrect \"name <email> date\" string: %s' % address)\n \n def address_or_alias(addr_str):\n     \"\"\"Return the address if it contains an e-mail address or look up\ndiff --git a/stgit/commands/edit.py b/stgit/commands/edit.py\nindex 7daf156..037425b 100644\n--- a/stgit/commands/edit.py\n+++ b/stgit/commands/edit.py\n@@ -60,19 +60,8 @@ options = [make_option('-d', '--diff',\n                        action = 'store_true'),\n            make_option('-e', '--edit', action = 'store_true',\n                        help = 'invoke interactive editor'),\n-           make_option('--author', metavar = '\"NAME <EMAIL>\"',\n-                       help = 'replae the author details with \"NAME <EMAIL>\"'),\n-           make_option('--authname',\n-                       help = 'replace the author name with AUTHNAME'),\n-           make_option('--authemail',\n-                       help = 'replace the author e-mail with AUTHEMAIL'),\n-           make_option('--authdate',\n-                       help = 'replace the author date with AUTHDATE'),\n-           make_option('--commname',\n-                       help = 'replace the committer name with COMMNAME'),\n-           make_option('--commemail',\n-                       help = 'replace the committer e-mail with COMMEMAIL')\n            ] + (utils.make_sign_options() + utils.make_message_options()\n+                + utils.make_author_committer_options()\n                 + utils.make_diff_opts_option())\n \n def patch_diff(repository, cd, diff, diff_flags):\n@@ -141,16 +130,8 @@ def func(parser, options, args):\n                                                    options.message)\n \n     # Modify author and committer data.\n-    if options.author != None:\n-        options.authname, options.authemail = common.name_email(options.author)\n-    for p, f, val in [('author', 'name', options.authname),\n-                      ('author', 'email', options.authemail),\n-                      ('author', 'date', gitlib.Date.maybe(options.authdate)),\n-                      ('committer', 'name', options.commname),\n-                      ('committer', 'email', options.commemail)]:\n-        if val != None:\n-            cd = getattr(cd, 'set_' + p)(\n-                getattr(getattr(cd, p), 'set_' + f)(val))\n+    cd = (cd.set_author(options.author(cd.author))\n+            .set_committer(options.committer(cd.committer)))\n \n     # Add Signed-off-by: or similar.\n     if options.sign_str != None:\ndiff --git a/stgit/commands/new.py b/stgit/commands/new.py\nindex dd9f93e..d44b8cc 100644\n--- a/stgit/commands/new.py\n+++ b/stgit/commands/new.py\n@@ -39,19 +39,8 @@ line of the commit message.\"\"\"\n directory = common.DirectoryHasRepositoryLib()\n options = [make_option('-m', '--message',\n                        help = 'use MESSAGE as the patch description'),\n-           make_option('-a', '--author', metavar = '\"NAME <EMAIL>\"',\n-                       help = 'use \"NAME <EMAIL>\" as the author details'),\n-           make_option('--authname',\n-                       help = 'use AUTHNAME as the author name'),\n-           make_option('--authemail',\n-                       help = 'use AUTHEMAIL as the author e-mail'),\n-           make_option('--authdate',\n-                       help = 'use AUTHDATE as the author date'),\n-           make_option('--commname',\n-                       help = 'use COMMNAME as the committer name'),\n-           make_option('--commemail',\n-                       help = 'use COMMEMAIL as the committer e-mail')\n-           ] + utils.make_sign_options()\n+           ] + (utils.make_author_committer_options()\n+                + utils.make_sign_options())\n \n def func(parser, options, args):\n     \"\"\"Create a new patch.\"\"\"\n@@ -72,30 +61,23 @@ def func(parser, options, args):\n         parser.error('incorrect number of arguments')\n \n     head = directory.repository.refs.get(directory.repository.head)\n-    cd = gitlib.Commitdata(tree = head.data.tree, parents = [head],\n-                           message = '')\n+    cd = gitlib.Commitdata(\n+        tree = head.data.tree, parents = [head], message = '',\n+        author = gitlib.Person.author(), committer = gitlib.Person.committer())\n \n     # Set patch commit message from commandline.\n     if options.message != None:\n         cd = cd.set_message(options.message)\n \n-    # Specify author and committer data.\n-    if options.author != None:\n-        options.authname, options.authemail = common.name_email(options.author)\n-    for p, f, val in [('author', 'name', options.authname),\n-                      ('author', 'email', options.authemail),\n-                      ('author', 'date', gitlib.Date.maybe(options.authdate)),\n-                      ('committer', 'name', options.commname),\n-                      ('committer', 'email', options.commemail)]:\n-        if val != None:\n-            cd = getattr(cd, 'set_' + p)(\n-                getattr(getattr(cd, p), 'set_' + f)(val))\n+    # Modify author and committer data.\n+    cd = (cd.set_author(options.author(cd.author))\n+            .set_committer(options.committer(cd.committer)))\n \n     # Add Signed-off-by: or similar.\n     if options.sign_str != None:\n-        cd = cd.set_message(utils.add_sign_line(\n-                cd.message, options.sign_str, gitlib.Person.committer().name,\n-                gitlib.Person.committer().email))\n+        cd = cd.set_message(\n+            utils.add_sign_line(cd.message, options.sign_str,\n+                                cd.committer.name, cd.committer.email))\n \n     # Let user edit the commit message manually.\n     if not options.message:\ndiff --git a/stgit/utils.py b/stgit/utils.py\nindex b75c3b4..947f747 100644\n--- a/stgit/utils.py\n+++ b/stgit/utils.py\n@@ -322,6 +322,56 @@ def make_diff_opts_option():\n         type = 'string', metavar = 'OPTIONS',\n         help = 'extra options to pass to \"git diff\"')]\n \n+def parse_name_email(address):\n+    \"\"\"Return a tuple consisting of the name and email parsed from a\n+    standard 'name <email>' or 'email (name)' string.\"\"\"\n+    address = re.sub(r'[\\\\\"]', r'\\\\\\g<0>', address)\n+    str_list = re.findall(r'^(.*)\\s*<(.*)>\\s*$', address)\n+    if not str_list:\n+        str_list = re.findall(r'^(.*)\\s*\\((.*)\\)\\s*$', address)\n+        if not str_list:\n+            return None\n+        return (str_list[0][1], str_list[0][0])\n+    return str_list[0]\n+\n+def parse_name_email_date(address):\n+    \"\"\"Return a tuple consisting of the name, email and date parsed\n+    from a 'name <email> date' string.\"\"\"\n+    address = re.sub(r'[\\\\\"]', r'\\\\\\g<0>', address)\n+    str_list = re.findall('^(.*)\\s*<(.*)>\\s*(.*)\\s*$', address)\n+    if not str_list:\n+        return None\n+    return str_list[0]\n+\n+def make_person_options(person, short):\n+    \"\"\"Sets options.<person> to a function that modifies a Person\n+    according to the commandline options.\"\"\"\n+    def short_callback(option, opt_str, value, parser, field):\n+        f = getattr(parser.values, person)\n+        setattr(parser.values, person,\n+                lambda p: getattr(f(p), 'set_' + field)(value))\n+    def full_callback(option, opt_str, value, parser):\n+        ne = parse_name_email(value)\n+        if not ne:\n+            raise optparse.OptionValueError(\n+                'Bad %s specification: %r' % (opt_str, value))\n+        name, email = ne\n+        short_callback(option, opt_str, name, parser, 'name')\n+        short_callback(option, opt_str, email, parser, 'email')\n+    return ([optparse.make_option(\n+                '--%s' % person, metavar = '\"NAME <EMAIL>\"', type = 'string',\n+                action = 'callback', callback = full_callback, dest = person,\n+                default = lambda p: p, help = 'set the %s details' % person)]\n+            + [optparse.make_option(\n+                '--%s%s' % (short, f), metavar = f.upper(), type = 'string',\n+                action = 'callback', callback = short_callback, dest = person,\n+                callback_args = (f,), help = 'set the %s %s' % (person, f))\n+               for f in ['name', 'email', 'date']])\n+\n+def make_author_committer_options():\n+    return (make_person_options('author', 'auth')\n+            + make_person_options('committer', 'comm'))\n+\n # Exit codes.\n STGIT_SUCCESS = 0        # everything's OK\n STGIT_GENERAL_ERROR = 1  # seems to be non-command-specific error\n"},{"id":"68265","messageId":"20080210204420.17683.1504.stgit@yoghurt","threadId":"12014","inReplyTo":"20080210203846.17683.43153.stgit@yoghurt","subject":"[StGit PATCH 4/5] Let \"stg new\" support more message options","fromName":"Karl Hasselström","fromEmail":"kha@treskal.com","sentAt":"2008-02-10T20:44:28Z","receivedAt":"2008-02-10T20:44:28Z","isPatch":true,"sender":{"key":"kha@treskal.com","avatar":"https://gravatar.com/avatar/f0120c734b5279b345075a28521e1ac66acb20c9913ffe9bf6ae97e53f7f3f13?d=mp&s=160"},"body":"Let \"stg new\" support --file, and --save-template in addition to\n--message. This is useful for scripting.\n\nSigned-off-by: Karl Hasselström <kha@treskal.com>\n\n---\n\n stgit/commands/new.py |   10 ++++++----\n 1 files changed, 6 insertions(+), 4 deletions(-)\n\n\ndiff --git a/stgit/commands/new.py b/stgit/commands/new.py\nindex d44b8cc..43414f5 100644\n--- a/stgit/commands/new.py\n+++ b/stgit/commands/new.py\n@@ -37,10 +37,8 @@ If no name is given for the new patch, one is generated from the first\n line of the commit message.\"\"\"\n \n directory = common.DirectoryHasRepositoryLib()\n-options = [make_option('-m', '--message',\n-                       help = 'use MESSAGE as the patch description'),\n-           ] + (utils.make_author_committer_options()\n-                + utils.make_sign_options())\n+options = (utils.make_author_committer_options()\n+           + utils.make_message_options() + utils.make_sign_options())\n \n def func(parser, options, args):\n     \"\"\"Create a new patch.\"\"\"\n@@ -79,6 +77,10 @@ def func(parser, options, args):\n             utils.add_sign_line(cd.message, options.sign_str,\n                                 cd.committer.name, cd.committer.email))\n \n+    if options.save_template:\n+        options.save_template(cd.message)\n+        return utils.STGIT_SUCCESS\n+\n     # Let user edit the commit message manually.\n     if not options.message:\n         cd = cd.set_message(utils.edit_string(cd.message, '.stgit-new.txt'))\n"},{"id":"68266","messageId":"20080210204434.17683.61684.stgit@yoghurt","threadId":"12014","inReplyTo":"20080210203846.17683.43153.stgit@yoghurt","subject":"[StGit PATCH 5/5] Emacs mode: use \"stg new --file\"","fromName":"Karl Hasselström","fromEmail":"kha@treskal.com","sentAt":"2008-02-10T20:46:04Z","receivedAt":"2008-02-10T20:46:04Z","isPatch":true,"sender":{"key":"kha@treskal.com","avatar":"https://gravatar.com/avatar/f0120c734b5279b345075a28521e1ac66acb20c9913ffe9bf6ae97e53f7f3f13?d=mp&s=160"},"body":"Creating a new patch is a great deal easier now that \"stg new\" has a\n--file flag.\n\nSigned-off-by: Karl Hasselström <kha@treskal.com>\n\n---\n\nDavid, will you sanity-check this? I don't really speak elisp, so I\nmight have done something insane without knowing it. But it does seem\nto work. :-)\n\n contrib/stgit.el |   10 ++--------\n 1 files changed, 2 insertions(+), 8 deletions(-)\n\n\ndiff --git a/contrib/stgit.el b/contrib/stgit.el\nindex bef41c7..30c1cd1 100644\n--- a/contrib/stgit.el\n+++ b/contrib/stgit.el\n@@ -316,16 +316,10 @@ Commands:\n \n (defun stgit-confirm-new ()\n   (interactive)\n-  (let ((file (make-temp-file \"stgit-edit-\"))\n-        (patch (stgit-create-patch-name\n-                (buffer-substring (point-min)\n-                                  (save-excursion (goto-char (point-min))\n-                                                  (end-of-line)\n-                                                  (point))))))\n+  (let ((file (make-temp-file \"stgit-edit-\")))\n     (write-region (point-min) (point-max) file)\n     (stgit-capture-output nil\n-      (stgit-run \"new\" \"-m\" \"placeholder\" patch)\n-      (stgit-run \"edit\" \"-f\" file patch))\n+      (stgit-run \"new\" \"-f\" file))\n     (with-current-buffer log-edit-parent-buffer\n       (stgit-refresh))))\n \n"},{"id":"68267","messageId":"20080210204628.17886.27365.stgit@yoghurt","threadId":"12014","inReplyTo":"20080210203640.GA19688@diana.vm.bytemark.co.uk","subject":"[StGit PATCH 0/2] Convert \"stg delete\" to the new infrastructure","fromName":"Karl Hasselström","fromEmail":"kha@treskal.com","sentAt":"2008-02-10T20:47:01Z","receivedAt":"2008-02-10T20:47:01Z","isPatch":true,"sender":{"key":"kha@treskal.com","avatar":"https://gravatar.com/avatar/f0120c734b5279b345075a28521e1ac66acb20c9913ffe9bf6ae97e53f7f3f13?d=mp&s=160"},"body":"---\n\nKarl Hasselström (2):\n      Emacs mode: delete patches\n      Convert \"stg delete\" to the new infrastructure\n\n\n contrib/stgit.el         |   10 ++++++\n stgit/commands/delete.py |   72 +++++++++++++++-------------------------------\n t/t1600-delete-one.sh    |    8 +++--\n 3 files changed, 36 insertions(+), 54 deletions(-)\n\n-- \nKarl Hasselström, kha@treskal.com\n      www.treskal.com/kalle\n"},{"id":"68268","messageId":"20080210204706.17886.69425.stgit@yoghurt","threadId":"12014","inReplyTo":"20080210204628.17886.27365.stgit@yoghurt","subject":"[StGit PATCH 1/2] Convert \"stg delete\" to the new infrastructure","fromName":"Karl Hasselström","fromEmail":"kha@treskal.com","sentAt":"2008-02-10T20:48:45Z","receivedAt":"2008-02-10T20:48:45Z","isPatch":true,"sender":{"key":"kha@treskal.com","avatar":"https://gravatar.com/avatar/f0120c734b5279b345075a28521e1ac66acb20c9913ffe9bf6ae97e53f7f3f13?d=mp&s=160"},"body":"In the process, it gains the ability to delete any applied patch (not\njust the topmost one, like before), even when deleting patches from\nanother branch. (However, when deleting patches on another branch, we\nobviously can't represent a conflict in the index and worktree, so any\nconflicts will make the operation abort.)\n\nOne of the t1600 subtests made sure that we couldn't delete\nnon-topmost patches, and had to be corrected.\n\nSigned-off-by: Karl Hasselström <kha@treskal.com>\n\n---\n\nUnlike the \"stg new\" conversion, this resulted in a sizeable reduction\nof lines of code, and of code complexity.\n\n stgit/commands/delete.py |   72 +++++++++++++++-------------------------------\n t/t1600-delete-one.sh    |    8 +++--\n 2 files changed, 27 insertions(+), 53 deletions(-)\n\n\ndiff --git a/stgit/commands/delete.py b/stgit/commands/delete.py\nindex 1696cb9..106fbd2 100644\n--- a/stgit/commands/delete.py\n+++ b/stgit/commands/delete.py\n@@ -16,67 +16,41 @@ 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+from optparse import make_option\n \n+from stgit.commands import common\n+from stgit.lib import transaction\n \n help = 'delete patches'\n usage = \"\"\"%prog [options] <patch1> [<patch2>] [<patch3>..<patch4>]\n \n-Delete the patches passed as arguments. If an applied patch is to be\n-deleted, all other patches applied on top of it must be deleted too,\n-and they must be explicitly specified, since this command will not try\n-to delete a patch unless you explicitly ask it to. If any applied\n-patches are deleted, they are popped from the stack.\n+Delete the patches passed as arguments.\n \n Note that the 'delete' operation is irreversible.\"\"\"\n \n-directory = DirectoryGotoToplevel()\n+directory = common.DirectoryHasRepositoryLib()\n options = [make_option('-b', '--branch',\n                        help = 'use BRANCH instead of the default one')]\n \n def func(parser, options, args):\n-    \"\"\"Deletes one or more patches.\n-    \"\"\"\n-    applied_patches = crt_series.get_applied()\n-    unapplied_patches = crt_series.get_unapplied()\n-    all_patches = applied_patches + unapplied_patches\n-\n+    \"\"\"Delete one or more patches.\"\"\"\n+    if options.branch:\n+        stack = directory.repository.get_stack(options.branch)\n+        iw = None # can't use index/workdir to manipulate another branch\n+    else:\n+        stack = directory.repository.current_stack\n+        iw = stack.repository.default_iw\n     if args:\n-        patches = parse_patches(args, all_patches, len(applied_patches))\n+        patches = set(common.parse_patches(\n+                args, (list(stack.patchorder.applied)\n+                       + list(stack.patchorder.unapplied))))\n     else:\n         parser.error('No patches specified')\n-\n-    applied = []\n-\n-    # find the applied patches to be deleted. We can only delete\n-    # consecutive patches in the applied range\n-    for patch in applied_patches[::-1]:\n-        if patch in patches:\n-            applied.append(patch)\n-            patches.remove(patch)\n-        else:\n-            break\n-\n-    # any applied patches to be deleted but not in consecutive order?\n-    for patch in patches:\n-        if patch in applied_patches:\n-            raise CmdException, 'Cannot delete the applied patch \"%s\"' % patch\n-\n-    if applied and not options.branch:\n-        check_local_changes()\n-        check_conflicts()\n-        check_head_top_equal(crt_series)\n-\n-    # delete the patches\n-    for patch in applied + patches:\n-        crt_series.delete_patch(patch)\n-        out.info('Patch \"%s\" successfully deleted' % patch)\n-\n-    if not options.branch:\n-        print_crt_patch(crt_series)\n+    trans = transaction.StackTransaction(stack, 'stg delete')\n+    try:\n+        to_push = trans.delete_patches(lambda pn: pn in patches)\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/t/t1600-delete-one.sh b/t/t1600-delete-one.sh\nindex 3052b3a..c3451d8 100755\n--- a/t/t1600-delete-one.sh\n+++ b/t/t1600-delete-one.sh\n@@ -77,8 +77,8 @@ test_expect_success \\\n     'Try to delete a non-topmost applied patch' \\\n     '\n     [ $(stg applied | wc -l) -eq 2 ] &&\n-    ! stg delete foo &&\n-    [ $(stg applied | wc -l) -eq 2 ]\n+    stg delete foo &&\n+    [ $(stg applied | wc -l) -eq 1 ]\n     '\n \n test_expect_success \\\n@@ -99,10 +99,10 @@ test_expect_success \\\n test_expect_success \\\n     'Delete a patch in another branch' \\\n     '\n-    [ $(stg applied | wc -l) -eq 3 ] &&\n+    [ $(stg applied | wc -l) -eq 2 ] &&\n     [ $(stg applied -b br | wc -l) -eq 1 ] &&\n     stg delete -b br baz &&\n-    [ $(stg applied | wc -l) -eq 3 ] &&\n+    [ $(stg applied | wc -l) -eq 2 ] &&\n     [ $(stg applied -b br | wc -l) -eq 0 ]\n     '\n \n"},{"id":"68271","messageId":"20080210204851.17886.69638.stgit@yoghurt","threadId":"12014","inReplyTo":"20080210204628.17886.27365.stgit@yoghurt","subject":"[StGit PATCH 2/2] Emacs mode: delete patches","fromName":"Karl Hasselström","fromEmail":"kha@treskal.com","sentAt":"2008-02-10T20:54:08Z","receivedAt":"2008-02-10T20:54:08Z","isPatch":true,"sender":{"key":"kha@treskal.com","avatar":"https://gravatar.com/avatar/f0120c734b5279b345075a28521e1ac66acb20c9913ffe9bf6ae97e53f7f3f13?d=mp&s=160"},"body":"Teach the emacs mode to delete patches.\n\nSigned-off-by: Karl Hasselström <kha@treskal.com>\n\n---\n\nDavid, could you have a look at this as well? In addition to me being\nelisp challenged, there are the following issues:\n\n  * Is \"d\" a reasonable binding? Any better suggestion?\n\n  * Currently, this command requires you to mark one or more patches\n    before deleting. This is convenient when deleting more than one\n    patch, but one could argue that it should be possible to delete\n    the patch at point without having to select it.\n\n  * We should probably ask for confirmation before deleting.\n\n contrib/stgit.el |   10 +++++++++-\n 1 files changed, 9 insertions(+), 1 deletions(-)\n\n\ndiff --git a/contrib/stgit.el b/contrib/stgit.el\nindex 30c1cd1..7468fcd 100644\n--- a/contrib/stgit.el\n+++ b/contrib/stgit.el\n@@ -150,7 +150,8 @@ Argument DIR is the repository path.\"\n   (define-key stgit-mode-map \"<\"   'stgit-pop-next)\n   (define-key stgit-mode-map \"P\"   'stgit-push-or-pop)\n   (define-key stgit-mode-map \"G\"   'stgit-goto)\n-  (define-key stgit-mode-map \"=\"   'stgit-show))\n+  (define-key stgit-mode-map \"=\"   'stgit-show)\n+  (define-key stgit-mode-map \"d\"   'stgit-delete))\n \n (defun stgit-mode ()\n   \"Major mode for interacting with StGit.\n@@ -341,6 +342,13 @@ Commands:\n            (substring patch 0 20))\n           (t patch))))\n \n+(defun stgit-delete (patch-names)\n+  \"Delete the named patches\"\n+  (interactive (list (stgit-marked-patches)))\n+  (stgit-capture-output nil\n+    (apply 'stgit-run \"delete\" patch-names))\n+  (stgit-refresh))\n+\n (defun stgit-coalesce (patch-names)\n   \"Run stg coalesce on the named patches\"\n   (interactive (list (stgit-marked-patches)))\n"},{"id":"68348","messageId":"87zlu7sv3b.fsf@lysator.liu.se","threadId":"12014","inReplyTo":"20080210204434.17683.61684.stgit@yoghurt","subject":"Re: [StGit PATCH 5/5] Emacs mode: use \"stg new --file\"","fromName":"David Kågedal","fromEmail":"davidk@lysator.liu.se","sentAt":"2008-02-11T09:25:44Z","receivedAt":"2008-02-11T09:25:44Z","isPatch":true,"sender":{"key":"davidk@lysator.liu.se","avatar":"https://avatars.githubusercontent.com/u/60530?v=4"},"body":"Karl Hasselström <kha@treskal.com> writes:\n\n> Creating a new patch is a great deal easier now that \"stg new\" has a\n> --file flag.\n>\n> Signed-off-by: Karl Hasselström <kha@treskal.com>\n>\n> ---\n>\n> David, will you sanity-check this? I don't really speak elisp, so I\n> might have done something insane without knowing it. But it does seem\n> to work. :-)\n\nLooks sane to me.\n\n>  contrib/stgit.el |   10 ++--------\n>  1 files changed, 2 insertions(+), 8 deletions(-)\n>\n>\n> diff --git a/contrib/stgit.el b/contrib/stgit.el\n> index bef41c7..30c1cd1 100644\n> --- a/contrib/stgit.el\n> +++ b/contrib/stgit.el\n> @@ -316,16 +316,10 @@ Commands:\n>  \n>  (defun stgit-confirm-new ()\n>    (interactive)\n> -  (let ((file (make-temp-file \"stgit-edit-\"))\n> -        (patch (stgit-create-patch-name\n> -                (buffer-substring (point-min)\n> -                                  (save-excursion (goto-char (point-min))\n> -                                                  (end-of-line)\n> -                                                  (point))))))\n> +  (let ((file (make-temp-file \"stgit-edit-\")))\n>      (write-region (point-min) (point-max) file)\n>      (stgit-capture-output nil\n> -      (stgit-run \"new\" \"-m\" \"placeholder\" patch)\n> -      (stgit-run \"edit\" \"-f\" file patch))\n> +      (stgit-run \"new\" \"-f\" file))\n>      (with-current-buffer log-edit-parent-buffer\n>        (stgit-refresh))))\n>  \n>\n\n-- \nDavid Kågedal\n"},{"id":"68350","messageId":"87wspbsubl.fsf@lysator.liu.se","threadId":"12014","inReplyTo":"20080210204851.17886.69638.stgit@yoghurt","subject":"Re: [StGit PATCH 2/2] Emacs mode: delete patches","fromName":"David Kågedal","fromEmail":"davidk@lysator.liu.se","sentAt":"2008-02-11T09:42:22Z","receivedAt":"2008-02-11T09:42:22Z","isPatch":true,"sender":{"key":"davidk@lysator.liu.se","avatar":"https://avatars.githubusercontent.com/u/60530?v=4"},"body":"Karl Hasselström <kha@treskal.com> writes:\n\n> Teach the emacs mode to delete patches.\n>\n> Signed-off-by: Karl Hasselström <kha@treskal.com>\n>\n> ---\n>\n> David, could you have a look at this as well? In addition to me being\n> elisp challenged, there are the following issues:\n>\n>   * Is \"d\" a reasonable binding? Any better suggestion?\n\nWe could reserve \"d\" for moving a patch \"down\", maybe.  The more\ndestructive commands could be on less accessible keys. Maybe \"D\" or\n\"C-d\".\n\n>   * Currently, this command requires you to mark one or more patches\n>     before deleting. This is convenient when deleting more than one\n>     patch, but one could argue that it should be possible to delete\n>     the patch at point without having to select it.\n\nYou need something like this:\n\n--- a/contrib/stgit.el\n+++ b/contrib/stgit.el\n@@ -187,6 +187,15 @@ Commands:\n         (match-string-no-properties 1)\n       nil)))\n \n+(defun stgit-selected-patches ()\n+  \"Return the names of the marked patches, or the patch on the current line.\"\n+  (if stgit-marked-patches\n+      (stgit-marked-patches)\n+    (let ((patch (stgit-patch-at-point)))\n+      (if patch\n+          (list patch)\n+        '()))))\n+\n (defun stgit-goto-patch (patch)\n   \"Move point to the line containing PATCH\"\n   (let ((p (point)))\n\n>   * We should probably ask for confirmation before deleting.\n\nAbsolutely. Something like this (untested):\n\n(defun stgit-delete (patch-names)\n  \"Delete the named patches\"\n  (interactive (list (stgit-selected-patches)))\n  (if (zerop (length patch-names))\n      (error \"No patches to delete\")\n    (when (yes-or-no-p (format \"Really delete %d patches? \"\n                               (length patch-names)))\n      (stgit-capture-output nil\n        (apply 'stgit-run \"delete\" patch-names))\n      (stgit-refresh))\n\n\n-- \nDavid Kågedal\n"},{"id":"68352","messageId":"20080211094738.GA28140@diana.vm.bytemark.co.uk","threadId":"12014","inReplyTo":"87zlu7sv3b.fsf@lysator.liu.se","subject":"Re: [StGit PATCH 5/5] Emacs mode: use \"stg new --file\"","fromName":"Karl Hasselström","fromEmail":"kha@treskal.com","sentAt":"2008-02-11T09:47:38Z","receivedAt":"2008-02-11T09:47:38Z","isPatch":true,"sender":{"key":"kha@treskal.com","avatar":"https://gravatar.com/avatar/f0120c734b5279b345075a28521e1ac66acb20c9913ffe9bf6ae97e53f7f3f13?d=mp&s=160"},"body":"On 2008-02-11 10:25:44 +0100, David Kågedal wrote:\n\n> Karl Hasselström <kha@treskal.com> writes:\n>\n> > David, will you sanity-check this? I don't really speak elisp, so\n> > I might have done something insane without knowing it. But it does\n> > seem to work. :-)\n>\n> Looks sane to me.\n\nThanks.\n\n-- \nKarl Hasselström, kha@treskal.com\n      www.treskal.com/kalle\n"},{"id":"68353","messageId":"20080211095118.GB28140@diana.vm.bytemark.co.uk","threadId":"12014","inReplyTo":"87wspbsubl.fsf@lysator.liu.se","subject":"Re: [StGit PATCH 2/2] Emacs mode: delete patches","fromName":"Karl Hasselström","fromEmail":"kha@treskal.com","sentAt":"2008-02-11T09:51:18Z","receivedAt":"2008-02-11T09:51:18Z","isPatch":true,"sender":{"key":"kha@treskal.com","avatar":"https://gravatar.com/avatar/f0120c734b5279b345075a28521e1ac66acb20c9913ffe9bf6ae97e53f7f3f13?d=mp&s=160"},"body":"On 2008-02-11 10:42:22 +0100, David Kågedal wrote:\n\n> Karl Hasselström <kha@treskal.com> writes:\n>\n> > David, could you have a look at this as well? In addition to me\n> > being elisp challenged, there are the following issues:\n> >\n> >   * Is \"d\" a reasonable binding? Any better suggestion?\n>\n> We could reserve \"d\" for moving a patch \"down\", maybe. The more\n> destructive commands could be on less accessible keys. Maybe \"D\" or\n> \"C-d\".\n\nI'll take \"D\" then, since control bindings are more likely to collide\nwith existing bindings (as is already the case with C-r for stg\nrepair).\n\n> >   * Currently, this command requires you to mark one or more\n> >     patches before deleting. This is convenient when deleting more\n> >     than one patch, but one could argue that it should be possible\n> >     to delete the patch at point without having to select it.\n>\n> You need something like this:\n\nOK, thanks. I'll whip up a proper patch tonight -- unless you prefer\nto do it yourself?\n\n> >   * We should probably ask for confirmation before deleting.\n>\n> Absolutely. Something like this (untested):\n\nThanks again.\n\n-- \nKarl Hasselström, kha@treskal.com\n      www.treskal.com/kalle\n"},{"id":"68357","messageId":"87tzkfssxv.fsf@lysator.liu.se","threadId":"12014","inReplyTo":"20080211095118.GB28140@diana.vm.bytemark.co.uk","subject":"Re: [StGit PATCH 2/2] Emacs mode: delete patches","fromName":"David Kågedal","fromEmail":"davidk@lysator.liu.se","sentAt":"2008-02-11T10:12:12Z","receivedAt":"2008-02-11T10:12:12Z","isPatch":true,"sender":{"key":"davidk@lysator.liu.se","avatar":"https://avatars.githubusercontent.com/u/60530?v=4"},"body":"Karl Hasselström <kha@treskal.com> writes:\n\n> On 2008-02-11 10:42:22 +0100, David Kågedal wrote:\n>\n>> Karl Hasselström <kha@treskal.com> writes:\n>>\n>> > David, could you have a look at this as well? In addition to me\n>> > being elisp challenged, there are the following issues:\n>> >\n>> >   * Is \"d\" a reasonable binding? Any better suggestion?\n>>\n>> We could reserve \"d\" for moving a patch \"down\", maybe. The more\n>> destructive commands could be on less accessible keys. Maybe \"D\" or\n>> \"C-d\".\n>\n> I'll take \"D\" then, since control bindings are more likely to collide\n> with existing bindings (as is already the case with C-r for stg\n> repair).\n\nTrue, maybe we should move the repair binding as well.\n\n>> >   * Currently, this command requires you to mark one or more\n>> >     patches before deleting. This is convenient when deleting more\n>> >     than one patch, but one could argue that it should be possible\n>> >     to delete the patch at point without having to select it.\n>>\n>> You need something like this:\n>\n> OK, thanks. I'll whip up a proper patch tonight -- unless you prefer\n> to do it yourself?\n\nBe my guest.\n\n-- \nDavid Kågedal\n"},{"id":"68454","messageId":"20080211222518.15978.22325.stgit@yoghurt","threadId":"12014","inReplyTo":"87tzkfssxv.fsf@lysator.liu.se","subject":"[StGit PATCH 1/2] Emacs mode: change \"stg repair\" binding","fromName":"Karl Hasselström","fromEmail":"kha@treskal.com","sentAt":"2008-02-11T22:25:29Z","receivedAt":"2008-02-11T22:25:29Z","isPatch":true,"sender":{"key":"kha@treskal.com","avatar":"https://gravatar.com/avatar/f0120c734b5279b345075a28521e1ac66acb20c9913ffe9bf6ae97e53f7f3f13?d=mp&s=160"},"body":"It used to be C-r, but that's commonly used for reverse searching, so\nuse R instead.\n\nSigned-off-by: Karl Hasselström <kha@treskal.com>\n\n---\n\n contrib/stgit.el |    2 +-\n 1 files changed, 1 insertions(+), 1 deletions(-)\n\n\ndiff --git a/contrib/stgit.el b/contrib/stgit.el\nindex e8bbb2c..aa54772 100644\n--- a/contrib/stgit.el\n+++ b/contrib/stgit.el\n@@ -143,7 +143,7 @@ Argument DIR is the repository path.\"\n   (define-key stgit-mode-map \"e\"   'stgit-edit)\n   (define-key stgit-mode-map \"c\"   'stgit-coalesce)\n   (define-key stgit-mode-map \"N\"   'stgit-new)\n-  (define-key stgit-mode-map \"\\C-r\"   'stgit-repair)\n+  (define-key stgit-mode-map \"R\"   'stgit-repair)\n   (define-key stgit-mode-map \"C\"   'stgit-commit)\n   (define-key stgit-mode-map \"U\"   'stgit-uncommit)\n   (define-key stgit-mode-map \">\"   'stgit-push-next)\n"},{"id":"68455","messageId":"20080211222537.15978.91287.stgit@yoghurt","threadId":"12014","inReplyTo":"87tzkfssxv.fsf@lysator.liu.se","subject":"[StGit PATCH v2 2/2] Emacs mode: delete patches","fromName":"Karl Hasselström","fromEmail":"kha@treskal.com","sentAt":"2008-02-11T22:26:24Z","receivedAt":"2008-02-11T22:26:24Z","isPatch":true,"sender":{"key":"kha@treskal.com","avatar":"https://gravatar.com/avatar/f0120c734b5279b345075a28521e1ac66acb20c9913ffe9bf6ae97e53f7f3f13?d=mp&s=160"},"body":"Teach the emacs mode to delete patches. It will delete the selected\npatches, or, if no patches are selected, the patch at point (and if\nthere is no patch at point, complain). Before deleting, it will ask\nfor confirmation.\n\nThanks to David Kågedal <davidk@lysator.liu.se> for lots of elisp\nhelp.\n\nSigned-off-by: Karl Hasselström <kha@treskal.com>\n\n---\n\n contrib/stgit.el |   23 ++++++++++++++++++++++-\n 1 files changed, 22 insertions(+), 1 deletions(-)\n\n\ndiff --git a/contrib/stgit.el b/contrib/stgit.el\nindex 386d46e..1036cf9 100644\n--- a/contrib/stgit.el\n+++ b/contrib/stgit.el\n@@ -150,7 +150,8 @@ Argument DIR is the repository path.\"\n   (define-key stgit-mode-map \"<\"   'stgit-pop-next)\n   (define-key stgit-mode-map \"P\"   'stgit-push-or-pop)\n   (define-key stgit-mode-map \"G\"   'stgit-goto)\n-  (define-key stgit-mode-map \"=\"   'stgit-show))\n+  (define-key stgit-mode-map \"=\"   'stgit-show)\n+  (define-key stgit-mode-map \"D\"   'stgit-delete))\n \n (defun stgit-mode ()\n   \"Major mode for interacting with StGit.\n@@ -187,6 +188,15 @@ Commands:\n         (match-string-no-properties 1)\n       nil)))\n \n+(defun stgit-patches-marked-or-at-point ()\n+  \"Return the names of the marked patches, or the patch on the current line.\"\n+  (if stgit-marked-patches\n+      (stgit-marked-patches)\n+    (let ((patch (stgit-patch-at-point)))\n+      (if patch\n+          (list patch)\n+        '()))))\n+\n (defun stgit-goto-patch (patch)\n   \"Move point to the line containing PATCH\"\n   (let ((p (point)))\n@@ -341,6 +351,17 @@ Commands:\n            (substring patch 0 20))\n           (t patch))))\n \n+(defun stgit-delete (patch-names)\n+  \"Delete the named patches\"\n+  (interactive (list (stgit-patches-marked-or-at-point)))\n+  (if (zerop (length patch-names))\n+      (error \"No patches to delete\")\n+    (when (yes-or-no-p (format \"Really delete %d patches? \"\n+                               (length patch-names)))\n+      (stgit-capture-output nil\n+        (apply 'stgit-run \"delete\" patch-names))\n+      (stgit-refresh))))\n+\n (defun stgit-coalesce (patch-names)\n   \"Run stg coalesce on the named patches\"\n   (interactive (list (stgit-marked-patches)))\n"},{"id":"68538","messageId":"b0943d9e0802120954j4322e1d9o7796428f9480f9a@mail.gmail.com","threadId":"12014","inReplyTo":"20080210203640.GA19688@diana.vm.bytemark.co.uk","subject":"Re: StGit: kha/safe and kha/experimental updated","fromName":"Catalin Marinas","fromEmail":"catalin.marinas@gmail.com","sentAt":"2008-02-12T17:54:24Z","receivedAt":"2008-02-12T17:54:24Z","isPatch":false,"sender":{"key":"catalin.marinas@gmail.com","avatar":null},"body":"On 10/02/2008, Karl Hasselström <kha@treskal.com> wrote:\n> Both branches updated. I've promoted some experimental patches to\n> safe, and done some work on new and delete (will post the patches in\n> reply to this mail).\n\nThanks, I merged them last night. I now have to spend some time to\nunderstand StGIT as it's moving too fast :-). I'll try to put back\nsome of the things I use like the automatic invocation of the merge\ntool during conflicts etc.\n\n-- \nCatalin\n"},{"id":"68559","messageId":"200802122305.05696.kumbayo84@arcor.de","threadId":"12014","inReplyTo":"20080210204359.17683.41935.stgit@yoghurt","subject":"Subject: [PATCH] fix stg edit command","fromName":"Peter Oberndorfer","fromEmail":"kumbayo84@arcor.de","sentAt":"2008-02-12T22:05:05Z","receivedAt":"2008-02-12T22:05:05Z","isPatch":true,"sender":{"key":"kumbayo84@arcor.de","avatar":"https://avatars.githubusercontent.com/u/1041267?v=4"},"body":"The comparison of two Commitdata objects returned False.\nSigned-off-by: Peter Oberndorfer <kumbayo84@arcor.de>\n---\n\nOn Sonntag 10 Februar 2008, Karl Hasselström wrote:\n> This refactoring is specific to the new infrastructure, so only new\n> and edit use it currently, but other commands can start using it as\n> they are converted.\n> \n> Signed-off-by: Karl Hasselström <kha@treskal.com>\n\nWhile testing my editor searching ordering patch i found that\nthis patch(Refactor --author/--committer options) seems to break\n\"stg edit\" (without arguments) starting a interactive editor for me.\nWhen i issue \"stg edit\" it silently does nothing.\n\nIt seems the following comparison does not return True\n\n># Let user edit the patch manually.\n>if cd == orig_cd or options.edit:\n\nI can work around this by adding a comparison function to Commitdata\nbut maybe __eq__ or __ne__ should be used instead(prevent similar bugs caused\nby == comparison)?\nI would guess the initial cause for this is that the following line which unconditionally replaces cd.\n\n> -    # Specify author and committer data.\n> -    if options.author != None:\n> -        options.authname, options.authemail = common.name_email(options.author)\n> -    for p, f, val in [('author', 'name', options.authname),\n> -                      ('author', 'email', options.authemail),\n> -                      ('author', 'date', gitlib.Date.maybe(options.authdate)),\n> -                      ('committer', 'name', options.commname),\n> -                      ('committer', 'email', options.commemail)]:\n> -        if val != None:\n> -            cd = getattr(cd, 'set_' + p)(\n> -                getattr(getattr(cd, p), 'set_' + f)(val))\n> +    # Modify author and committer data.\n> +    cd = (cd.set_author(options.author(cd.author))\n> +            .set_committer(options.committer(cd.committer)))\n\nSo another way to fix this might be, to not overwrite cd unconditionally.\n\nGreetings Peter\n\n stgit/commands/edit.py |    2 +-\n stgit/lib/git.py       |    8 ++++++++\n 2 files changed, 9 insertions(+), 1 deletions(-)\n\ndiff --git a/stgit/commands/edit.py b/stgit/commands/edit.py\nindex 037425b..9439fb6 100644\n--- a/stgit/commands/edit.py\n+++ b/stgit/commands/edit.py\n@@ -146,7 +146,7 @@ def func(parser, options, args):\n         return utils.STGIT_SUCCESS\n \n     # Let user edit the patch manually.\n-    if cd == orig_cd or options.edit:\n+    if cd.is_same(orig_cd) or options.edit:\n         fn = '.stgit-edit.' + ['txt', 'patch'][bool(options.diff)]\n         cd, failed_diff = update_patch_description(\n             stack.repository, cd, utils.edit_string(\ndiff --git a/stgit/lib/git.py b/stgit/lib/git.py\nindex 6ee8a71..b62d14c 100644\n--- a/stgit/lib/git.py\n+++ b/stgit/lib/git.py\n@@ -202,6 +202,14 @@ class Commitdata(Repr):\n         return ('Commitdata<tree: %s, parents: %s, author: %s,'\n                 ' committer: %s, message: \"%s\">'\n                 ) % (tree, parents, self.author, self.committer, self.message)\n+\n+    def is_same(self, other):\n+        return (self.__tree == other.__tree and\n+                self.__parents == other.__parents and\n+                self.__author == other.__author and\n+                self.__committer == other.__committer and\n+                self.__message == other.__message)\n+\n     @classmethod\n     def parse(cls, repository, s):\n         cd = cls()\n-- \n1.5.4.rc3\n"},{"id":"68564","messageId":"20080212224724.GA24993@diana.vm.bytemark.co.uk","threadId":"12014","inReplyTo":"200802122305.05696.kumbayo84@arcor.de","subject":"Re: Subject: [PATCH] fix stg edit command","fromName":"Karl Hasselström","fromEmail":"kha@treskal.com","sentAt":"2008-02-12T22:47:24Z","receivedAt":"2008-02-12T22:47:24Z","isPatch":true,"sender":{"key":"kha@treskal.com","avatar":"https://gravatar.com/avatar/f0120c734b5279b345075a28521e1ac66acb20c9913ffe9bf6ae97e53f7f3f13?d=mp&s=160"},"body":"On 2008-02-12 23:05:05 +0100, Peter Oberndorfer wrote:\n\n> While testing my editor searching ordering patch i found that this\n> patch(Refactor --author/--committer options) seems to break \"stg\n> edit\" (without arguments) starting a interactive editor for me. When\n> i issue \"stg edit\" it silently does nothing.\n\nThanks for the report. And yes, as far as I can tell your analysis is\nspot on. In the initial patch I remember being careful to not replace\ncd unless it was actually changed, but obviously I got sloppy after\nthat. :-(\n\n> It seems the following comparison does not return True\n>\n> > # Let user edit the patch manually.\n> > if cd == orig_cd or options.edit:\n>\n> I can work around this by adding a comparison function to Commitdata\n> but maybe __eq__ or __ne__ should be used instead(prevent similar\n> bugs caused by == comparison)?\n>\n> +    def is_same(self, other):\n> +        return (self.__tree == other.__tree and\n> +                self.__parents == other.__parents and\n> +                self.__author == other.__author and\n> +                self.__committer == other.__committer and\n> +                self.__message == other.__message)\n\nYes, you'd definitely want the common operators to work. But I usually\nimplement __cmp__ instead of __eq__ and __ne__ -- that gives you all\nof <, <=, =, !=, >=, and > for the price of a single method. And it's\nusually possible to define it rather simply in terms of cmp() with\ntuple arguments, like this:\n\n    def __cmp__(self, other):\n        return cmp((self.__tree, self.__parents, self.__author,\n                    self.__committer, self.__message),\n                   (other.__tree, other.__parents, other.__author,\n                    other.__committer, other.__message))\n\nThis sidesteps the great problem of cmp -- having to remember when to\nreturn 1 and when to return -1.\n\n> So another way to fix this might be, to not overwrite cd\n> unconditionally.\n\nYes, this is what we want -- if the user gives --author, we shouldn't\nopen the interactive editor even if the given author is the same as\nthe patch already had.\n\nUpdated patch on the way.\n\n-- \nKarl Hasselström, kha@treskal.com\n      www.treskal.com/kalle\n"},{"id":"68566","messageId":"20080212230842.GA25839@diana.vm.bytemark.co.uk","threadId":"12014","inReplyTo":"20080212224724.GA24993@diana.vm.bytemark.co.uk","subject":"[StGit PATCH] Refactor --author/--committer options","fromName":"Karl Hasselström","fromEmail":"kha@treskal.com","sentAt":"2008-02-12T23:08:42Z","receivedAt":"2008-02-12T23:08:42Z","isPatch":true,"sender":{"key":"kha@treskal.com","avatar":"https://gravatar.com/avatar/f0120c734b5279b345075a28521e1ac66acb20c9913ffe9bf6ae97e53f7f3f13?d=mp&s=160"},"body":"This refactoring is specific to the new infrastructure, so only new\nand edit use it currently, but other commands can start using it as\nthey are converted.\n\nSigned-off-by: Karl Hasselström <kha@treskal.com>\n\n---\n\nOn 2008-02-12 23:47:24 +0100, Karl Hasselström wrote:\n\n> On 2008-02-12 23:05:05 +0100, Peter Oberndorfer wrote:\n>\n> > So another way to fix this might be, to not overwrite cd\n> > unconditionally.\n>\n> Yes, this is what we want -- if the user gives --author, we\n> shouldn't open the interactive editor even if the given author is\n> the same as the patch already had.\n>\n> Updated patch on the way.\n\nAnd here it is. The relevant piece of code now reads\n\n    a, c = options.author(cd.author), options.committer(cd.committer)\n    if (a, c) != (cd.author, cd.committer):\n        cd = cd.set_author(a).set_committer(c)\n\nThis works because the default value for options.author and\noptions.committer -- used when no commandline options are given -- is\nthe identity function.\n\n stgit/commands/common.py |   33 ++++++++++--------------------\n stgit/commands/edit.py   |   26 ++++--------------------\n stgit/commands/new.py    |   40 ++++++++++---------------------------\n stgit/utils.py           |   50 ++++++++++++++++++++++++++++++++++++++++++++++\n 4 files changed, 76 insertions(+), 73 deletions(-)\n\n\ndiff --git a/stgit/commands/common.py b/stgit/commands/common.py\nindex 5a1952b..d6df813 100644\n--- a/stgit/commands/common.py\n+++ b/stgit/commands/common.py\n@@ -266,30 +266,19 @@ def parse_patches(patch_args, patch_list, boundary = 0, ordered = False):\n     return patches\n \n def name_email(address):\n-    \"\"\"Return a tuple consisting of the name and email parsed from a\n-    standard 'name <email>' or 'email (name)' string\n-    \"\"\"\n-    address = re.sub(r'[\\\\\"]', r'\\\\\\g<0>', address)\n-    str_list = re.findall('^(.*)\\s*<(.*)>\\s*$', address)\n-    if not str_list:\n-        str_list = re.findall('^(.*)\\s*\\((.*)\\)\\s*$', address)\n-        if not str_list:\n-            raise CmdException('Incorrect \"name <email>\"/\"email (name)\"'\n-                               ' string: %s' % address)\n-        return ( str_list[0][1], str_list[0][0] )\n-\n-    return str_list[0]\n+    p = parse_name_email(address)\n+    if p:\n+        return p\n+    else:\n+        raise CmdException('Incorrect \"name <email>\"/\"email (name)\" string: %s'\n+                           % address)\n \n def name_email_date(address):\n-    \"\"\"Return a tuple consisting of the name, email and date parsed\n-    from a 'name <email> date' string\n-    \"\"\"\n-    address = re.sub(r'[\\\\\"]', r'\\\\\\g<0>', address)\n-    str_list = re.findall('^(.*)\\s*<(.*)>\\s*(.*)\\s*$', address)\n-    if not str_list:\n-        raise CmdException, 'Incorrect \"name <email> date\" string: %s' % address\n-\n-    return str_list[0]\n+    p = parse_name_email_date(address)\n+    if p:\n+        return p\n+    else:\n+        raise CmdException('Incorrect \"name <email> date\" string: %s' % address)\n \n def address_or_alias(addr_str):\n     \"\"\"Return the address if it contains an e-mail address or look up\ndiff --git a/stgit/commands/edit.py b/stgit/commands/edit.py\nindex 7daf156..436f7ea 100644\n--- a/stgit/commands/edit.py\n+++ b/stgit/commands/edit.py\n@@ -60,19 +60,8 @@ options = [make_option('-d', '--diff',\n                        action = 'store_true'),\n            make_option('-e', '--edit', action = 'store_true',\n                        help = 'invoke interactive editor'),\n-           make_option('--author', metavar = '\"NAME <EMAIL>\"',\n-                       help = 'replae the author details with \"NAME <EMAIL>\"'),\n-           make_option('--authname',\n-                       help = 'replace the author name with AUTHNAME'),\n-           make_option('--authemail',\n-                       help = 'replace the author e-mail with AUTHEMAIL'),\n-           make_option('--authdate',\n-                       help = 'replace the author date with AUTHDATE'),\n-           make_option('--commname',\n-                       help = 'replace the committer name with COMMNAME'),\n-           make_option('--commemail',\n-                       help = 'replace the committer e-mail with COMMEMAIL')\n            ] + (utils.make_sign_options() + utils.make_message_options()\n+                + utils.make_author_committer_options()\n                 + utils.make_diff_opts_option())\n \n def patch_diff(repository, cd, diff, diff_flags):\n@@ -141,16 +130,9 @@ def func(parser, options, args):\n                                                    options.message)\n \n     # Modify author and committer data.\n-    if options.author != None:\n-        options.authname, options.authemail = common.name_email(options.author)\n-    for p, f, val in [('author', 'name', options.authname),\n-                      ('author', 'email', options.authemail),\n-                      ('author', 'date', gitlib.Date.maybe(options.authdate)),\n-                      ('committer', 'name', options.commname),\n-                      ('committer', 'email', options.commemail)]:\n-        if val != None:\n-            cd = getattr(cd, 'set_' + p)(\n-                getattr(getattr(cd, p), 'set_' + f)(val))\n+    a, c = options.author(cd.author), options.committer(cd.committer)\n+    if (a, c) != (cd.author, cd.committer):\n+        cd = cd.set_author(a).set_committer(c)\n \n     # Add Signed-off-by: or similar.\n     if options.sign_str != None:\ndiff --git a/stgit/commands/new.py b/stgit/commands/new.py\nindex dd9f93e..d44b8cc 100644\n--- a/stgit/commands/new.py\n+++ b/stgit/commands/new.py\n@@ -39,19 +39,8 @@ line of the commit message.\"\"\"\n directory = common.DirectoryHasRepositoryLib()\n options = [make_option('-m', '--message',\n                        help = 'use MESSAGE as the patch description'),\n-           make_option('-a', '--author', metavar = '\"NAME <EMAIL>\"',\n-                       help = 'use \"NAME <EMAIL>\" as the author details'),\n-           make_option('--authname',\n-                       help = 'use AUTHNAME as the author name'),\n-           make_option('--authemail',\n-                       help = 'use AUTHEMAIL as the author e-mail'),\n-           make_option('--authdate',\n-                       help = 'use AUTHDATE as the author date'),\n-           make_option('--commname',\n-                       help = 'use COMMNAME as the committer name'),\n-           make_option('--commemail',\n-                       help = 'use COMMEMAIL as the committer e-mail')\n-           ] + utils.make_sign_options()\n+           ] + (utils.make_author_committer_options()\n+                + utils.make_sign_options())\n \n def func(parser, options, args):\n     \"\"\"Create a new patch.\"\"\"\n@@ -72,30 +61,23 @@ def func(parser, options, args):\n         parser.error('incorrect number of arguments')\n \n     head = directory.repository.refs.get(directory.repository.head)\n-    cd = gitlib.Commitdata(tree = head.data.tree, parents = [head],\n-                           message = '')\n+    cd = gitlib.Commitdata(\n+        tree = head.data.tree, parents = [head], message = '',\n+        author = gitlib.Person.author(), committer = gitlib.Person.committer())\n \n     # Set patch commit message from commandline.\n     if options.message != None:\n         cd = cd.set_message(options.message)\n \n-    # Specify author and committer data.\n-    if options.author != None:\n-        options.authname, options.authemail = common.name_email(options.author)\n-    for p, f, val in [('author', 'name', options.authname),\n-                      ('author', 'email', options.authemail),\n-                      ('author', 'date', gitlib.Date.maybe(options.authdate)),\n-                      ('committer', 'name', options.commname),\n-                      ('committer', 'email', options.commemail)]:\n-        if val != None:\n-            cd = getattr(cd, 'set_' + p)(\n-                getattr(getattr(cd, p), 'set_' + f)(val))\n+    # Modify author and committer data.\n+    cd = (cd.set_author(options.author(cd.author))\n+            .set_committer(options.committer(cd.committer)))\n \n     # Add Signed-off-by: or similar.\n     if options.sign_str != None:\n-        cd = cd.set_message(utils.add_sign_line(\n-                cd.message, options.sign_str, gitlib.Person.committer().name,\n-                gitlib.Person.committer().email))\n+        cd = cd.set_message(\n+            utils.add_sign_line(cd.message, options.sign_str,\n+                                cd.committer.name, cd.committer.email))\n \n     # Let user edit the commit message manually.\n     if not options.message:\ndiff --git a/stgit/utils.py b/stgit/utils.py\nindex b75c3b4..947f747 100644\n--- a/stgit/utils.py\n+++ b/stgit/utils.py\n@@ -322,6 +322,56 @@ def make_diff_opts_option():\n         type = 'string', metavar = 'OPTIONS',\n         help = 'extra options to pass to \"git diff\"')]\n \n+def parse_name_email(address):\n+    \"\"\"Return a tuple consisting of the name and email parsed from a\n+    standard 'name <email>' or 'email (name)' string.\"\"\"\n+    address = re.sub(r'[\\\\\"]', r'\\\\\\g<0>', address)\n+    str_list = re.findall(r'^(.*)\\s*<(.*)>\\s*$', address)\n+    if not str_list:\n+        str_list = re.findall(r'^(.*)\\s*\\((.*)\\)\\s*$', address)\n+        if not str_list:\n+            return None\n+        return (str_list[0][1], str_list[0][0])\n+    return str_list[0]\n+\n+def parse_name_email_date(address):\n+    \"\"\"Return a tuple consisting of the name, email and date parsed\n+    from a 'name <email> date' string.\"\"\"\n+    address = re.sub(r'[\\\\\"]', r'\\\\\\g<0>', address)\n+    str_list = re.findall('^(.*)\\s*<(.*)>\\s*(.*)\\s*$', address)\n+    if not str_list:\n+        return None\n+    return str_list[0]\n+\n+def make_person_options(person, short):\n+    \"\"\"Sets options.<person> to a function that modifies a Person\n+    according to the commandline options.\"\"\"\n+    def short_callback(option, opt_str, value, parser, field):\n+        f = getattr(parser.values, person)\n+        setattr(parser.values, person,\n+                lambda p: getattr(f(p), 'set_' + field)(value))\n+    def full_callback(option, opt_str, value, parser):\n+        ne = parse_name_email(value)\n+        if not ne:\n+            raise optparse.OptionValueError(\n+                'Bad %s specification: %r' % (opt_str, value))\n+        name, email = ne\n+        short_callback(option, opt_str, name, parser, 'name')\n+        short_callback(option, opt_str, email, parser, 'email')\n+    return ([optparse.make_option(\n+                '--%s' % person, metavar = '\"NAME <EMAIL>\"', type = 'string',\n+                action = 'callback', callback = full_callback, dest = person,\n+                default = lambda p: p, help = 'set the %s details' % person)]\n+            + [optparse.make_option(\n+                '--%s%s' % (short, f), metavar = f.upper(), type = 'string',\n+                action = 'callback', callback = short_callback, dest = person,\n+                callback_args = (f,), help = 'set the %s %s' % (person, f))\n+               for f in ['name', 'email', 'date']])\n+\n+def make_author_committer_options():\n+    return (make_person_options('author', 'auth')\n+            + make_person_options('committer', 'comm'))\n+\n # Exit codes.\n STGIT_SUCCESS = 0        # everything's OK\n STGIT_GENERAL_ERROR = 1  # seems to be non-command-specific error\n\n\n-- \nKarl Hasselström, kha@treskal.com\n      www.treskal.com/kalle\n"}]}