A RetroSearch Logo

Home - News ( United States | United Kingdom | Italy | Germany ) - Football scores

Search Query:

Showing content from https://github.com/GitoxideLabs/gitoxide/commit/76eddf86b91afc3535f7eb0d9004652823ccda36 below:

Merge pull request #2022 from cruessler/add-rename-tracking-to-blame · GitoxideLabs/gitoxide@76eddf8 · GitHub

@@ -102,6 +102,7 @@ pub fn file(

102 102

hunks_to_blame.push(UnblamedHunk {

103 103

range_in_blamed_file: range.clone(),

104 104

suspects: [(suspect, range)].into(),

105 +

source_file_name: None,

105 106

});

106 107

}

107 108

@@ -120,12 +121,19 @@ pub fn file(

120 121

break;

121 122

}

122 123 123 -

let is_still_suspect = hunks_to_blame.iter().any(|hunk| hunk.has_suspect(&suspect));

124 -

if !is_still_suspect {

124 +

let first_hunk_for_suspect = hunks_to_blame.iter().find(|hunk| hunk.has_suspect(&suspect));

125 +

let Some(first_hunk_for_suspect) = first_hunk_for_suspect else {

125 126

// There are no `UnblamedHunk`s associated with this `suspect`, so we can continue with

126 127

// the next one.

127 128

continue 'outer;

128 -

}

129 +

};

130 + 131 +

// We know `first_hunk_for_suspect` can’t be `None` here because we check `is_some()`

132 +

// above.

133 +

let current_file_path = first_hunk_for_suspect

134 +

.source_file_name

135 +

.clone()

136 +

.unwrap_or_else(|| file_path.to_owned());

129 137 130 138

let commit = find_commit(cache.as_ref(), &odb, &suspect, &mut buf)?;

131 139

let commit_time = commit.commit_time()?;

@@ -165,7 +173,7 @@ pub fn file(

165 173

entry = find_path_entry_in_commit(

166 174

&odb,

167 175

&suspect,

168 -

file_path,

176 +

current_file_path.as_ref(),

169 177

cache.as_ref(),

170 178

&mut buf,

171 179

&mut buf2,

@@ -216,7 +224,7 @@ pub fn file(

216 224

if let Some(parent_entry_id) = find_path_entry_in_commit(

217 225

&odb,

218 226

parent_id,

219 -

file_path,

227 +

current_file_path.as_ref(),

220 228

cache.as_ref(),

221 229

&mut buf,

222 230

&mut buf2,

@@ -239,15 +247,17 @@ pub fn file(

239 247

queue.insert(parent_commit_time, parent_id);

240 248

let changes_for_file_path = tree_diff_at_file_path(

241 249

&odb,

242 -

file_path,

250 +

current_file_path.as_ref(),

243 251

suspect,

244 252

parent_id,

245 253

cache.as_ref(),

246 254

&mut stats,

247 255

&mut diff_state,

256 +

resource_cache,

248 257

&mut buf,

249 258

&mut buf2,

250 259

&mut buf3,

260 +

options.rewrites,

251 261

)?;

252 262

let Some(modification) = changes_for_file_path else {

253 263

if more_than_one_parent {

@@ -263,7 +273,7 @@ pub fn file(

263 273

};

264 274 265 275

match modification {

266 -

gix_diff::tree::recorder::Change::Addition { .. } => {

276 +

TreeDiffChange::Addition => {

267 277

if more_than_one_parent {

268 278

// Do nothing under the assumption that this always (or almost always)

269 279

// implies that the file comes from a different parent, compared to which

@@ -272,20 +282,44 @@ pub fn file(

272 282

break 'outer;

273 283

}

274 284

}

275 -

gix_diff::tree::recorder::Change::Deletion { .. } => {

285 +

TreeDiffChange::Deletion => {

276 286

unreachable!("We already found file_path in suspect^{{tree}}, so it can't be deleted")

277 287

}

278 -

gix_diff::tree::recorder::Change::Modification { previous_oid, oid, .. } => {

288 +

TreeDiffChange::Modification { previous_id, id } => {

279 289

let changes = blob_changes(

280 290

&odb,

281 291

resource_cache,

282 -

oid,

283 -

previous_oid,

292 +

id,

293 +

previous_id,

294 +

file_path,

295 +

file_path,

296 +

options.diff_algorithm,

297 +

&mut stats,

298 +

)?;

299 +

hunks_to_blame = process_changes(hunks_to_blame, changes, suspect, parent_id);

300 +

}

301 +

TreeDiffChange::Rewrite {

302 +

source_location,

303 +

source_id,

304 +

id,

305 +

} => {

306 +

let changes = blob_changes(

307 +

&odb,

308 +

resource_cache,

309 +

id,

310 +

source_id,

284 311

file_path,

312 +

source_location.as_ref(),

285 313

options.diff_algorithm,

286 314

&mut stats,

287 315

)?;

288 316

hunks_to_blame = process_changes(hunks_to_blame, changes, suspect, parent_id);

317 + 318 +

for hunk in hunks_to_blame.iter_mut() {

319 +

if hunk.has_suspect(&parent_id) {

320 +

hunk.source_file_name = Some(source_location.clone());

321 +

}

322 +

}

289 323

}

290 324

}

291 325

}

@@ -382,6 +416,7 @@ fn coalesce_blame_entries(lines_blamed: Vec<BlameEntry>) -> Vec<BlameEntry> {

382 416

len: NonZeroU32::new((current_source_range.end - previous_source_range.start) as u32)

383 417

.expect("BUG: hunks are never zero-sized"),

384 418

commit_id: previous_entry.commit_id,

419 +

source_file_name: previous_entry.source_file_name.clone(),

385 420

};

386 421 387 422

acc.pop();

@@ -399,6 +434,59 @@ fn coalesce_blame_entries(lines_blamed: Vec<BlameEntry>) -> Vec<BlameEntry> {

399 434

})

400 435

}

401 436 437 +

/// The union of [`gix_diff::tree::recorder::Change`] and [`gix_diff::tree_with_rewrites::Change`],

438 +

/// keeping only the blame-relevant information.

439 +

enum TreeDiffChange {

440 +

Addition,

441 +

Deletion,

442 +

Modification {

443 +

previous_id: ObjectId,

444 +

id: ObjectId,

445 +

},

446 +

Rewrite {

447 +

source_location: BString,

448 +

source_id: ObjectId,

449 +

id: ObjectId,

450 +

},

451 +

}

452 + 453 +

impl From<gix_diff::tree::recorder::Change> for TreeDiffChange {

454 +

fn from(value: gix_diff::tree::recorder::Change) -> Self {

455 +

use gix_diff::tree::recorder::Change;

456 + 457 +

match value {

458 +

Change::Addition { .. } => Self::Addition,

459 +

Change::Deletion { .. } => Self::Deletion,

460 +

Change::Modification { previous_oid, oid, .. } => Self::Modification {

461 +

previous_id: previous_oid,

462 +

id: oid,

463 +

},

464 +

}

465 +

}

466 +

}

467 + 468 +

impl From<gix_diff::tree_with_rewrites::Change> for TreeDiffChange {

469 +

fn from(value: gix_diff::tree_with_rewrites::Change) -> Self {

470 +

use gix_diff::tree_with_rewrites::Change;

471 + 472 +

match value {

473 +

Change::Addition { .. } => Self::Addition,

474 +

Change::Deletion { .. } => Self::Deletion,

475 +

Change::Modification { previous_id, id, .. } => Self::Modification { previous_id, id },

476 +

Change::Rewrite {

477 +

source_location,

478 +

source_id,

479 +

id,

480 +

..

481 +

} => Self::Rewrite {

482 +

source_location,

483 +

source_id,

484 +

id,

485 +

},

486 +

}

487 +

}

488 +

}

489 + 402 490

#[allow(clippy::too_many_arguments)]

403 491

fn tree_diff_at_file_path(

404 492

odb: impl gix_object::Find + gix_object::FindHeader,

@@ -408,10 +496,12 @@ fn tree_diff_at_file_path(

408 496

cache: Option<&gix_commitgraph::Graph>,

409 497

stats: &mut Statistics,

410 498

state: &mut gix_diff::tree::State,

499 +

resource_cache: &mut gix_diff::blob::Platform,

411 500

commit_buf: &mut Vec<u8>,

412 501

lhs_tree_buf: &mut Vec<u8>,

413 502

rhs_tree_buf: &mut Vec<u8>,

414 -

) -> Result<Option<gix_diff::tree::recorder::Change>, Error> {

503 +

rewrites: Option<gix_diff::Rewrites>,

504 +

) -> Result<Option<TreeDiffChange>, Error> {

415 505

let parent_tree_id = find_commit(cache, &odb, &parent_id, commit_buf)?.tree_id()?;

416 506 417 507

let parent_tree_iter = odb.find_tree_iter(&parent_tree_id, lhs_tree_buf)?;

@@ -422,6 +512,44 @@ fn tree_diff_at_file_path(

422 512

let tree_iter = odb.find_tree_iter(&tree_id, rhs_tree_buf)?;

423 513

stats.trees_decoded += 1;

424 514 515 +

let result = tree_diff_without_rewrites_at_file_path(&odb, file_path, stats, state, parent_tree_iter, tree_iter)?;

516 + 517 +

// Here, we follow git’s behaviour. We return when we’ve found a `Modification`. We try a

518 +

// second time with rename tracking when the change is either an `Addition` or a `Deletion`

519 +

// because those can turn out to have been a `Rewrite`.

520 +

// TODO(perf): renames are usually rare enough to not care about the work duplication done here.

521 +

// But in theory, a rename tracker could be used by us, on demand, and we could stuff the

522 +

// changes in there and have it find renames, without repeating the diff.

523 +

if matches!(result, Some(TreeDiffChange::Modification { .. })) {

524 +

return Ok(result);

525 +

}

526 +

let Some(rewrites) = rewrites else {

527 +

return Ok(result);

528 +

};

529 + 530 +

let result = tree_diff_with_rewrites_at_file_path(

531 +

&odb,

532 +

file_path,

533 +

stats,

534 +

state,

535 +

resource_cache,

536 +

parent_tree_iter,

537 +

tree_iter,

538 +

rewrites,

539 +

)?;

540 + 541 +

Ok(result)

542 +

}

543 + 544 +

#[allow(clippy::too_many_arguments)]

545 +

fn tree_diff_without_rewrites_at_file_path(

546 +

odb: impl gix_object::Find + gix_object::FindHeader,

547 +

file_path: &BStr,

548 +

stats: &mut Statistics,

549 +

state: &mut gix_diff::tree::State,

550 +

parent_tree_iter: gix_object::TreeRefIter<'_>,

551 +

tree_iter: gix_object::TreeRefIter<'_>,

552 +

) -> Result<Option<TreeDiffChange>, Error> {

425 553

struct FindChangeToPath {

426 554

inner: gix_diff::tree::Recorder,

427 555

interesting_path: BString,

@@ -509,17 +637,62 @@ fn tree_diff_at_file_path(

509 637

stats.trees_diffed += 1;

510 638 511 639

match result {

512 -

Ok(_) | Err(gix_diff::tree::Error::Cancelled) => Ok(recorder.change),

640 +

Ok(_) | Err(gix_diff::tree::Error::Cancelled) => Ok(recorder.change.map(Into::into)),

513 641

Err(error) => Err(Error::DiffTree(error)),

514 642

}

515 643

}

516 644 645 +

#[allow(clippy::too_many_arguments)]

646 +

fn tree_diff_with_rewrites_at_file_path(

647 +

odb: impl gix_object::Find + gix_object::FindHeader,

648 +

file_path: &BStr,

649 +

stats: &mut Statistics,

650 +

state: &mut gix_diff::tree::State,

651 +

resource_cache: &mut gix_diff::blob::Platform,

652 +

parent_tree_iter: gix_object::TreeRefIter<'_>,

653 +

tree_iter: gix_object::TreeRefIter<'_>,

654 +

rewrites: gix_diff::Rewrites,

655 +

) -> Result<Option<TreeDiffChange>, Error> {

656 +

let mut change: Option<gix_diff::tree_with_rewrites::Change> = None;

657 + 658 +

let options: gix_diff::tree_with_rewrites::Options = gix_diff::tree_with_rewrites::Options {

659 +

location: Some(gix_diff::tree::recorder::Location::Path),

660 +

rewrites: Some(rewrites),

661 +

};

662 +

let result = gix_diff::tree_with_rewrites(

663 +

parent_tree_iter,

664 +

tree_iter,

665 +

resource_cache,

666 +

state,

667 +

&odb,

668 +

|change_ref| -> Result<_, std::convert::Infallible> {

669 +

if change_ref.location() == file_path {

670 +

change = Some(change_ref.into_owned());

671 +

Ok(gix_diff::tree_with_rewrites::Action::Cancel)

672 +

} else {

673 +

Ok(gix_diff::tree_with_rewrites::Action::Continue)

674 +

}

675 +

},

676 +

options,

677 +

);

678 +

stats.trees_diffed_with_rewrites += 1;

679 + 680 +

match result {

681 +

Ok(_) | Err(gix_diff::tree_with_rewrites::Error::Diff(gix_diff::tree::Error::Cancelled)) => {

682 +

Ok(change.map(Into::into))

683 +

}

684 +

Err(error) => Err(Error::DiffTreeWithRewrites(error)),

685 +

}

686 +

}

687 + 688 +

#[allow(clippy::too_many_arguments)]

517 689

fn blob_changes(

518 690

odb: impl gix_object::Find + gix_object::FindHeader,

519 691

resource_cache: &mut gix_diff::blob::Platform,

520 692

oid: ObjectId,

521 693

previous_oid: ObjectId,

522 694

file_path: &BStr,

695 +

previous_file_path: &BStr,

523 696

diff_algorithm: gix_diff::blob::Algorithm,

524 697

stats: &mut Statistics,

525 698

) -> Result<Vec<Change>, Error> {

@@ -579,7 +752,7 @@ fn blob_changes(

579 752

resource_cache.set_resource(

580 753

previous_oid,

581 754

gix_object::tree::EntryKind::Blob,

582 -

file_path,

755 +

previous_file_path,

583 756

gix_diff::blob::ResourceKind::OldOrSource,

584 757

&odb,

585 758

)?;


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