@@ -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,23 @@ 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
+
parent_index: 0,
178
+
};
179
+
blame_path.push(blame_path_entry);
180
+
}
181
+
159
182
break 'outer;
160
183
}
161
184
}
@@ -241,13 +264,13 @@ pub fn file(
241
264
}
242
265
243
266
let more_than_one_parent = parent_ids.len() > 1;
244
-
for (parent_id, parent_commit_time) in parent_ids {
245
-
queue.insert(parent_commit_time, parent_id);
267
+
for (index, (parent_id, parent_commit_time)) in parent_ids.iter().enumerate() {
268
+
queue.insert(*parent_commit_time, *parent_id);
246
269
let changes_for_file_path = tree_diff_at_file_path(
247
270
&odb,
248
271
current_file_path.as_ref(),
249
272
suspect,
250
-
parent_id,
273
+
*parent_id,
251
274
cache.as_ref(),
252
275
&mut stats,
253
276
&mut diff_state,
@@ -262,21 +285,33 @@ pub fn file(
262
285
// None of the changes affected the file we’re currently blaming.
263
286
// Copy blame to parent.
264
287
for unblamed_hunk in &mut hunks_to_blame {
265
-
unblamed_hunk.clone_blame(suspect, parent_id);
288
+
unblamed_hunk.clone_blame(suspect, *parent_id);
266
289
}
267
290
} else {
268
-
pass_blame_from_to(suspect, parent_id, &mut hunks_to_blame);
291
+
pass_blame_from_to(suspect, *parent_id, &mut hunks_to_blame);
269
292
}
270
293
continue;
271
294
};
272
295
273
296
match modification {
274
-
TreeDiffChange::Addition => {
297
+
TreeDiffChange::Addition { id } => {
275
298
if more_than_one_parent {
276
299
// Do nothing under the assumption that this always (or almost always)
277
300
// implies that the file comes from a different parent, compared to which
278
301
// it was modified, not added.
279
302
} else if unblamed_to_out_is_done(&mut hunks_to_blame, &mut out, suspect) {
303
+
if let Some(ref mut blame_path) = blame_path {
304
+
let blame_path_entry = BlamePathEntry {
305
+
source_file_path: current_file_path.clone(),
306
+
previous_source_file_path: None,
307
+
commit_id: suspect,
308
+
blob_id: id,
309
+
previous_blob_id: ObjectId::null(gix_hash::Kind::Sha1),
310
+
parent_index: index,
311
+
};
312
+
blame_path.push(blame_path_entry);
313
+
}
314
+
280
315
break 'outer;
281
316
}
282
317
}
@@ -294,7 +329,22 @@ pub fn file(
294
329
options.diff_algorithm,
295
330
&mut stats,
296
331
)?;
297
-
hunks_to_blame = process_changes(hunks_to_blame, changes, suspect, parent_id);
332
+
hunks_to_blame = process_changes(hunks_to_blame, changes.clone(), suspect, *parent_id);
333
+
if let Some(ref mut blame_path) = blame_path {
334
+
let has_blame_been_passed = hunks_to_blame.iter().any(|hunk| hunk.has_suspect(parent_id));
335
+
336
+
if has_blame_been_passed {
337
+
let blame_path_entry = BlamePathEntry {
338
+
source_file_path: current_file_path.clone(),
339
+
previous_source_file_path: Some(current_file_path.clone()),
340
+
commit_id: suspect,
341
+
blob_id: id,
342
+
previous_blob_id: previous_id,
343
+
parent_index: index,
344
+
};
345
+
blame_path.push(blame_path_entry);
346
+
}
347
+
}
298
348
}
299
349
TreeDiffChange::Rewrite {
300
350
source_location,
@@ -311,11 +361,29 @@ pub fn file(
311
361
options.diff_algorithm,
312
362
&mut stats,
313
363
)?;
314
-
hunks_to_blame = process_changes(hunks_to_blame, changes, suspect, parent_id);
364
+
hunks_to_blame = process_changes(hunks_to_blame, changes, suspect, *parent_id);
365
+
366
+
let mut has_blame_been_passed = false;
315
367
316
368
for hunk in hunks_to_blame.iter_mut() {
317
-
if hunk.has_suspect(&parent_id) {
369
+
if hunk.has_suspect(parent_id) {
318
370
hunk.source_file_name = Some(source_location.clone());
371
+
372
+
has_blame_been_passed = true;
373
+
}
374
+
}
375
+
376
+
if has_blame_been_passed {
377
+
if let Some(ref mut blame_path) = blame_path {
378
+
let blame_path_entry = BlamePathEntry {
379
+
source_file_path: current_file_path.clone(),
380
+
previous_source_file_path: Some(source_location.clone()),
381
+
commit_id: suspect,
382
+
blob_id: id,
383
+
previous_blob_id: source_id,
384
+
parent_index: index,
385
+
};
386
+
blame_path.push(blame_path_entry);
319
387
}
320
388
}
321
389
}
@@ -351,6 +419,7 @@ pub fn file(
351
419
entries: coalesce_blame_entries(out),
352
420
blob: blamed_file_blob,
353
421
statistics: stats,
422
+
blame_path,
354
423
})
355
424
}
356
425
@@ -435,7 +504,9 @@ fn coalesce_blame_entries(lines_blamed: Vec<BlameEntry>) -> Vec<BlameEntry> {
435
504
/// The union of [`gix_diff::tree::recorder::Change`] and [`gix_diff::tree_with_rewrites::Change`],
436
505
/// keeping only the blame-relevant information.
437
506
enum TreeDiffChange {
438
-
Addition,
507
+
Addition {
508
+
id: ObjectId,
509
+
},
439
510
Deletion,
440
511
Modification {
441
512
previous_id: ObjectId,
@@ -453,7 +524,7 @@ impl From<gix_diff::tree::recorder::Change> for TreeDiffChange {
453
524
use gix_diff::tree::recorder::Change;
454
525
455
526
match value {
456
-
Change::Addition { .. } => Self::Addition,
527
+
Change::Addition { oid, .. } => Self::Addition { id: oid },
457
528
Change::Deletion { .. } => Self::Deletion,
458
529
Change::Modification { previous_oid, oid, .. } => Self::Modification {
459
530
previous_id: previous_oid,
@@ -468,7 +539,7 @@ impl From<gix_diff::tree_with_rewrites::Change> for TreeDiffChange {
468
539
use gix_diff::tree_with_rewrites::Change;
469
540
470
541
match value {
471
-
Change::Addition { .. } => Self::Addition,
542
+
Change::Addition { id, .. } => Self::Addition { id },
472
543
Change::Deletion { .. } => Self::Deletion,
473
544
Change::Modification { previous_id, id, .. } => Self::Modification { previous_id, id },
474
545
Change::Rewrite {
RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4