@@ -10,7 +10,7 @@ use gix_traverse::commit::find as find_commit;
10
10
use smallvec:: SmallVec ;
11
11
12
12
use super :: { process_changes, Change , UnblamedHunk } ;
13
- use crate :: { BlameEntry , Error , Options , Outcome , Statistics } ;
13
+ use crate :: { types :: BlamePathEntry , BlameEntry , Error , Options , Outcome , Statistics } ;
14
14
15
15
/// Produce a list of consecutive [`BlameEntry`] instances to indicate in which commits the ranges of the file
16
16
/// at `suspect:<file_path>` originated in.
@@ -115,6 +115,12 @@ pub fn file(
115
115
let mut out = Vec :: new ( ) ;
116
116
let mut diff_state = gix_diff:: tree:: State :: default ( ) ;
117
117
let mut previous_entry: Option < ( ObjectId , ObjectId ) > = None ;
118
+ let mut blame_path = if options. debug_track_path {
119
+ Some ( Vec :: new ( ) )
120
+ } else {
121
+ None
122
+ } ;
123
+
118
124
' outer: while let Some ( suspect) = queue. pop_value ( ) {
119
125
stats. commits_traversed += 1 ;
120
126
if hunks_to_blame. is_empty ( ) {
@@ -156,6 +162,22 @@ pub fn file(
156
162
// true here. We could perhaps use diff-tree-to-tree to compare `suspect` against
157
163
// an empty tree to validate this assumption.
158
164
if unblamed_to_out_is_done ( & mut hunks_to_blame, & mut out, suspect) {
165
+ if let Some ( ref mut blame_path) = blame_path {
166
+ let entry = previous_entry
167
+ . take ( )
168
+ . filter ( |( id, _) | * id == suspect)
169
+ . map ( |( _, entry) | entry) ;
170
+
171
+ let blame_path_entry = BlamePathEntry {
172
+ source_file_path : current_file_path. clone ( ) ,
173
+ previous_source_file_path : None ,
174
+ commit_id : suspect,
175
+ blob_id : entry. unwrap_or ( ObjectId :: null ( gix_hash:: Kind :: Sha1 ) ) ,
176
+ previous_blob_id : ObjectId :: null ( gix_hash:: Kind :: Sha1 ) ,
177
+ } ;
178
+ blame_path. push ( blame_path_entry) ;
179
+ }
180
+
159
181
break ' outer;
160
182
}
161
183
}
@@ -271,12 +293,23 @@ pub fn file(
271
293
} ;
272
294
273
295
match modification {
274
- TreeDiffChange :: Addition => {
296
+ TreeDiffChange :: Addition { id } => {
275
297
if more_than_one_parent {
276
298
// Do nothing under the assumption that this always (or almost always)
277
299
// implies that the file comes from a different parent, compared to which
278
300
// it was modified, not added.
279
301
} else if unblamed_to_out_is_done ( & mut hunks_to_blame, & mut out, suspect) {
302
+ if let Some ( ref mut blame_path) = blame_path {
303
+ let blame_path_entry = BlamePathEntry {
304
+ source_file_path : current_file_path. clone ( ) ,
305
+ previous_source_file_path : None ,
306
+ commit_id : suspect,
307
+ blob_id : id,
308
+ previous_blob_id : ObjectId :: null ( gix_hash:: Kind :: Sha1 ) ,
309
+ } ;
310
+ blame_path. push ( blame_path_entry) ;
311
+ }
312
+
280
313
break ' outer;
281
314
}
282
315
}
@@ -295,6 +328,16 @@ pub fn file(
295
328
& mut stats,
296
329
) ?;
297
330
hunks_to_blame = process_changes ( hunks_to_blame, changes, suspect, parent_id) ;
331
+ if let Some ( ref mut blame_path) = blame_path {
332
+ let blame_path_entry = BlamePathEntry {
333
+ source_file_path : current_file_path. clone ( ) ,
334
+ previous_source_file_path : Some ( current_file_path. clone ( ) ) ,
335
+ commit_id : suspect,
336
+ blob_id : id,
337
+ previous_blob_id : previous_id,
338
+ } ;
339
+ blame_path. push ( blame_path_entry) ;
340
+ }
298
341
}
299
342
TreeDiffChange :: Rewrite {
300
343
source_location,
@@ -313,9 +356,26 @@ pub fn file(
313
356
) ?;
314
357
hunks_to_blame = process_changes ( hunks_to_blame, changes, suspect, parent_id) ;
315
358
359
+ let mut has_blame_been_passed = false ;
360
+
316
361
for hunk in hunks_to_blame. iter_mut ( ) {
317
362
if hunk. has_suspect ( & parent_id) {
318
363
hunk. source_file_name = Some ( source_location. clone ( ) ) ;
364
+
365
+ has_blame_been_passed = true ;
366
+ }
367
+ }
368
+
369
+ if has_blame_been_passed {
370
+ if let Some ( ref mut blame_path) = blame_path {
371
+ let blame_path_entry = BlamePathEntry {
372
+ source_file_path : current_file_path. clone ( ) ,
373
+ previous_source_file_path : Some ( source_location. clone ( ) ) ,
374
+ commit_id : suspect,
375
+ blob_id : id,
376
+ previous_blob_id : source_id,
377
+ } ;
378
+ blame_path. push ( blame_path_entry) ;
319
379
}
320
380
}
321
381
}
@@ -351,6 +411,7 @@ pub fn file(
351
411
entries : coalesce_blame_entries ( out) ,
352
412
blob : blamed_file_blob,
353
413
statistics : stats,
414
+ blame_path,
354
415
} )
355
416
}
356
417
@@ -435,7 +496,9 @@ fn coalesce_blame_entries(lines_blamed: Vec<BlameEntry>) -> Vec<BlameEntry> {
435
496
/// The union of [`gix_diff::tree::recorder::Change`] and [`gix_diff::tree_with_rewrites::Change`],
436
497
/// keeping only the blame-relevant information.
437
498
enum TreeDiffChange {
438
- Addition ,
499
+ Addition {
500
+ id : ObjectId ,
501
+ } ,
439
502
Deletion ,
440
503
Modification {
441
504
previous_id : ObjectId ,
@@ -453,7 +516,7 @@ impl From<gix_diff::tree::recorder::Change> for TreeDiffChange {
453
516
use gix_diff:: tree:: recorder:: Change ;
454
517
455
518
match value {
456
- Change :: Addition { .. } => Self :: Addition ,
519
+ Change :: Addition { oid , .. } => Self :: Addition { id : oid } ,
457
520
Change :: Deletion { .. } => Self :: Deletion ,
458
521
Change :: Modification { previous_oid, oid, .. } => Self :: Modification {
459
522
previous_id : previous_oid,
@@ -468,7 +531,7 @@ impl From<gix_diff::tree_with_rewrites::Change> for TreeDiffChange {
468
531
use gix_diff:: tree_with_rewrites:: Change ;
469
532
470
533
match value {
471
- Change :: Addition { .. } => Self :: Addition ,
534
+ Change :: Addition { id , .. } => Self :: Addition { id } ,
472
535
Change :: Deletion { .. } => Self :: Deletion ,
473
536
Change :: Modification { previous_id, id, .. } => Self :: Modification { previous_id, id } ,
474
537
Change :: Rewrite {
0 commit comments