diff options
author | Karl Wiberg <kha@treskal.com> | 2011-06-01 07:07:37 +0200 |
---|---|---|
committer | Karl Wiberg <kha@treskal.com> | 2011-06-01 07:07:37 +0200 |
commit | 956ef4a8a5112f8b5ed60e80f990920c884d4e02 (patch) | |
tree | bfb309f7099b18c15dced000318831b9392352b5 | |
parent | 622f322b681faa2292883c115980255e280e5231 (diff) | |
download | stgit-956ef4a8a5112f8b5ed60e80f990920c884d4e02.tar.gz |
Diff several trees at once with git diff-tree --stdin
Instead of spawning a separate diff-tree process for every pair of
trees we want to diff. This speeds things up slightly: about 10% when
uncommitting and rebasing 1470 linux-kernel patches (perftest.py
rebase-newrebase-add-file-linux).
Signed-off-by: Karl Wiberg <kha@treskal.com>
-rw-r--r-- | INSTALL | 5 | ||||
-rw-r--r-- | stgit/lib/git.py | 37 |
2 files changed, 36 insertions, 6 deletions
@@ -12,8 +12,9 @@ prefix option. Issues of note: -- StGit requires git version 1.5.6 or later. (Specifically, it needs a - git that includes commit a8128ed6: "git-cat-file: Add --batch option".) +- StGit requires git version 1.6.1 or later. (Specifically, it needs a + git that includes commit 140b378d: "Teach git diff-tree --stdin to + diff trees".) - To build and install the documentation, you need to have the asciidoc/xmlto toolchain. The default build target ("make all") diff --git a/stgit/lib/git.py b/stgit/lib/git.py index f5ea965..56287f6 100644 --- a/stgit/lib/git.py +++ b/stgit/lib/git.py @@ -555,6 +555,34 @@ class CatFileProcess(object): b += os.read(p.stdout.fileno(), 4096) return type, b[:-1] +class DiffTreeProcesses(object): + def __init__(self, repo): + self.__repo = repo + self.__procs = {} + atexit.register(self.__shutdown) + def __get_process(self, args): + args = tuple(args) + if not args in self.__procs: + self.__procs[args] = self.__repo.run( + ['git', 'diff-tree', '--stdin'] + list(args)).run_background() + return self.__procs[args] + def __shutdown(self): + for p in self.__procs.values(): + os.kill(p.pid(), signal.SIGTERM) + p.wait() + def diff_trees(self, args, sha1a, sha1b): + p = self.__get_process(args) + query = '%s %s\n' % (sha1a, sha1b) + end = 'EOF\n' # arbitrary string that's not a 40-digit hex number + p.stdin.write(query + end) + p.stdin.flush() + s = '' + while not (s.endswith('\n' + end) or s.endswith('\0' + end)): + s += os.read(p.stdout.fileno(), 4096) + assert s.startswith(query) + assert s.endswith(end) + return s[len(query):-len(end)] + class Repository(RunWithEnv): """Represents a git repository.""" def __init__(self, directory): @@ -567,6 +595,7 @@ class Repository(RunWithEnv): self.__default_worktree = None self.__default_iw = None self.__catfile = CatFileProcess(self) + self.__difftree = DiffTreeProcesses(self) env = property(lambda self: { 'GIT_DIR': self.__git_dir }) @classmethod def default(cls): @@ -693,8 +722,8 @@ class Repository(RunWithEnv): diff_opts = list(diff_opts) if binary and not '--binary' in diff_opts: diff_opts.append('--binary') - return self.run(['git', 'diff-tree', '-p'] + diff_opts - + [t1.sha1, t2.sha1]).raw_output() + return self.__difftree.diff_trees(['-p'] + diff_opts, + t1.sha1, t2.sha1) def diff_tree_files(self, t1, t2): """Given two L{Tree}s C{t1} and C{t2}, iterate over all files for which they differ. For each file, yield a tuple with the old @@ -704,8 +733,8 @@ class Repository(RunWithEnv): identical.""" assert isinstance(t1, Tree) assert isinstance(t2, Tree) - i = iter(self.run(['git', 'diff-tree', '-r', '-z'] + [t1.sha1, t2.sha1] - ).raw_output().split('\0')) + i = iter(self.__difftree.diff_trees( + ['-r', '-z'], t1.sha1, t2.sha1).split('\0')) try: while True: x = i.next() |