Skip to content

Commit

Permalink
Coalesce adjacent blame entries
Browse files Browse the repository at this point in the history
  • Loading branch information
cruessler committed Sep 19, 2024
1 parent 1e4191d commit 381b673
Show file tree
Hide file tree
Showing 2 changed files with 50 additions and 1 deletion.
44 changes: 43 additions & 1 deletion gix-blame/tests/blame.rs
Original file line number Diff line number Diff line change
Expand Up @@ -732,6 +732,47 @@ mod baseline {
}
}

/// This function merges adjacent blame entries. It merges entries that are adjacent both in the
/// blamed file as well as in the original file that introduced them. This follows `git`’s
/// behaviour. `libgit2`, as of 2024-09-19, only checks whether two entries are adjacent in the
/// blamed file which can result in different blames in certain edge cases. See [the commit][1]
/// that introduced the extra check into `git` for context.
///
/// [1]: https://github.com/git/git/commit/c2ebaa27d63bfb7c50cbbdaba90aee4efdd45d0a
fn coalesce_blame_entries(lines_blamed: Vec<BlameEntry>) -> Vec<BlameEntry> {
// TODO
// It’s possible this could better be done on insertion into `lines_blamed`.
lines_blamed.into_iter().fold(vec![], |mut acc, entry| {
let previous_entry = acc.last();

if let Some(previous_entry) = previous_entry {
if previous_entry.commit_id == entry.commit_id
&& previous_entry.range_in_blamed_file.end == entry.range_in_blamed_file.start
// As of 2024-09-19, the check below only is in `git`, but not in `libgit2`.
&& previous_entry.range_in_original_file.end == entry.range_in_original_file.start
{
let coalesced_entry = BlameEntry {
range_in_blamed_file: previous_entry.range_in_blamed_file.start..entry.range_in_blamed_file.end,
range_in_original_file: previous_entry.range_in_original_file.start
..entry.range_in_original_file.end,
commit_id: previous_entry.commit_id,
};

acc.pop();
acc.push(coalesced_entry);
} else {
acc.push(entry);
}

acc
} else {
acc.push(entry);

acc
}
})
}

fn blame_file(worktree_path: PathBuf, file_path: &BStr) -> Vec<BlameEntry> {
// TODO
// At a high level, what we want to do is the following:
Expand Down Expand Up @@ -944,7 +985,7 @@ fn blame_file(worktree_path: PathBuf, file_path: &BStr) -> Vec<BlameEntry> {
// order on insertion.
lines_blamed.sort_by(|a, b| a.range_in_blamed_file.start.cmp(&b.range_in_blamed_file.start));

lines_blamed
coalesce_blame_entries(lines_blamed)
}

macro_rules! mktest {
Expand Down Expand Up @@ -979,6 +1020,7 @@ mktest!(added_lines_around, "added-lines-around", 3);
mktest!(switched_lines, "switched-lines", 4);
mktest!(added_line_before_changed_line, "added-line-before-changed-line", 3);
mktest!(same_line_changed_twice, "same-line-changed-twice", 2);
mktest!(coalesce_adjacent_hunks, "coalesce-adjacent-hunks", 1);

#[test]
fn process_change_works() {
Expand Down
7 changes: 7 additions & 0 deletions gix-blame/tests/fixtures/make_blame_repo.sh
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,10 @@ git commit -q -m c1.2

echo "line 2" >> added-lines.txt
echo "line 2" >> added-lines-around.txt
echo -e "line 1\nline 2" > coalesce-adjacent-hunks.txt
git add added-lines.txt
git add added-lines-around.txt
git add coalesce-adjacent-hunks.txt
git commit -q -m c1.3

echo "line 2" >> simple.txt
Expand All @@ -45,7 +47,9 @@ git add added-line-before-changed-line.txt
git commit -q -m c2.3

echo -e "line 1\nline 2" > same-line-changed-twice.txt
echo -e "line 1\nline in between\nline 2" > coalesce-adjacent-hunks.txt
git add same-line-changed-twice.txt
git add coalesce-adjacent-hunks.txt
git commit -q -m c2.4

echo "line 3" >> simple.txt
Expand All @@ -65,7 +69,9 @@ git add changed-line-between-unchanged-lines.txt
git commit -q -m c3.2

echo -e "line 2\nline 3" > added-line-before-changed-line.txt
echo -e "line 1\nline 2" > coalesce-adjacent-hunks.txt
git add added-line-before-changed-line.txt
git add coalesce-adjacent-hunks.txt
git commit -q -m c3.3

echo -e "line 1\nline 2 changed" > same-line-changed-twice.txt
Expand Down Expand Up @@ -121,3 +127,4 @@ git blame --porcelain added-lines-around.txt > .git/added-lines-around.baseline
git blame --porcelain switched-lines.txt > .git/switched-lines.baseline
git blame --porcelain added-line-before-changed-line.txt > .git/added-line-before-changed-line.baseline
git blame --porcelain same-line-changed-twice.txt > .git/same-line-changed-twice.baseline
git blame --porcelain coalesce-adjacent-hunks.txt > .git/coalesce-adjacent-hunks.baseline

0 comments on commit 381b673

Please sign in to comment.