@@ -69,12 +69,12 @@ where
6969
7070 let mut stats = Statistics :: default ( ) ;
7171 let ( mut buf, mut buf2, mut buf3) = ( Vec :: new ( ) , Vec :: new ( ) , Vec :: new ( ) ) ;
72- let blamed_file_entry = find_path_entry_in_commit ( & odb, & suspect, file_path, & mut buf, & mut buf2, & mut stats) ?
72+ let blamed_file_entry_id = find_path_entry_in_commit ( & odb, & suspect, file_path, & mut buf, & mut buf2, & mut stats) ?
7373 . ok_or_else ( || Error :: FileMissing {
74- file_path : file_path. to_owned ( ) ,
75- commit_id : suspect,
76- } ) ?;
77- let blamed_file_blob = odb. find_blob ( & blamed_file_entry . oid , & mut buf) ?. data . to_vec ( ) ;
74+ file_path : file_path. to_owned ( ) ,
75+ commit_id : suspect,
76+ } ) ?;
77+ let blamed_file_blob = odb. find_blob ( & blamed_file_entry_id , & mut buf) ?. data . to_vec ( ) ;
7878 let num_lines_in_blamed = {
7979 let mut interner = gix_diff:: blob:: intern:: Interner :: new ( blamed_file_blob. len ( ) / 100 ) ;
8080 tokens_for_diffing ( & blamed_file_blob)
9898
9999 let mut out = Vec :: new ( ) ;
100100 let mut diff_state = gix_diff:: tree:: State :: default ( ) ;
101+ let mut previous_entry: Option < ( ObjectId , ObjectId ) > = None ;
101102 ' outer: while let Some ( item) = traverse. next ( ) {
102103 if hunks_to_blame. is_empty ( ) {
103104 break ;
@@ -123,15 +124,27 @@ where
123124 continue ;
124125 }
125126
126- let Some ( entry) = find_path_entry_in_commit ( & odb, & suspect, file_path, & mut buf, & mut buf2, & mut stats) ? else {
127+ let mut entry = previous_entry
128+ . take ( )
129+ . filter ( |( id, _) | * id == suspect)
130+ . map ( |( _, entry) | entry) ;
131+ if entry. is_none ( ) {
132+ entry = find_path_entry_in_commit ( & odb, & suspect, file_path, & mut buf, & mut buf2, & mut stats) ?;
133+ }
134+
135+ let Some ( entry_id) = entry else {
127136 continue ;
128137 } ;
129138
130- for parent_id in & parent_ids {
131- if let Some ( parent_entry ) =
139+ for ( pid , parent_id) in parent_ids. iter ( ) . enumerate ( ) {
140+ if let Some ( parent_entry_id ) =
132141 find_path_entry_in_commit ( & odb, parent_id, file_path, & mut buf, & mut buf2, & mut stats) ?
133142 {
134- if entry. oid == parent_entry. oid {
143+ let no_change_in_entry = entry_id == parent_entry_id;
144+ if pid == 0 {
145+ previous_entry = Some ( ( * parent_id, parent_entry_id) ) ;
146+ }
147+ if no_change_in_entry {
135148 pass_blame_from_to ( suspect, * parent_id, & mut hunks_to_blame) ;
136149 continue ' outer;
137150 }
@@ -170,10 +183,8 @@ where
170183 // Do nothing under the assumption that this always (or almost always)
171184 // implies that the file comes from a different parent, compared to which
172185 // it was modified, not added.
173- } else {
174- if unblamed_to_out_is_done ( & mut hunks_to_blame, & mut out, suspect) {
175- break ' outer;
176- }
186+ } else if unblamed_to_out_is_done ( & mut hunks_to_blame, & mut out, suspect) {
187+ break ' outer;
177188 }
178189 }
179190 gix_diff:: tree:: recorder:: Change :: Deletion { .. } => {
@@ -418,7 +429,7 @@ fn find_path_entry_in_commit(
418429 buf : & mut Vec < u8 > ,
419430 buf2 : & mut Vec < u8 > ,
420431 stats : & mut Statistics ,
421- ) -> Result < Option < gix_object :: tree :: Entry > , Error > {
432+ ) -> Result < Option < ObjectId > , Error > {
422433 let commit_id = odb. find_commit ( commit, buf) ?. tree ( ) ;
423434 stats. commits_to_tree += 1 ;
424435 let tree_iter = odb. find_tree_iter ( & commit_id, buf) ?;
@@ -430,7 +441,7 @@ fn find_path_entry_in_commit(
430441 file_path. split ( |b| * b == b'/' ) . inspect ( |_| stats. trees_decoded += 1 ) ,
431442 ) ?;
432443 stats. trees_decoded -= 1 ;
433- Ok ( res)
444+ Ok ( res. map ( |e| e . oid ) )
434445}
435446
436447/// Return an iterator over tokens for use in diffing. These usually lines, but iit's important to unify them
0 commit comments