Instead of making a new temp index every time we need one, just keep reusing the same one. And keep track of which tree is currently stored in it -- if we do several consecutive successful pushes, it's always going to be the "right" tree so that we don't have to call read-tree before each patch application. The motivation behind this change is of course that it makes things faster. (The same simple test as in the previous patch -- pushing 250 patches in a 32k-file repository, with one file-level merge necessary per push -- went from 0.36 to 0.19 seconds per patch with this patch applied.) Signed-off-by: Karl Hasselström <kha@xxxxxxxxxxx> --- stgit/lib/git.py | 43 +++++++++++++++++++++++++++++-------------- stgit/lib/transaction.py | 12 +++++++++++- 2 files changed, 40 insertions(+), 15 deletions(-) diff --git a/stgit/lib/git.py b/stgit/lib/git.py index a38eaa5..c98e919 100644 --- a/stgit/lib/git.py +++ b/stgit/lib/git.py @@ -459,31 +459,46 @@ class Repository(RunWithEnv): def set_head_ref(self, ref, msg): self.run(['git', 'symbolic-ref', '-m', msg, 'HEAD', ref]).no_output() def simple_merge(self, base, ours, theirs): + index = self.temp_index() + try: + result, index_tree = self.index_merge(base, ours, theirs, + index, None) + finally: + index.delete() + return result + def index_merge(self, base, ours, theirs, index, current): """Given three L{Tree}s, tries to do an in-index merge with a - temporary index. Returns the result L{Tree}, or None if the - merge failed (due to conflicts).""" + temporary index. Returns a pair: the result L{Tree}, or None + if the merge failed (due to conflicts); and the L{Tree} now + stored in the index. + + C{index} is the L{Index} object to use for the merge. + C{current} is the L{Tree} object currently stored in the given + index. If this is the same as C{ours}, some work is saved. + (C{current} may be C{None}, in which case this optimization is + disabled.)""" assert isinstance(base, Tree) assert isinstance(ours, Tree) assert isinstance(theirs, Tree) + assert isinstance(index, Index) + assert current == None or isinstance(current, Tree) # Take care of the really trivial cases. if base == ours: - return theirs + return (theirs, current) if base == theirs: - return ours + return (ours, current) if ours == theirs: - return ours + return (ours, current) - index = self.temp_index() - index.read_tree(ours) + if current != ours: + index.read_tree(ours) try: - try: - index.apply_treediff(base, theirs) - return index.write_tree() - except MergeException: - return None - finally: - index.delete() + index.apply_treediff(base, theirs) + result = index.write_tree() + return result, result + except MergeException: + return None, ours def apply(self, tree, patch_text): """Given a L{Tree} and a patch, will either return the new L{Tree} that results when the patch is applied, or None if the patch diff --git a/stgit/lib/transaction.py b/stgit/lib/transaction.py index e47997e..b4d4b75 100644 --- a/stgit/lib/transaction.py +++ b/stgit/lib/transaction.py @@ -1,6 +1,8 @@ """The L{StackTransaction} class makes it possible to make complex updates to an StGit stack in a safe and convenient way.""" +import atexit + from stgit import exception, utils from stgit.utils import any, all from stgit.out import * @@ -84,6 +86,7 @@ class StackTransaction(object): self.__allow_conflicts = lambda trans: allow_conflicts else: self.__allow_conflicts = allow_conflicts + self.__temp_index = self.temp_index_tree = None stack = property(lambda self: self.__stack) patches = property(lambda self: self.__patches) def __set_applied(self, val): @@ -97,6 +100,12 @@ class StackTransaction(object): or self.patches[self.applied[0]].data.parent == val) self.__base = val base = property(lambda self: self.__base, __set_base) + @property + def temp_index(self): + if not self.__temp_index: + self.__temp_index = self.__stack.repository.temp_index() + atexit.register(self.__temp_index.delete) + return self.__temp_index def __checkout(self, tree, iw): if not self.__stack.head_top_equal(): out.error( @@ -238,7 +247,8 @@ class StackTransaction(object): base = oldparent.data.tree ours = cd.parent.data.tree theirs = cd.tree - tree = self.__stack.repository.simple_merge(base, ours, theirs) + tree, self.temp_index_tree = self.__stack.repository.index_merge( + base, ours, theirs, self.temp_index, self.temp_index_tree) merge_conflict = False if not tree: if iw == None: -- 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