[StGit PATCH] Write to a stack log when stack is modified

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Create a log branch (called <branchname>.stgit) for each StGit branch,
and write to it whenever the stack is modified.

Commands using the new infrastructure write to the log when they
commit a transaction. Commands using the old infrastructure get a log
entry write written for them when they exit, unless they explicitly
ask for this not to happen.

The only thing you can do with this log at the moment is look at it.

Signed-off-by: Karl Hasselström <kha@xxxxxxxxxxx>

---

Now rewritten to use a log format that should be more efficient (see
the docs at the top of lib/log.py). There is still a simplified log,
but it's not expensive since we recompute only the parts that have
changed since the last log entry.

A few of the other patches in the series had to be fixed up as well,
but mostly trivially since the interface between the log stuff and the
rest did not change; I won't spam the list with them. I'll be pushing
out the updated series to

  git://repo.or.cz/stgit/kha.git experimental

in a few minutes.

 stgit/commands/branch.py  |   19 ++-
 stgit/commands/common.py  |    8 +
 stgit/commands/diff.py    |    2 
 stgit/commands/files.py   |    2 
 stgit/commands/id.py      |    2 
 stgit/commands/log.py     |    2 
 stgit/commands/mail.py    |    2 
 stgit/commands/patches.py |    2 
 stgit/commands/show.py    |    2 
 stgit/commands/status.py  |    3 
 stgit/lib/git.py          |    3 
 stgit/lib/log.py          |  340 +++++++++++++++++++++++++++++++++++++++++++++
 stgit/lib/stack.py        |    9 +
 stgit/lib/transaction.py  |    3 
 stgit/main.py             |    2 
 15 files changed, 384 insertions(+), 17 deletions(-)
 create mode 100644 stgit/lib/log.py


diff --git a/stgit/commands/branch.py b/stgit/commands/branch.py
index 50684bb..edbb01c 100644
--- a/stgit/commands/branch.py
+++ b/stgit/commands/branch.py
@@ -25,7 +25,7 @@ from stgit.commands.common import *
 from stgit.utils import *
 from stgit.out import *
 from stgit import stack, git, basedir
-
+from stgit.lib import log
 
 help = 'manage patch stacks'
 usage = """%prog [options] branch-name [commit-id]
@@ -40,7 +40,7 @@ When displaying the branches, the names can be prefixed with
 
 If not given any options, switch to the named branch."""
 
-directory = DirectoryGotoToplevel()
+directory = DirectoryGotoToplevel(log = False)
 options = [make_option('-c', '--create',
                        help = 'create a new development branch',
                        action = 'store_true'),
@@ -161,6 +161,7 @@ def func(parser, options, args):
                                    parent_branch = parentbranch)
 
         out.info('Branch "%s" created' % args[0])
+        log.compat_log_entry('branch --create')
         return
 
     elif options.clone:
@@ -181,6 +182,8 @@ def func(parser, options, args):
         crt_series.clone(clone)
         out.done()
 
+        log.copy_log(log.default_repo(), crt_series.get_name(), clone,
+                     'branch --clone')
         return
 
     elif options.delete:
@@ -188,6 +191,7 @@ def func(parser, options, args):
         if len(args) != 1:
             parser.error('incorrect number of arguments')
         __delete_branch(args[0], options.force)
+        log.delete_log(log.default_repo(), args[0])
         return
 
     elif options.list:
@@ -195,13 +199,16 @@ def func(parser, options, args):
         if len(args) != 0:
             parser.error('incorrect number of arguments')
 
-        branches = git.get_heads()
-        branches.sort()
+        branches = set(git.get_heads())
+        for br in set(branches):
+            m = re.match(r'^(.*)\.stgit$', br)
+            if m and m.group(1) in branches:
+                branches.remove(br)
 
         if branches:
             out.info('Available branches:')
             max_len = max([len(i) for i in branches])
-            for i in branches:
+            for i in sorted(branches):
                 __print_branch(i, max_len)
         else:
             out.info('No branches')
@@ -238,7 +245,7 @@ def func(parser, options, args):
         stack.Series(args[0]).rename(args[1])
 
         out.info('Renamed branch "%s" to "%s"' % (args[0], args[1]))
-
+        log.rename_log(log.default_repo(), args[0], args[1], 'branch --rename')
         return
 
     elif options.unprotect:
diff --git a/stgit/commands/common.py b/stgit/commands/common.py
index 029ec65..fd02398 100644
--- a/stgit/commands/common.py
+++ b/stgit/commands/common.py
@@ -28,6 +28,7 @@ from stgit.run import *
 from stgit import stack, git, basedir
 from stgit.config import config, file_extensions
 from stgit.lib import stack as libstack
+from stgit.lib import log
 
 # Command exception class
 class CmdException(StgException):
@@ -478,8 +479,9 @@ class DirectoryException(StgException):
     pass
 
 class _Directory(object):
-    def __init__(self, needs_current_series = True):
+    def __init__(self, needs_current_series = True, log = True):
         self.needs_current_series =  needs_current_series
+        self.log = log
     @readonly_constant_property
     def git_dir(self):
         try:
@@ -512,6 +514,9 @@ class _Directory(object):
                        ).output_one_line()]
     def cd_to_topdir(self):
         os.chdir(self.__topdir_path)
+    def write_log(self, msg):
+        if self.log:
+            log.compat_log_entry(msg)
 
 class DirectoryAnywhere(_Directory):
     def setup(self):
@@ -536,6 +541,7 @@ class DirectoryHasRepositoryLib(_Directory):
     """For commands that use the new infrastructure in stgit.lib.*."""
     def __init__(self):
         self.needs_current_series = False
+        self.log = False # stgit.lib.transaction handles logging
     def setup(self):
         # This will throw an exception if we don't have a repository.
         self.repository = libstack.Repository.default()
diff --git a/stgit/commands/diff.py b/stgit/commands/diff.py
index fd6be34..8966642 100644
--- a/stgit/commands/diff.py
+++ b/stgit/commands/diff.py
@@ -42,7 +42,7 @@ rev = '([patch][//[bottom | top]]) | <tree-ish> | base'
 If neither bottom nor top are given but a '//' is present, the command
 shows the specified patch (defaulting to the current one)."""
 
-directory = DirectoryHasRepository()
+directory = DirectoryHasRepository(log = False)
 options = [make_option('-r', '--range',
                        metavar = 'rev1[..[rev2]]', dest = 'revs',
                        help = 'show the diff between revisions'),
diff --git a/stgit/commands/files.py b/stgit/commands/files.py
index b43b12f..7844f8d 100644
--- a/stgit/commands/files.py
+++ b/stgit/commands/files.py
@@ -34,7 +34,7 @@ given patch. Note that this command doesn't show the files modified in
 the working tree and not yet included in the patch by a 'refresh'
 command. Use the 'diff' or 'status' commands for these files."""
 
-directory = DirectoryHasRepository()
+directory = DirectoryHasRepository(log = False)
 options = [make_option('-s', '--stat',
                        help = 'show the diff stat',
                        action = 'store_true'),
diff --git a/stgit/commands/id.py b/stgit/commands/id.py
index 94b0229..5bb1ad2 100644
--- a/stgit/commands/id.py
+++ b/stgit/commands/id.py
@@ -33,7 +33,7 @@ the standard GIT id's like heads and tags, this command also accepts
 'top' or 'bottom' are passed and <patch> is a valid patch name, 'top'
 will be used by default."""
 
-directory = DirectoryHasRepository()
+directory = DirectoryHasRepository(log = False)
 options = [make_option('-b', '--branch',
                        help = 'use BRANCH instead of the default one')]
 
diff --git a/stgit/commands/log.py b/stgit/commands/log.py
index 52d55a5..13e0baa 100644
--- a/stgit/commands/log.py
+++ b/stgit/commands/log.py
@@ -44,7 +44,7 @@ represent the changes to the entire base of the current
 patch. Conflicts reset the patch content and a subsequent 'refresh'
 will show the entire patch."""
 
-directory = DirectoryHasRepository()
+directory = DirectoryHasRepository(log = False)
 options = [make_option('-b', '--branch',
                        help = 'use BRANCH instead of the default one'),
            make_option('-p', '--patch',
diff --git a/stgit/commands/mail.py b/stgit/commands/mail.py
index b4d4e18..4027170 100644
--- a/stgit/commands/mail.py
+++ b/stgit/commands/mail.py
@@ -90,7 +90,7 @@ the following:
   %(prefix)s       - 'prefix ' string passed on the command line
   %(shortdescr)s   - the first line of the patch description"""
 
-directory = DirectoryHasRepository()
+directory = DirectoryHasRepository(log = False)
 options = [make_option('-a', '--all',
                        help = 'e-mail all the applied patches',
                        action = 'store_true'),
diff --git a/stgit/commands/patches.py b/stgit/commands/patches.py
index 140699d..c95c40f 100644
--- a/stgit/commands/patches.py
+++ b/stgit/commands/patches.py
@@ -33,7 +33,7 @@ it shows the patches affected by the local tree modifications. The
 '--diff' option also lists the patch log and the diff for the given
 files."""
 
-directory = DirectoryHasRepository()
+directory = DirectoryHasRepository(log = False)
 options = [make_option('-d', '--diff',
                        help = 'show the diff for the given files',
                        action = 'store_true'),
diff --git a/stgit/commands/show.py b/stgit/commands/show.py
index b77a9c8..dd2a3a3 100644
--- a/stgit/commands/show.py
+++ b/stgit/commands/show.py
@@ -30,7 +30,7 @@ Show the commit log and the diff corresponding to the given
 patches. The output is similar to that generated by the 'git show'
 command."""
 
-directory = DirectoryHasRepository()
+directory = DirectoryHasRepository(log = False)
 options = [make_option('-b', '--branch',
                        help = 'use BRANCH instead of the default one'),
            make_option('-a', '--applied',
diff --git a/stgit/commands/status.py b/stgit/commands/status.py
index a5b2f88..4d13112 100644
--- a/stgit/commands/status.py
+++ b/stgit/commands/status.py
@@ -40,7 +40,7 @@ under revision control. The files are prefixed as follows:
 A 'refresh' command clears the status of the modified, new and deleted
 files."""
 
-directory = DirectoryHasRepository(needs_current_series = False)
+directory = DirectoryHasRepository(needs_current_series = False, log = False)
 options = [make_option('-m', '--modified',
                        help = 'show modified files only',
                        action = 'store_true'),
@@ -106,6 +106,7 @@ def func(parser, options, args):
     directory.cd_to_topdir()
 
     if options.reset:
+        directory.log = True
         if args:
             conflicts = git.get_conflicts()
             git.resolved([fn for fn in args if fn in conflicts])
diff --git a/stgit/lib/git.py b/stgit/lib/git.py
index a8881f4..35e03d2 100644
--- a/stgit/lib/git.py
+++ b/stgit/lib/git.py
@@ -139,6 +139,7 @@ class Person(Immutable, Repr):
         assert isinstance(self.__date, Date) or self.__date in [None, NoValue]
     name = property(lambda self: self.__name)
     email = property(lambda self: self.__email)
+    name_email = property(lambda self: '%s <%s>' % (self.name, self.email))
     date = property(lambda self: self.__date)
     def set_name(self, name):
         return type(self)(name = name, defaults = self)
@@ -147,7 +148,7 @@ class Person(Immutable, Repr):
     def set_date(self, date):
         return type(self)(date = date, defaults = self)
     def __str__(self):
-        return '%s <%s> %s' % (self.name, self.email, self.date)
+        return '%s %s' % (self.name_email, self.date)
     @classmethod
     def parse(cls, s):
         m = re.match(r'^([^<]*)<([^>]*)>\s+(\d+\s+[+-]\d{4})$', s)
diff --git a/stgit/lib/log.py b/stgit/lib/log.py
new file mode 100644
index 0000000..1188b24
--- /dev/null
+++ b/stgit/lib/log.py
@@ -0,0 +1,340 @@
+r"""This module contains functions and classes for manipulating
+I{patch stack logs} (or just I{stack logs}).
+
+A stack log is a git branch. Each commit contains the complete state
+of the stack at the moment it was written; the most recent commit has
+the most recent state.
+
+For a branch C{I{foo}}, the stack log is stored in C{I{foo}.stgit}.
+
+Stack log format (full)
+=======================
+
+Commit message
+--------------
+
+First comes a message for human consumption; in most cases it is just
+a subject line: the stg subcommand name and possibly some important
+command-line flag.
+
+An exception to this is log commits for undo and redo. Their subject
+line is "C{undo I{n}}" and "C{redo I{n}}"; the positive integer I{n}
+says how many steps were undone or redone.
+
+Following the message is a newline, three dashes, and another newline.
+Then come, each on its own line,
+
+  - C{Version:} I{n}
+
+    where I{n} must be 0. (Future versions of StGit might change the
+    log format; when this is done, this version number will be
+    incremented.)
+
+  - C{Previous:} I{sha1 or C{None}}
+
+    The commit of the previous log entry, or C{None} if this is the
+    first entry.
+
+  - C{Head:} I{sha1}
+
+    The current branch head.
+
+  - C{Applied:}
+
+    Marks the start of the list of applied patches. They are listed in
+    order, each on its own line: first one or more spaces, then the
+    patch name, then a colon, then the patch's sha1.
+
+  - C{Unapplied:}
+
+    Same as C{Applied:}, but for the unapplied patches.
+
+Tree
+----
+
+The tree is not significant.
+
+Parents
+-------
+
+  - The first parent is the I{simplified log}, described below.
+
+  - The rest of the parents are just there to make sure that all the
+    commits referred to in the log entry -- patches, branch head,
+    previous log entry -- are ancestors of the log commit.
+
+Stack log format (simplified)
+=============================
+
+The simplified log contains no information not in the full log; its
+purpose is ease of visualization.
+
+Commit message
+--------------
+
+Same as for the full log, but just the message part; the three dashes
+and the log data are omitted.
+
+Tree
+----
+
+  - One blob, C{meta}, that contains the log data (but not the three
+    dashes) that was omitted from the commit message.
+
+  - One subtree, C{patches}, that contains one blob per patch::
+
+      Bottom: <sha1 of patch's bottom tree>
+      Top:    <sha1 of patch's top tree>
+      Author: <author name and e-mail>
+      Date:   <patch timestamp>
+
+      <commit message>
+
+      ---
+
+      <patch diff>
+
+Parents
+-------
+
+Just one parent: the simplified version of the previous log entry. (If
+there is no previous log entry, there are no parents.)"""
+
+from stgit.lib import git, stack
+from stgit import exception, utils
+from stgit.out import out
+import StringIO
+
+class LogException(exception.StgException):
+    pass
+
+class LogParseException(LogException):
+    pass
+
+def patch_file(repo, cd):
+    return repo.commit(git.BlobData(''.join(s + '\n' for s in [
+                    'Bottom: %s' % cd.parent.data.tree.sha1,
+                    'Top:    %s' % cd.tree.sha1,
+                    'Author: %s' % cd.author.name_email,
+                    'Date:   %s' % cd.author.date,
+                    '',
+                    cd.message,
+                    '',
+                    '---',
+                    '',
+                    repo.diff_tree(cd.parent.data.tree, cd.tree, ['-M']
+                                   ).strip()])))
+
+def log_ref(branch):
+    return 'refs/heads/%s.stgit' % branch
+
+class LogEntry(object):
+    __separator = '\n---\n'
+    __max_parents = 16
+    def __init__(self, repo, prev, head, applied, unapplied, patches, message):
+        self.__repo = repo
+        self.__prev = prev
+        self.head = head
+        self.applied = applied
+        self.unapplied = unapplied
+        self.patches = patches
+        self.message = message
+    @property
+    def prev(self):
+        if self.__prev != None and not isinstance(self.__prev, LogEntry):
+            self.__prev = self.__from_commit_full(self.__repo, self.__prev)
+        return self.__prev
+    @classmethod
+    def from_stack(cls, prev, stack, message):
+        return cls(
+            repo = stack.repository,
+            prev = prev,
+            head = stack.head,
+            applied = list(stack.patchorder.applied),
+            unapplied = list(stack.patchorder.unapplied),
+            patches = dict((pn, stack.patches.get(pn).commit)
+                           for pn in stack.patchorder.all),
+            message = message)
+    @staticmethod
+    def __parse_metadata(repo, metadata):
+        """Parse a stack log metadata string."""
+        if not metadata.startswith('Version:'):
+            raise LogParseException('Malformed log metadata')
+        metadata = metadata.splitlines()
+        version_str = utils.strip_leading('Version:', metadata.pop(0)).strip()
+        try:
+            version = int(version_str)
+        except ValueError:
+            raise LogParseException(
+                'Malformed version number: %r' % version_str)
+        if version != 0:
+            raise LogException('Log is version %d, which is too new' % version)
+        parsed = {}
+        for line in metadata:
+            if line.startswith(' '):
+                parsed[key].append(line.strip())
+            else:
+                key, val = [x.strip() for x in line.split(':', 1)]
+                if val:
+                    parsed[key] = val
+                else:
+                    parsed[key] = []
+        prev = parsed['Previous']
+        if prev == 'None':
+            prev = None
+        else:
+            prev = repo.get_commit(prev)
+        head = repo.get_commit(parsed['Head'])
+        lists = { 'Applied': [], 'Unapplied': [] }
+        patches = {}
+        for lst in lists.keys():
+            for entry in parsed[lst]:
+                pn, sha1 = [x.strip() for x in entry.split(':')]
+                lists[lst].append(pn)
+                patches[pn] = repo.get_commit(sha1)
+        return (prev, head, lists['Applied'], lists['Unapplied'], patches)
+    @classmethod
+    def __from_commit_full(cls, repo, commit):
+        """Parse a full stack log commit."""
+        if not cls.__separator in commit.data.message:
+            raise LogParseException('Not a full log')
+        message, metadata = commit.data.message.rsplit(cls.__separator, 1)
+        (prev, head, applied, unapplied, patches
+         ) = cls.__parse_metadata(repo, metadata)
+        lg = cls(repo, prev, head, applied, unapplied, patches, message)
+        lg.simplified = commit.data.parents[0]
+        lg.commit = commit
+        return lg
+    @classmethod
+    def __from_commit_simplified(cls, repo, commit):
+        """Parse a simplified stack log commit."""
+        message = commit.data.message
+        try:
+            perm, meta = commit.data.tree.data.entries['meta']
+        except KeyError:
+            raise LogParseException('Not a simplified log')
+        (prev, head, applied, unapplied, patches
+         ) = cls.__parse_metadata(repo, meta.data.str)
+        lg = cls(repo, prev, head, applied, unapplied, patches, message)
+        lg.simplified = commit
+        return lg
+    @classmethod
+    def from_commit(cls, repo, commit):
+        """Parse a stack log commit, either full or simplified."""
+        try:
+            return cls.__from_commit_full(repo, commit)
+        except LogException, e:
+            full_exc = e
+        try:
+            return cls.__from_commit_simplified(repo, commit)
+        except LogParseException, e:
+            # Couldn't parse it as a simplified log. Raise the
+            # exception we got while trying to parse it as a full log,
+            # since that exception might be more informative than a
+            # simple parse exception.
+            raise full_exc
+    def __metadata_string(self):
+        e = StringIO.StringIO()
+        e.write('Version: 0\n')
+        if self.prev == None:
+            e.write('Previous: None\n')
+        else:
+            e.write('Previous: %s\n' % self.prev.commit.sha1)
+        e.write('Head: %s\n' % self.head.sha1)
+        for lst, title in [(self.applied, 'Applied'),
+                           (self.unapplied, 'Unapplied')]:
+            e.write('%s:\n' % title)
+            for pn in lst:
+                e.write('  %s: %s\n' % (pn, self.patches[pn].sha1))
+        return e.getvalue()
+    def __parents(self):
+        """Return the set of parents this log entry needs in order to be a
+        descendant of all the commits it refers to."""
+        xp = set([self.head]) | set(self.patches[pn] for pn in self.unapplied)
+        if self.applied:
+            xp.add(self.patches[self.applied[-1]])
+        if self.prev != None:
+            xp.add(self.prev.commit)
+            xp -= set(self.prev.patches.values())
+        return xp
+    def __simplified_tree(self, metadata):
+        if self.prev == None:
+            def pf(c):
+                return patch_file(self.__repo, c.data)
+        else:
+            prev_top_tree = self.prev.simplified.data.tree
+            perm, prev_patch_tree = prev_top_tree.data.entries['patches']
+            # Map from Commit object to patch_file() results taken
+            # from the previous log entry.
+            c2b = dict((self.prev.patches[pn], pf) for pn, pf
+                       in prev_patch_tree.data.entries.iteritems())
+            def pf(c):
+                r = c2b.get(c, None)
+                if not r:
+                    r = patch_file(self.__repo, c.data)
+                return r
+        patches = dict((pn, pf(c)) for pn, c in self.patches.iteritems())
+        return self.__repo.commit(git.TreeData({
+                    'meta': self.__repo.commit(git.BlobData(metadata)),
+                    'patches': self.__repo.commit(git.TreeData(patches)) }))
+    def write_commit(self):
+        metadata = self.__metadata_string()
+        self.simplified = self.__repo.commit(git.CommitData(
+                tree = self.__simplified_tree(metadata),
+                parents = [prev.simplified for prev in [self.prev]
+                           if prev != None],
+                message = self.message))
+        parents = list(self.__parents())
+        while len(parents) > self.__max_parents - 1:
+            g = self.__repo.commit(git.CommitData(
+                    tree = self.head.data.tree,
+                    parents = parents[-self.__max_parents:],
+                    message = 'Stack log parent grouping'))
+            parents[-self.__max_parents:] = [g]
+        self.commit = self.__repo.commit(git.CommitData(
+                tree = self.head.data.tree,
+                parents = [self.simplified] + parents,
+                message = self.message + self.__separator + metadata))
+
+def log_entry(stack, msg):
+    """Write a new log entry for the stack."""
+    ref = log_ref(stack.name)
+    try:
+        last_log = stack.repository.refs.get(ref)
+    except KeyError:
+        last_log = None
+    try:
+        new_log = LogEntry.from_stack(last_log, stack, msg)
+    except LogException, e:
+        out.warn(str(e), 'No log entry written.')
+        return
+    new_log.write_commit()
+    stack.repository.refs.set(ref, new_log.commit, msg)
+
+def compat_log_entry(msg):
+    """Write a new log entry. (Convenience function intended for use by
+    code not yet converted to the new infrastructure.)"""
+    repo = default_repo()
+    stack = repo.get_stack(repo.current_branch_name)
+    log_entry(stack, msg)
+
+def delete_log(repo, branch):
+    ref = log_ref(branch)
+    if repo.refs.exists(ref):
+        repo.refs.delete(ref)
+
+def rename_log(repo, old_branch, new_branch, msg):
+    old_ref = log_ref(old_branch)
+    new_ref = log_ref(new_branch)
+    if repo.refs.exists(old_ref):
+        repo.refs.set(new_ref, repo.refs.get(old_ref), msg)
+        repo.refs.delete(old_ref)
+
+def copy_log(repo, src_branch, dst_branch, msg):
+    src_ref = log_ref(src_branch)
+    dst_ref = log_ref(dst_branch)
+    if repo.refs.exists(src_ref):
+        repo.refs.set(dst_ref, repo.refs.get(src_ref), msg)
+
+def default_repo():
+    return stack.Repository.default()
diff --git a/stgit/lib/stack.py b/stgit/lib/stack.py
index 9cb3967..62a1ec2 100644
--- a/stgit/lib/stack.py
+++ b/stgit/lib/stack.py
@@ -165,6 +165,15 @@ class Stack(git.Branch):
                                     ).commit.data.parent
         else:
             return self.head
+    @property
+    def top(self):
+        """Commit of the topmost patch, or the stack base if no patches are
+        applied."""
+        if self.patchorder.applied:
+            return self.patches.get(self.patchorder.applied[-1]).commit
+        else:
+            # When no patches are applied, base == head.
+            return self.head
     def head_top_equal(self):
         if not self.patchorder.applied:
             return True
diff --git a/stgit/lib/transaction.py b/stgit/lib/transaction.py
index e47997e..4c4da1a 100644
--- a/stgit/lib/transaction.py
+++ b/stgit/lib/transaction.py
@@ -4,7 +4,7 @@ updates to an StGit stack in a safe and convenient way."""
 from stgit import exception, utils
 from stgit.utils import any, all
 from stgit.out import *
-from stgit.lib import git
+from stgit.lib import git, log
 
 class TransactionException(exception.StgException):
     """Exception raised when something goes wrong with a
@@ -170,6 +170,7 @@ class StackTransaction(object):
         _print_current_patch(self.__stack.patchorder.applied, self.__applied)
         self.__stack.patchorder.applied = self.__applied
         self.__stack.patchorder.unapplied = self.__unapplied
+        log.log_entry(self.__stack, self.__msg)
 
         if self.__error:
             return utils.STGIT_CONFLICT
diff --git a/stgit/main.py b/stgit/main.py
index aa1f8ef..ec0e840 100644
--- a/stgit/main.py
+++ b/stgit/main.py
@@ -277,6 +277,7 @@ def main():
 
         ret = command.func(parser, options, args)
     except (StgException, IOError, ParsingError, NoSectionError), err:
+        directory.write_log(cmd)
         out.error(str(err), title = '%s %s' % (prog, cmd))
         if debug_level > 0:
             traceback.print_exc()
@@ -292,4 +293,5 @@ def main():
         traceback.print_exc()
         sys.exit(utils.STGIT_BUG_ERROR)
 
+    directory.write_log(cmd)
     sys.exit(ret or utils.STGIT_SUCCESS)

--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux Kernel Development]     [Gcc Help]     [IETF Annouce]     [DCCP]     [Netdev]     [Networking]     [Security]     [V4L]     [Bugtraq]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux SCSI]     [Fedora Users]

  Powered by Linux