diff --git a/git/repo/base.py b/git/repo/base.py index f74e0b591..0274c0a7b 100644 --- a/git/repo/base.py +++ b/git/repo/base.py @@ -60,12 +60,15 @@ import os import sys import re +from collections import namedtuple DefaultDBType = GitCmdObjectDB if sys.version_info[:2] < (2, 5): # python 2.4 compatiblity DefaultDBType = GitCmdObjectDB # END handle python 2.4 +BlameEntry = namedtuple('BlameEntry', ['commit', 'linenos', 'orig_path', 'orig_linenos']) + __all__ = ('Repo', ) @@ -661,10 +664,10 @@ def blame_incremental(self, rev, file, **kwargs): """Iterator for blame information for the given file at the given revision. Unlike .blame(), this does not return the actual file's contents, only - a stream of (commit, range) tuples. + a stream of BlameEntry tuples. :parm rev: revision specifier, see git-rev-parse for viable options. - :return: lazy iterator of (git.Commit, range) tuples, where the commit + :return: lazy iterator of BlameEntry tuples, where the commit indicates the commit to blame for the line, and range indicates a span of line numbers in the resulting file. @@ -678,9 +681,10 @@ def blame_incremental(self, rev, file, **kwargs): while True: line = next(stream) # when exhausted, casues a StopIteration, terminating this function - hexsha, _, lineno, num_lines = line.split() + hexsha, orig_lineno, lineno, num_lines = line.split() lineno = int(lineno) num_lines = int(num_lines) + orig_lineno = int(orig_lineno) if hexsha not in commits: # Now read the next few lines and build up a dict of properties # for this commit @@ -696,6 +700,7 @@ def blame_incremental(self, rev, file, **kwargs): props[tag] = value if tag == b'filename': # "filename" formally terminates the entry for --incremental + orig_filename = value break c = Commit(self, hex_to_bin(hexsha), @@ -710,9 +715,14 @@ def blame_incremental(self, rev, file, **kwargs): else: # Discard the next line (it's a filename end tag) line = next(stream) - assert line.startswith(b'filename'), 'Unexpected git blame output' - - yield commits[hexsha], range(lineno, lineno + num_lines) + tag, value = line.split(b' ', 1) + assert tag == b'filename', 'Unexpected git blame output' + orig_filename = value + + yield BlameEntry(commits[hexsha], + range(lineno, lineno + num_lines), + safe_decode(orig_filename), + range(orig_lineno, orig_lineno + num_lines)) def blame(self, rev, file, incremental=False, **kwargs): """The blame information for the given file at the given revision. diff --git a/git/test/test_repo.py b/git/test/test_repo.py index ab6c502fd..d7437d35b 100644 --- a/git/test/test_repo.py +++ b/git/test/test_repo.py @@ -341,12 +341,19 @@ def test_blame_incremental(self, git): assert len(blame_output) == 5 # Check all outputted line numbers - ranges = flatten([line_numbers for _, line_numbers in blame_output]) + ranges = flatten([entry.linenos for entry in blame_output]) assert ranges == flatten([range(2, 3), range(14, 15), range(1, 2), range(3, 14), range(15, 17)]), str(ranges) - commits = [c.hexsha[:7] for c, _ in blame_output] + commits = [entry.commit.hexsha[:7] for entry in blame_output] assert commits == ['82b8902', '82b8902', 'c76852d', 'c76852d', 'c76852d'], str(commits) + # Original filenames + assert all([entry.orig_path == u'AUTHORS' for entry in blame_output]) + + # Original line numbers + orig_ranges = flatten([entry.orig_linenos for entry in blame_output]) + assert orig_ranges == flatten([range(2, 3), range(14, 15), range(1, 2), range(2, 13), range(13, 15)]), str(orig_ranges) # noqa + @patch.object(Git, '_call_process') def test_blame_complex_revision(self, git): git.return_value = fixture('blame_complex_revision')