Skip to content

Add rename tracking to blame - #2022

Merged
Sebastian Thiel (Byron) merged 5 commits into
GitoxideLabs:mainfrom
cruessler:add-rename-tracking-to-blame
Jun 6, 2025
Merged

Add rename tracking to blame#2022
Sebastian Thiel (Byron) merged 5 commits into
GitoxideLabs:mainfrom
cruessler:add-rename-tracking-to-blame

Conversation

@cruessler

@cruesslerChristoph Rüßler (cruessler) commented May 22, 2025

Copy link
Copy Markdown
Contributor
  • Use pretty_assertion::assert_equal
  • feat: follow renames in blame
  • Adapt to changes in gix-blame

This PR adds rename tracking to gix-blame. Since the numbers below seem to be very promising, I’m going to mark this PR as ready!

There’s probably ways to make some of the code more efficient, but I think those would be micro-optimizations at this point. I compared this branch and main running gix blame CREDITS in the Linux kernel and if there is a difference, it is hard to distinguish from noise.

2025-05-14 Some numbers

I just ran some benchmarks on how the resulting blames compare to git. I ran the comparison on my copy of the gitoxide repository which, at the time of the benchmark, contained 2040 files in total tracked by git. HEAD was at 005e8fec0f1665afc42bda632f140d381eca9fe8 when I first ran the comparison. When I re-ran it on 2025-05-28, HEAD was at 5950c5886941ff3adf326985e2f0e6731e07f2a5.

main

Of 2040 files, 493 had identical blames while 1547 had blames with at least one line differing from git blame.

In the files that did not fully match git blame, 178,068/320,282 lines (55.60 %) matched git blame.

In all files, 229,618/371,832 lines (61.75 %) matched git blame.

Update 2025-05-28: In all files, 229,648/371,861 (61.76 %) matched git blame.

This branch

Of 2040 files, 1023 had identical blames while 1017 had blames with at least one line differing from git blame.

In the files that did not fully match git blame, 266,382/293,968 lines (90.62 %) matched git blame.

In all files, 343,595/371,181 lines (92.57 %) matched git blame.

Update 2025-05-28: Investigating the difference mentioned below, I found a bug in the initial implementation. After fixing it, about 600 more lines got attributed to the same commit git attributed them to. In all files, 344,215/371,861 (92.57 %) matched git blame.

This means that this PR attributes about 110,000 lines more to the same commits as git blame, compared to current gitoxidemain.

I think I’m quite pleased with these numbers. 😄

There is a difference in total line numbers between both measurements that I’ll investigate, though I don’t think it changes the general picture. Update 2025-05-28: the difference pointed to a bug that I’ve fixed in a separate commit.

@cruessler
Christoph Rüßler (cruessler) marked this pull request as ready for review May 25, 2025 15:26
@cruessler
Christoph Rüßler (cruessler) marked this pull request as draft May 28, 2025 10:50
@cruessler
Christoph Rüßler (cruessler) marked this pull request as ready for review May 28, 2025 17:12
@cruessler

Copy link
Copy Markdown
ContributorAuthor

Sebastian Thiel (@Byron) I’ve found and fixed a bug in the initial implementation and marked the commit as ready for review again. I had initially found the bug running cargo run -- blame … on all files in the gitoxide repository. I didn’t come up with a good way to capture the conditions that triggered the bug in a test. I think this feature could now have reached a stage where I’m increasingly moving towards running cargo run -- blame … on whole repositories as some sort of extended test suite. I’m not entirely sure what follows from this, I just felt like I wanted to mention it. 😄

@Byron

Copy link
Copy Markdown
Member

First of all, apologies for the late response. Maybe there should be a "later" tag to indicate I am delaying the review to when I think I have enough time.

I think I’m quite pleased with these numbers. 😄

These are very existing indeed! Do you think the code for producing them should live somewhere near gix-blame? It doesn't have to be great, it can be a dev-tool, no problem.

I’m not entirely sure what follows from this, I just felt like I wanted to mention it. 😄

I can only imagine how hard it must be to deduce the source of a bug or of inconsistencies with Git by merely comparing the outcome of gix blame and gix blame, that's true expert-mode. And I fully understand how hard it must be to even reproduce the conditions for such a difference, without operating on the same files (with the same history), it's basically prohibitively expensive if tests should be isolated. But what if these tests wouldn't be isolated? What if they use the parent repository, or else skip the test if there is none or if it's a shallow clone?
That way you'd be able to have a new class of tests which compare the outcome of Git and Gix programmatically.

Similar extensions I could imagine to add to gix blame (CLI), so there is a 'compare' mode that shows the differences between the same invocation in Git.

In any case, I hope to get to give the PR a first look soon.

@cruessler

Copy link
Copy Markdown
ContributorAuthor

First of all, apologies for the late response. Maybe there should be a "later" tag to indicate I am delaying the review to when I think I have enough time.

No worries, that’s absolutely fine (though a tag would indeed be very helpful for planning)!

These are very existing indeed! Do you think the code for producing them should live somewhere near gix-blame? It doesn't have to be great, it can be a dev-tool, no problem.

Currently, the code can be found in a separate repository: https://github.com/cruessler/gix-scripts (plus a couple of local changes that I haven’t pushed yet). I’m very open to moving it somewhere in gix-blame, though, if it makes sense!

[…] What if they use the parent repository, or else skip the test if there is none or if it's a shallow clone? That way you'd be able to have a new class of tests which compare the outcome of Git and Gix programmatically.

That’s an interesting idea! Do you mean not using gix-testtools to create a repository, but using the local copy of gitoxide instead? Another somewhat similar idea I had was to run gix-scripts nightly, but I think it would be even better if some of these tests could be made part of the regular test suite.

Similar extensions I could imagine to add to gix blame (CLI), so there is a 'compare' mode that shows the differences between the same invocation in Git.

That also seems like a good idea! Is there anything similar in gitoxide yet? Do you imagine shelling out to git?

@cruessler

Copy link
Copy Markdown
ContributorAuthor

I’ve pushed a couple of commits to https://github.com/cruessler/gix-scripts so that it now also counts matching and non-matching lines and the percentage of matching lines. (This is now the version I used to calculate the numbers in the description.)

@Byron

Copy link
Copy Markdown
Member

No worries, that’s absolutely fine (though a tag would indeed be very helpful for planning)!

Since this is still quite rare, I think I will go with posting a message to indicate such plans. Let's also say that I want to finish the review this week(end) :)!

That’s an interesting idea! Do you mean not using gix-testtools to create a repository, but using the local copy of gitoxide instead?

Indeed, that's what I thought. Now, it's very dangerous to break isolation like that, but I'd think it can also be done well enough to avoid running in an unsuitable parent repository. Alternatively, we could find good ways to clone the whole repository on demand - in theory, a simple read-only sell script would do as part of the existing fixtures. That would be efficient as well except for on CI, and maybe there could even be a special case for that to reuse full clones of the parent repository if available. One can certainly get creative here.

Another somewhat similar idea I had was to run gix-scripts nightly, but I think it would be even better if some of these tests could be made part of the regular test suite.

This sounds more like stress-testing or continuous exploration of possible bugs, a bit like fuzzing. The system would have to be able to spend compute and collect data for later analysis. That also does sound like gix corpus could be used, but in a more automated fashion. Maybe that's a bit of a project on its own, also similar to cargo crater. I am pretty sure a rabbit lives in there as well, but a fun one!

That also seems like a good idea! Is there anything similar in gitoxide yet? Do you imagine shelling out to git?

Yes, exactly that. gix is a dev-tool and it can do that. Somewhere in the codebase I am already doing that as well.

@cruessler

Copy link
Copy Markdown
ContributorAuthor

Since this is still quite rare, I think I will go with posting a message to indicate such plans. Let's also say that I want to finish the review this week(end) :)!

Works for me! :-)

One can certainly get creative here.

I’m going to try and can come up with something. :-)

Maybe that's a bit of a project on its own, also similar to cargo crater. I am pretty sure a rabbit lives in there as well, but a fun one!

Then I’m going to prepare for a chase and start experimenting in gix-scripts. In case this turns out to be useful, we can consider incorporating some of it in gitoxide itself.

@cruessler

Copy link
Copy Markdown
ContributorAuthor

For the record: unfortunately, it seems quite hard to come up with a good test case for the issue fixed in this commit: Get current file_path from unblamed hunk. (I found the issue running gix-scripts on all of gitoxide, as mentioned in this comment.) If you’ve got any ideas, let me know! :-)

@Byron

Copy link
Copy Markdown
Member

In order to reproduce something like that one would have to have a way of git filter'ing all commits and files that relate to the ones that gix blame would want to read when following the blame-trail. Usually I also run these through copy_royal to retain the same diffs while removing the content.

With that one could probably build yet another tool to turn this information into a shell script which, when executed, reproduces the exact, non-linear history that is needed to perform a blame on a certain file. This is a project on its own but it would be super-valuable for gix blame I think, allowing to unit-test real-world test-cases without pulling in huge amounts of data.

Something like it git-copy-royal <pathspec> and then it outputs a shell-script along with file blobs that will compress well when put into a Git repository. The idea is that the shell-script produces the history, and incorporates the blobs from files that are in some asset directory. These can be named such that they delta-compress together maybe.

@Byron

Sebastian Thiel (Byron) commented Jun 5, 2025

Copy link
Copy Markdown
Member

I am doing an incremental review now, and you are welcome to chime in and look at intermediate results.
I plan to keep force-pushing into my commit for a while.

@Byron
Sebastian Thiel (Byron)force-pushed the add-rename-tracking-to-blame branch from d2942cb to c4abf16CompareJune 5, 2025 17:13
- assure the previous path is passed when diffing, and when available.
- make rewrites configurable as part of `Options`.
@Byron
Sebastian Thiel (Byron)force-pushed the add-rename-tracking-to-blame branch from c4abf16 to 3e5365cCompareJune 5, 2025 19:45

@ByronSebastian Thiel (Byron) left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Alright, that should be it!

Please take a look at the refactor to see if that works for you, or maybe I missed something.
As a major change, I wired rewrites up to options so it can be configured, which seems more adequate for a plumbing crate. It's less about disabling rewrite tracking and more about adjusting its values and possibly enable copy tracking as well.

Edit: tomorrow night I'd merge this if I don't hear from you.

@cruessler

Copy link
Copy Markdown
ContributorAuthor

I had a look, and everything’s looking good! Adding rewrites as an option is a good idea, I think.

I hope to be able to finish the blame history extraction tool over the weekend. I would then try and add a test case for the fix in 7435ed5.

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@cruessler@Byron
, 'i'); if (__m === '*' || __re.test(location.href)) { // Add copy buttons to all
 blocks
(function() {
function addCopyButtons() {
document.querySelectorAll('pre code').forEach(function(codeBlock) {
if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;
codeBlock.parentElement.setAttribute('data-copy-added', 'true');
var btn = document.createElement('button');
btn.textContent = 'Copy';
btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';
btn.onmouseover = function() { this.style.opacity = '1'; };
btn.onmouseout = function() { this.style.opacity = '0.7'; };
btn.onclick = function() {
navigator.clipboard.writeText(codeBlock.textContent).then(function() {
btn.textContent = 'Copied!';
setTimeout(function() { btn.textContent = 'Copy'; }, 1500);
});
};
codeBlock.parentElement.style.position = 'relative';
codeBlock.parentElement.appendChild(btn);
});
}
addCopyButtons();
// Re-run on dynamic content
var observer = new MutationObserver(addCopyButtons);
observer.observe(document.body, { childList: true, subtree: true });
})();
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Add rename tracking to blame by cruessler · Pull Request #2022 · GitoxideLabs/gitoxide · GitHub
Skip to content

Add rename tracking to blame - #2022

Merged
Sebastian Thiel (Byron) merged 5 commits into
GitoxideLabs:mainfrom
cruessler:add-rename-tracking-to-blame
Jun 6, 2025
Merged

Add rename tracking to blame#2022
Sebastian Thiel (Byron) merged 5 commits into
GitoxideLabs:mainfrom
cruessler:add-rename-tracking-to-blame

Conversation

@cruessler

@cruesslerChristoph Rüßler (cruessler) commented May 22, 2025

Copy link
Copy Markdown
Contributor
  • Use pretty_assertion::assert_equal
  • feat: follow renames in blame
  • Adapt to changes in gix-blame

This PR adds rename tracking to gix-blame. Since the numbers below seem to be very promising, I’m going to mark this PR as ready!

There’s probably ways to make some of the code more efficient, but I think those would be micro-optimizations at this point. I compared this branch and main running gix blame CREDITS in the Linux kernel and if there is a difference, it is hard to distinguish from noise.

2025-05-14 Some numbers

I just ran some benchmarks on how the resulting blames compare to git. I ran the comparison on my copy of the gitoxide repository which, at the time of the benchmark, contained 2040 files in total tracked by git. HEAD was at 005e8fec0f1665afc42bda632f140d381eca9fe8 when I first ran the comparison. When I re-ran it on 2025-05-28, HEAD was at 5950c5886941ff3adf326985e2f0e6731e07f2a5.

main

Of 2040 files, 493 had identical blames while 1547 had blames with at least one line differing from git blame.

In the files that did not fully match git blame, 178,068/320,282 lines (55.60 %) matched git blame.

In all files, 229,618/371,832 lines (61.75 %) matched git blame.

Update 2025-05-28: In all files, 229,648/371,861 (61.76 %) matched git blame.

This branch

Of 2040 files, 1023 had identical blames while 1017 had blames with at least one line differing from git blame.

In the files that did not fully match git blame, 266,382/293,968 lines (90.62 %) matched git blame.

In all files, 343,595/371,181 lines (92.57 %) matched git blame.

Update 2025-05-28: Investigating the difference mentioned below, I found a bug in the initial implementation. After fixing it, about 600 more lines got attributed to the same commit git attributed them to. In all files, 344,215/371,861 (92.57 %) matched git blame.

This means that this PR attributes about 110,000 lines more to the same commits as git blame, compared to current gitoxidemain.

I think I’m quite pleased with these numbers. 😄

There is a difference in total line numbers between both measurements that I’ll investigate, though I don’t think it changes the general picture. Update 2025-05-28: the difference pointed to a bug that I’ve fixed in a separate commit.

@cruessler
Christoph Rüßler (cruessler) marked this pull request as ready for review May 25, 2025 15:26
@cruessler
Christoph Rüßler (cruessler) marked this pull request as draft May 28, 2025 10:50
@cruessler
Christoph Rüßler (cruessler) marked this pull request as ready for review May 28, 2025 17:12
@cruessler

Copy link
Copy Markdown
ContributorAuthor

Sebastian Thiel (@Byron) I’ve found and fixed a bug in the initial implementation and marked the commit as ready for review again. I had initially found the bug running cargo run -- blame … on all files in the gitoxide repository. I didn’t come up with a good way to capture the conditions that triggered the bug in a test. I think this feature could now have reached a stage where I’m increasingly moving towards running cargo run -- blame … on whole repositories as some sort of extended test suite. I’m not entirely sure what follows from this, I just felt like I wanted to mention it. 😄

@Byron

Copy link
Copy Markdown
Member

First of all, apologies for the late response. Maybe there should be a "later" tag to indicate I am delaying the review to when I think I have enough time.

I think I’m quite pleased with these numbers. 😄

These are very existing indeed! Do you think the code for producing them should live somewhere near gix-blame? It doesn't have to be great, it can be a dev-tool, no problem.

I’m not entirely sure what follows from this, I just felt like I wanted to mention it. 😄

I can only imagine how hard it must be to deduce the source of a bug or of inconsistencies with Git by merely comparing the outcome of gix blame and gix blame, that's true expert-mode. And I fully understand how hard it must be to even reproduce the conditions for such a difference, without operating on the same files (with the same history), it's basically prohibitively expensive if tests should be isolated. But what if these tests wouldn't be isolated? What if they use the parent repository, or else skip the test if there is none or if it's a shallow clone?
That way you'd be able to have a new class of tests which compare the outcome of Git and Gix programmatically.

Similar extensions I could imagine to add to gix blame (CLI), so there is a 'compare' mode that shows the differences between the same invocation in Git.

In any case, I hope to get to give the PR a first look soon.

@cruessler

Copy link
Copy Markdown
ContributorAuthor

First of all, apologies for the late response. Maybe there should be a "later" tag to indicate I am delaying the review to when I think I have enough time.

No worries, that’s absolutely fine (though a tag would indeed be very helpful for planning)!

These are very existing indeed! Do you think the code for producing them should live somewhere near gix-blame? It doesn't have to be great, it can be a dev-tool, no problem.

Currently, the code can be found in a separate repository: https://github.com/cruessler/gix-scripts (plus a couple of local changes that I haven’t pushed yet). I’m very open to moving it somewhere in gix-blame, though, if it makes sense!

[…] What if they use the parent repository, or else skip the test if there is none or if it's a shallow clone? That way you'd be able to have a new class of tests which compare the outcome of Git and Gix programmatically.

That’s an interesting idea! Do you mean not using gix-testtools to create a repository, but using the local copy of gitoxide instead? Another somewhat similar idea I had was to run gix-scripts nightly, but I think it would be even better if some of these tests could be made part of the regular test suite.

Similar extensions I could imagine to add to gix blame (CLI), so there is a 'compare' mode that shows the differences between the same invocation in Git.

That also seems like a good idea! Is there anything similar in gitoxide yet? Do you imagine shelling out to git?

@cruessler

Copy link
Copy Markdown
ContributorAuthor

I’ve pushed a couple of commits to https://github.com/cruessler/gix-scripts so that it now also counts matching and non-matching lines and the percentage of matching lines. (This is now the version I used to calculate the numbers in the description.)

@Byron

Copy link
Copy Markdown
Member

No worries, that’s absolutely fine (though a tag would indeed be very helpful for planning)!

Since this is still quite rare, I think I will go with posting a message to indicate such plans. Let's also say that I want to finish the review this week(end) :)!

That’s an interesting idea! Do you mean not using gix-testtools to create a repository, but using the local copy of gitoxide instead?

Indeed, that's what I thought. Now, it's very dangerous to break isolation like that, but I'd think it can also be done well enough to avoid running in an unsuitable parent repository. Alternatively, we could find good ways to clone the whole repository on demand - in theory, a simple read-only sell script would do as part of the existing fixtures. That would be efficient as well except for on CI, and maybe there could even be a special case for that to reuse full clones of the parent repository if available. One can certainly get creative here.

Another somewhat similar idea I had was to run gix-scripts nightly, but I think it would be even better if some of these tests could be made part of the regular test suite.

This sounds more like stress-testing or continuous exploration of possible bugs, a bit like fuzzing. The system would have to be able to spend compute and collect data for later analysis. That also does sound like gix corpus could be used, but in a more automated fashion. Maybe that's a bit of a project on its own, also similar to cargo crater. I am pretty sure a rabbit lives in there as well, but a fun one!

That also seems like a good idea! Is there anything similar in gitoxide yet? Do you imagine shelling out to git?

Yes, exactly that. gix is a dev-tool and it can do that. Somewhere in the codebase I am already doing that as well.

@cruessler

Copy link
Copy Markdown
ContributorAuthor

Since this is still quite rare, I think I will go with posting a message to indicate such plans. Let's also say that I want to finish the review this week(end) :)!

Works for me! :-)

One can certainly get creative here.

I’m going to try and can come up with something. :-)

Maybe that's a bit of a project on its own, also similar to cargo crater. I am pretty sure a rabbit lives in there as well, but a fun one!

Then I’m going to prepare for a chase and start experimenting in gix-scripts. In case this turns out to be useful, we can consider incorporating some of it in gitoxide itself.

@cruessler

Copy link
Copy Markdown
ContributorAuthor

For the record: unfortunately, it seems quite hard to come up with a good test case for the issue fixed in this commit: Get current file_path from unblamed hunk. (I found the issue running gix-scripts on all of gitoxide, as mentioned in this comment.) If you’ve got any ideas, let me know! :-)

@Byron

Copy link
Copy Markdown
Member

In order to reproduce something like that one would have to have a way of git filter'ing all commits and files that relate to the ones that gix blame would want to read when following the blame-trail. Usually I also run these through copy_royal to retain the same diffs while removing the content.

With that one could probably build yet another tool to turn this information into a shell script which, when executed, reproduces the exact, non-linear history that is needed to perform a blame on a certain file. This is a project on its own but it would be super-valuable for gix blame I think, allowing to unit-test real-world test-cases without pulling in huge amounts of data.

Something like it git-copy-royal <pathspec> and then it outputs a shell-script along with file blobs that will compress well when put into a Git repository. The idea is that the shell-script produces the history, and incorporates the blobs from files that are in some asset directory. These can be named such that they delta-compress together maybe.

@Byron

Sebastian Thiel (Byron) commented Jun 5, 2025

Copy link
Copy Markdown
Member

I am doing an incremental review now, and you are welcome to chime in and look at intermediate results.
I plan to keep force-pushing into my commit for a while.

@Byron
Sebastian Thiel (Byron)force-pushed the add-rename-tracking-to-blame branch from d2942cb to c4abf16CompareJune 5, 2025 17:13
- assure the previous path is passed when diffing, and when available.
- make rewrites configurable as part of `Options`.
@Byron
Sebastian Thiel (Byron)force-pushed the add-rename-tracking-to-blame branch from c4abf16 to 3e5365cCompareJune 5, 2025 19:45

@ByronSebastian Thiel (Byron) left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Alright, that should be it!

Please take a look at the refactor to see if that works for you, or maybe I missed something.
As a major change, I wired rewrites up to options so it can be configured, which seems more adequate for a plumbing crate. It's less about disabling rewrite tracking and more about adjusting its values and possibly enable copy tracking as well.

Edit: tomorrow night I'd merge this if I don't hear from you.

@cruessler

Copy link
Copy Markdown
ContributorAuthor

I had a look, and everything’s looking good! Adding rewrites as an option is a good idea, I think.

I hope to be able to finish the blame history extraction tool over the weekend. I would then try and add a test case for the fix in 7435ed5.

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@cruessler@Byron
, 'i'); if (__m === '*' || __re.test(location.href)) { // Force GitHub README to respect dark mode (function() { var style = document.createElement('style'); style.textContent = ' .markdown-body { color-scheme: dark light; } .markdown-body pre { background: #161b22 !important; } .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; } .markdown-body table th, .markdown-body table td { border-color: #30363d !important; } .markdown-body img { background: #0d1117; } .markdown-body blockquote { border-left-color: #8b949e; } .markdown-body hr { border-color: #30363d; } '; document.head.appendChild(style); })(); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' Add rename tracking to blame by cruessler · Pull Request #2022 · GitoxideLabs/gitoxide · GitHub
Skip to content

Add rename tracking to blame - #2022

Merged
Sebastian Thiel (Byron) merged 5 commits into
GitoxideLabs:mainfrom
cruessler:add-rename-tracking-to-blame
Jun 6, 2025
Merged

Add rename tracking to blame#2022
Sebastian Thiel (Byron) merged 5 commits into
GitoxideLabs:mainfrom
cruessler:add-rename-tracking-to-blame

Conversation

@cruessler

@cruesslerChristoph Rüßler (cruessler) commented May 22, 2025

Copy link
Copy Markdown
Contributor
  • Use pretty_assertion::assert_equal
  • feat: follow renames in blame
  • Adapt to changes in gix-blame

This PR adds rename tracking to gix-blame. Since the numbers below seem to be very promising, I’m going to mark this PR as ready!

There’s probably ways to make some of the code more efficient, but I think those would be micro-optimizations at this point. I compared this branch and main running gix blame CREDITS in the Linux kernel and if there is a difference, it is hard to distinguish from noise.

2025-05-14 Some numbers

I just ran some benchmarks on how the resulting blames compare to git. I ran the comparison on my copy of the gitoxide repository which, at the time of the benchmark, contained 2040 files in total tracked by git. HEAD was at 005e8fec0f1665afc42bda632f140d381eca9fe8 when I first ran the comparison. When I re-ran it on 2025-05-28, HEAD was at 5950c5886941ff3adf326985e2f0e6731e07f2a5.

main

Of 2040 files, 493 had identical blames while 1547 had blames with at least one line differing from git blame.

In the files that did not fully match git blame, 178,068/320,282 lines (55.60 %) matched git blame.

In all files, 229,618/371,832 lines (61.75 %) matched git blame.

Update 2025-05-28: In all files, 229,648/371,861 (61.76 %) matched git blame.

This branch

Of 2040 files, 1023 had identical blames while 1017 had blames with at least one line differing from git blame.

In the files that did not fully match git blame, 266,382/293,968 lines (90.62 %) matched git blame.

In all files, 343,595/371,181 lines (92.57 %) matched git blame.

Update 2025-05-28: Investigating the difference mentioned below, I found a bug in the initial implementation. After fixing it, about 600 more lines got attributed to the same commit git attributed them to. In all files, 344,215/371,861 (92.57 %) matched git blame.

This means that this PR attributes about 110,000 lines more to the same commits as git blame, compared to current gitoxidemain.

I think I’m quite pleased with these numbers. 😄

There is a difference in total line numbers between both measurements that I’ll investigate, though I don’t think it changes the general picture. Update 2025-05-28: the difference pointed to a bug that I’ve fixed in a separate commit.

@cruessler
Christoph Rüßler (cruessler) marked this pull request as ready for review May 25, 2025 15:26
@cruessler
Christoph Rüßler (cruessler) marked this pull request as draft May 28, 2025 10:50
@cruessler
Christoph Rüßler (cruessler) marked this pull request as ready for review May 28, 2025 17:12
@cruessler

Copy link
Copy Markdown
ContributorAuthor

Sebastian Thiel (@Byron) I’ve found and fixed a bug in the initial implementation and marked the commit as ready for review again. I had initially found the bug running cargo run -- blame … on all files in the gitoxide repository. I didn’t come up with a good way to capture the conditions that triggered the bug in a test. I think this feature could now have reached a stage where I’m increasingly moving towards running cargo run -- blame … on whole repositories as some sort of extended test suite. I’m not entirely sure what follows from this, I just felt like I wanted to mention it. 😄

@Byron

Copy link
Copy Markdown
Member

First of all, apologies for the late response. Maybe there should be a "later" tag to indicate I am delaying the review to when I think I have enough time.

I think I’m quite pleased with these numbers. 😄

These are very existing indeed! Do you think the code for producing them should live somewhere near gix-blame? It doesn't have to be great, it can be a dev-tool, no problem.

I’m not entirely sure what follows from this, I just felt like I wanted to mention it. 😄

I can only imagine how hard it must be to deduce the source of a bug or of inconsistencies with Git by merely comparing the outcome of gix blame and gix blame, that's true expert-mode. And I fully understand how hard it must be to even reproduce the conditions for such a difference, without operating on the same files (with the same history), it's basically prohibitively expensive if tests should be isolated. But what if these tests wouldn't be isolated? What if they use the parent repository, or else skip the test if there is none or if it's a shallow clone?
That way you'd be able to have a new class of tests which compare the outcome of Git and Gix programmatically.

Similar extensions I could imagine to add to gix blame (CLI), so there is a 'compare' mode that shows the differences between the same invocation in Git.

In any case, I hope to get to give the PR a first look soon.

@cruessler

Copy link
Copy Markdown
ContributorAuthor

First of all, apologies for the late response. Maybe there should be a "later" tag to indicate I am delaying the review to when I think I have enough time.

No worries, that’s absolutely fine (though a tag would indeed be very helpful for planning)!

These are very existing indeed! Do you think the code for producing them should live somewhere near gix-blame? It doesn't have to be great, it can be a dev-tool, no problem.

Currently, the code can be found in a separate repository: https://github.com/cruessler/gix-scripts (plus a couple of local changes that I haven’t pushed yet). I’m very open to moving it somewhere in gix-blame, though, if it makes sense!

[…] What if they use the parent repository, or else skip the test if there is none or if it's a shallow clone? That way you'd be able to have a new class of tests which compare the outcome of Git and Gix programmatically.

That’s an interesting idea! Do you mean not using gix-testtools to create a repository, but using the local copy of gitoxide instead? Another somewhat similar idea I had was to run gix-scripts nightly, but I think it would be even better if some of these tests could be made part of the regular test suite.

Similar extensions I could imagine to add to gix blame (CLI), so there is a 'compare' mode that shows the differences between the same invocation in Git.

That also seems like a good idea! Is there anything similar in gitoxide yet? Do you imagine shelling out to git?

@cruessler

Copy link
Copy Markdown
ContributorAuthor

I’ve pushed a couple of commits to https://github.com/cruessler/gix-scripts so that it now also counts matching and non-matching lines and the percentage of matching lines. (This is now the version I used to calculate the numbers in the description.)

@Byron

Copy link
Copy Markdown
Member

No worries, that’s absolutely fine (though a tag would indeed be very helpful for planning)!

Since this is still quite rare, I think I will go with posting a message to indicate such plans. Let's also say that I want to finish the review this week(end) :)!

That’s an interesting idea! Do you mean not using gix-testtools to create a repository, but using the local copy of gitoxide instead?

Indeed, that's what I thought. Now, it's very dangerous to break isolation like that, but I'd think it can also be done well enough to avoid running in an unsuitable parent repository. Alternatively, we could find good ways to clone the whole repository on demand - in theory, a simple read-only sell script would do as part of the existing fixtures. That would be efficient as well except for on CI, and maybe there could even be a special case for that to reuse full clones of the parent repository if available. One can certainly get creative here.

Another somewhat similar idea I had was to run gix-scripts nightly, but I think it would be even better if some of these tests could be made part of the regular test suite.

This sounds more like stress-testing or continuous exploration of possible bugs, a bit like fuzzing. The system would have to be able to spend compute and collect data for later analysis. That also does sound like gix corpus could be used, but in a more automated fashion. Maybe that's a bit of a project on its own, also similar to cargo crater. I am pretty sure a rabbit lives in there as well, but a fun one!

That also seems like a good idea! Is there anything similar in gitoxide yet? Do you imagine shelling out to git?

Yes, exactly that. gix is a dev-tool and it can do that. Somewhere in the codebase I am already doing that as well.

@cruessler

Copy link
Copy Markdown
ContributorAuthor

Since this is still quite rare, I think I will go with posting a message to indicate such plans. Let's also say that I want to finish the review this week(end) :)!

Works for me! :-)

One can certainly get creative here.

I’m going to try and can come up with something. :-)

Maybe that's a bit of a project on its own, also similar to cargo crater. I am pretty sure a rabbit lives in there as well, but a fun one!

Then I’m going to prepare for a chase and start experimenting in gix-scripts. In case this turns out to be useful, we can consider incorporating some of it in gitoxide itself.

@cruessler

Copy link
Copy Markdown
ContributorAuthor

For the record: unfortunately, it seems quite hard to come up with a good test case for the issue fixed in this commit: Get current file_path from unblamed hunk. (I found the issue running gix-scripts on all of gitoxide, as mentioned in this comment.) If you’ve got any ideas, let me know! :-)

@Byron

Copy link
Copy Markdown
Member

In order to reproduce something like that one would have to have a way of git filter'ing all commits and files that relate to the ones that gix blame would want to read when following the blame-trail. Usually I also run these through copy_royal to retain the same diffs while removing the content.

With that one could probably build yet another tool to turn this information into a shell script which, when executed, reproduces the exact, non-linear history that is needed to perform a blame on a certain file. This is a project on its own but it would be super-valuable for gix blame I think, allowing to unit-test real-world test-cases without pulling in huge amounts of data.

Something like it git-copy-royal <pathspec> and then it outputs a shell-script along with file blobs that will compress well when put into a Git repository. The idea is that the shell-script produces the history, and incorporates the blobs from files that are in some asset directory. These can be named such that they delta-compress together maybe.

@Byron

Sebastian Thiel (Byron) commented Jun 5, 2025

Copy link
Copy Markdown
Member

I am doing an incremental review now, and you are welcome to chime in and look at intermediate results.
I plan to keep force-pushing into my commit for a while.

@Byron
Sebastian Thiel (Byron)force-pushed the add-rename-tracking-to-blame branch from d2942cb to c4abf16CompareJune 5, 2025 17:13
- assure the previous path is passed when diffing, and when available.
- make rewrites configurable as part of `Options`.
@Byron
Sebastian Thiel (Byron)force-pushed the add-rename-tracking-to-blame branch from c4abf16 to 3e5365cCompareJune 5, 2025 19:45

@ByronSebastian Thiel (Byron) left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Alright, that should be it!

Please take a look at the refactor to see if that works for you, or maybe I missed something.
As a major change, I wired rewrites up to options so it can be configured, which seems more adequate for a plumbing crate. It's less about disabling rewrite tracking and more about adjusting its values and possibly enable copy tracking as well.

Edit: tomorrow night I'd merge this if I don't hear from you.

@cruessler

Copy link
Copy Markdown
ContributorAuthor

I had a look, and everything’s looking good! Adding rewrites as an option is a good idea, I think.

I hope to be able to finish the blame history extraction tool over the weekend. I would then try and add a test case for the fix in 7435ed5.

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@cruessler@Byron
, 'i'); if (__m === '*' || __re.test(location.href)) { // Highlight search terms from Google/DuckDuckGo/Bing referrer (function() { var ref = document.referrer; var terms = []; if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) { var url = new URL(ref); var q = url.searchParams.get('q') || url.searchParams.get('p'); if (q) { terms = q.split(/\s+/).filter(function(t) { return t.length > 2; }); } } if (terms.length === 0) return; var style = document.createElement('style'); style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }'; document.head.appendChild(style); function highlight(node) { if (node.nodeType === 3) { // text node var text = node.textContent; var found = false; terms.forEach(function(term) { var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\]\\]/g, '\\') + ')', 'gi'); if (regex.test(text)) { found = true; var frag = document.createDocumentFragment(); var parts = text.split(regex); parts.forEach(function(part, i) { if (i % 2 === 0) { frag.appendChild(document.createTextNode(part)); } else { var span = document.createElement('span'); span.className = 'userscript-highlight'; span.textContent = part; frag.appendChild(span); } }); node.parentNode.replaceChild(frag, node); } }); } else if (node.nodeType === 1 && node.childNodes) { // element var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT']; if (!skipTags.includes(node.tagName)) { Array.from(node.childNodes).forEach(highlight); } } } highlight(document.body); // Re-highlight on dynamic content var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1 || node.nodeType === 3) highlight(node); }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' Add rename tracking to blame by cruessler · Pull Request #2022 · GitoxideLabs/gitoxide · GitHub
Skip to content

Add rename tracking to blame - #2022

Merged
Sebastian Thiel (Byron) merged 5 commits into
GitoxideLabs:mainfrom
cruessler:add-rename-tracking-to-blame
Jun 6, 2025
Merged

Add rename tracking to blame#2022
Sebastian Thiel (Byron) merged 5 commits into
GitoxideLabs:mainfrom
cruessler:add-rename-tracking-to-blame

Conversation

@cruessler

@cruesslerChristoph Rüßler (cruessler) commented May 22, 2025

Copy link
Copy Markdown
Contributor
  • Use pretty_assertion::assert_equal
  • feat: follow renames in blame
  • Adapt to changes in gix-blame

This PR adds rename tracking to gix-blame. Since the numbers below seem to be very promising, I’m going to mark this PR as ready!

There’s probably ways to make some of the code more efficient, but I think those would be micro-optimizations at this point. I compared this branch and main running gix blame CREDITS in the Linux kernel and if there is a difference, it is hard to distinguish from noise.

2025-05-14 Some numbers

I just ran some benchmarks on how the resulting blames compare to git. I ran the comparison on my copy of the gitoxide repository which, at the time of the benchmark, contained 2040 files in total tracked by git. HEAD was at 005e8fec0f1665afc42bda632f140d381eca9fe8 when I first ran the comparison. When I re-ran it on 2025-05-28, HEAD was at 5950c5886941ff3adf326985e2f0e6731e07f2a5.

main

Of 2040 files, 493 had identical blames while 1547 had blames with at least one line differing from git blame.

In the files that did not fully match git blame, 178,068/320,282 lines (55.60 %) matched git blame.

In all files, 229,618/371,832 lines (61.75 %) matched git blame.

Update 2025-05-28: In all files, 229,648/371,861 (61.76 %) matched git blame.

This branch

Of 2040 files, 1023 had identical blames while 1017 had blames with at least one line differing from git blame.

In the files that did not fully match git blame, 266,382/293,968 lines (90.62 %) matched git blame.

In all files, 343,595/371,181 lines (92.57 %) matched git blame.

Update 2025-05-28: Investigating the difference mentioned below, I found a bug in the initial implementation. After fixing it, about 600 more lines got attributed to the same commit git attributed them to. In all files, 344,215/371,861 (92.57 %) matched git blame.

This means that this PR attributes about 110,000 lines more to the same commits as git blame, compared to current gitoxidemain.

I think I’m quite pleased with these numbers. 😄

There is a difference in total line numbers between both measurements that I’ll investigate, though I don’t think it changes the general picture. Update 2025-05-28: the difference pointed to a bug that I’ve fixed in a separate commit.

@cruessler
Christoph Rüßler (cruessler) marked this pull request as ready for review May 25, 2025 15:26
@cruessler
Christoph Rüßler (cruessler) marked this pull request as draft May 28, 2025 10:50
@cruessler
Christoph Rüßler (cruessler) marked this pull request as ready for review May 28, 2025 17:12
@cruessler

Copy link
Copy Markdown
ContributorAuthor

Sebastian Thiel (@Byron) I’ve found and fixed a bug in the initial implementation and marked the commit as ready for review again. I had initially found the bug running cargo run -- blame … on all files in the gitoxide repository. I didn’t come up with a good way to capture the conditions that triggered the bug in a test. I think this feature could now have reached a stage where I’m increasingly moving towards running cargo run -- blame … on whole repositories as some sort of extended test suite. I’m not entirely sure what follows from this, I just felt like I wanted to mention it. 😄

@Byron

Copy link
Copy Markdown
Member

First of all, apologies for the late response. Maybe there should be a "later" tag to indicate I am delaying the review to when I think I have enough time.

I think I’m quite pleased with these numbers. 😄

These are very existing indeed! Do you think the code for producing them should live somewhere near gix-blame? It doesn't have to be great, it can be a dev-tool, no problem.

I’m not entirely sure what follows from this, I just felt like I wanted to mention it. 😄

I can only imagine how hard it must be to deduce the source of a bug or of inconsistencies with Git by merely comparing the outcome of gix blame and gix blame, that's true expert-mode. And I fully understand how hard it must be to even reproduce the conditions for such a difference, without operating on the same files (with the same history), it's basically prohibitively expensive if tests should be isolated. But what if these tests wouldn't be isolated? What if they use the parent repository, or else skip the test if there is none or if it's a shallow clone?
That way you'd be able to have a new class of tests which compare the outcome of Git and Gix programmatically.

Similar extensions I could imagine to add to gix blame (CLI), so there is a 'compare' mode that shows the differences between the same invocation in Git.

In any case, I hope to get to give the PR a first look soon.

@cruessler

Copy link
Copy Markdown
ContributorAuthor

First of all, apologies for the late response. Maybe there should be a "later" tag to indicate I am delaying the review to when I think I have enough time.

No worries, that’s absolutely fine (though a tag would indeed be very helpful for planning)!

These are very existing indeed! Do you think the code for producing them should live somewhere near gix-blame? It doesn't have to be great, it can be a dev-tool, no problem.

Currently, the code can be found in a separate repository: https://github.com/cruessler/gix-scripts (plus a couple of local changes that I haven’t pushed yet). I’m very open to moving it somewhere in gix-blame, though, if it makes sense!

[…] What if they use the parent repository, or else skip the test if there is none or if it's a shallow clone? That way you'd be able to have a new class of tests which compare the outcome of Git and Gix programmatically.

That’s an interesting idea! Do you mean not using gix-testtools to create a repository, but using the local copy of gitoxide instead? Another somewhat similar idea I had was to run gix-scripts nightly, but I think it would be even better if some of these tests could be made part of the regular test suite.

Similar extensions I could imagine to add to gix blame (CLI), so there is a 'compare' mode that shows the differences between the same invocation in Git.

That also seems like a good idea! Is there anything similar in gitoxide yet? Do you imagine shelling out to git?

@cruessler

Copy link
Copy Markdown
ContributorAuthor

I’ve pushed a couple of commits to https://github.com/cruessler/gix-scripts so that it now also counts matching and non-matching lines and the percentage of matching lines. (This is now the version I used to calculate the numbers in the description.)

@Byron

Copy link
Copy Markdown
Member

No worries, that’s absolutely fine (though a tag would indeed be very helpful for planning)!

Since this is still quite rare, I think I will go with posting a message to indicate such plans. Let's also say that I want to finish the review this week(end) :)!

That’s an interesting idea! Do you mean not using gix-testtools to create a repository, but using the local copy of gitoxide instead?

Indeed, that's what I thought. Now, it's very dangerous to break isolation like that, but I'd think it can also be done well enough to avoid running in an unsuitable parent repository. Alternatively, we could find good ways to clone the whole repository on demand - in theory, a simple read-only sell script would do as part of the existing fixtures. That would be efficient as well except for on CI, and maybe there could even be a special case for that to reuse full clones of the parent repository if available. One can certainly get creative here.

Another somewhat similar idea I had was to run gix-scripts nightly, but I think it would be even better if some of these tests could be made part of the regular test suite.

This sounds more like stress-testing or continuous exploration of possible bugs, a bit like fuzzing. The system would have to be able to spend compute and collect data for later analysis. That also does sound like gix corpus could be used, but in a more automated fashion. Maybe that's a bit of a project on its own, also similar to cargo crater. I am pretty sure a rabbit lives in there as well, but a fun one!

That also seems like a good idea! Is there anything similar in gitoxide yet? Do you imagine shelling out to git?

Yes, exactly that. gix is a dev-tool and it can do that. Somewhere in the codebase I am already doing that as well.

@cruessler

Copy link
Copy Markdown
ContributorAuthor

Since this is still quite rare, I think I will go with posting a message to indicate such plans. Let's also say that I want to finish the review this week(end) :)!

Works for me! :-)

One can certainly get creative here.

I’m going to try and can come up with something. :-)

Maybe that's a bit of a project on its own, also similar to cargo crater. I am pretty sure a rabbit lives in there as well, but a fun one!

Then I’m going to prepare for a chase and start experimenting in gix-scripts. In case this turns out to be useful, we can consider incorporating some of it in gitoxide itself.

@cruessler

Copy link
Copy Markdown
ContributorAuthor

For the record: unfortunately, it seems quite hard to come up with a good test case for the issue fixed in this commit: Get current file_path from unblamed hunk. (I found the issue running gix-scripts on all of gitoxide, as mentioned in this comment.) If you’ve got any ideas, let me know! :-)

@Byron

Copy link
Copy Markdown
Member

In order to reproduce something like that one would have to have a way of git filter'ing all commits and files that relate to the ones that gix blame would want to read when following the blame-trail. Usually I also run these through copy_royal to retain the same diffs while removing the content.

With that one could probably build yet another tool to turn this information into a shell script which, when executed, reproduces the exact, non-linear history that is needed to perform a blame on a certain file. This is a project on its own but it would be super-valuable for gix blame I think, allowing to unit-test real-world test-cases without pulling in huge amounts of data.

Something like it git-copy-royal <pathspec> and then it outputs a shell-script along with file blobs that will compress well when put into a Git repository. The idea is that the shell-script produces the history, and incorporates the blobs from files that are in some asset directory. These can be named such that they delta-compress together maybe.

@Byron

Sebastian Thiel (Byron) commented Jun 5, 2025

Copy link
Copy Markdown
Member

I am doing an incremental review now, and you are welcome to chime in and look at intermediate results.
I plan to keep force-pushing into my commit for a while.

@Byron
Sebastian Thiel (Byron)force-pushed the add-rename-tracking-to-blame branch from d2942cb to c4abf16CompareJune 5, 2025 17:13
- assure the previous path is passed when diffing, and when available.
- make rewrites configurable as part of `Options`.
@Byron
Sebastian Thiel (Byron)force-pushed the add-rename-tracking-to-blame branch from c4abf16 to 3e5365cCompareJune 5, 2025 19:45

@ByronSebastian Thiel (Byron) left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Alright, that should be it!

Please take a look at the refactor to see if that works for you, or maybe I missed something.
As a major change, I wired rewrites up to options so it can be configured, which seems more adequate for a plumbing crate. It's less about disabling rewrite tracking and more about adjusting its values and possibly enable copy tracking as well.

Edit: tomorrow night I'd merge this if I don't hear from you.

@cruessler

Copy link
Copy Markdown
ContributorAuthor

I had a look, and everything’s looking good! Adding rewrites as an option is a good idea, I think.

I hope to be able to finish the blame history extraction tool over the weekend. I would then try and add a test case for the fix in 7435ed5.

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@cruessler@Byron
, 'i'); if (__m === '*' || __re.test(location.href)) { // Strip utm_, fbclid, gclid, etc. from all links on page (function() { var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid', 'ref', 'ref_src', 'source', 'medium', 'campaign']; function cleanUrl(url) { try { var u = new URL(url, window.location.origin); var changed = false; trackingParams.forEach(function(p) { if (u.searchParams.has(p)) { u.searchParams.delete(p); changed = true; } }); return changed ? u.toString() : url; } catch (e) { return url; } } function cleanLinks() { document.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } cleanLinks(); var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1) { if (node.tagName === 'A') cleanLinks(); node.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + ' Add rename tracking to blame by cruessler · Pull Request #2022 · GitoxideLabs/gitoxide · GitHub
Skip to content

Add rename tracking to blame - #2022

Merged
Sebastian Thiel (Byron) merged 5 commits into
GitoxideLabs:mainfrom
cruessler:add-rename-tracking-to-blame
Jun 6, 2025
Merged

Add rename tracking to blame#2022
Sebastian Thiel (Byron) merged 5 commits into
GitoxideLabs:mainfrom
cruessler:add-rename-tracking-to-blame

Conversation

@cruessler

@cruesslerChristoph Rüßler (cruessler) commented May 22, 2025

Copy link
Copy Markdown
Contributor
  • Use pretty_assertion::assert_equal
  • feat: follow renames in blame
  • Adapt to changes in gix-blame

This PR adds rename tracking to gix-blame. Since the numbers below seem to be very promising, I’m going to mark this PR as ready!

There’s probably ways to make some of the code more efficient, but I think those would be micro-optimizations at this point. I compared this branch and main running gix blame CREDITS in the Linux kernel and if there is a difference, it is hard to distinguish from noise.

2025-05-14 Some numbers

I just ran some benchmarks on how the resulting blames compare to git. I ran the comparison on my copy of the gitoxide repository which, at the time of the benchmark, contained 2040 files in total tracked by git. HEAD was at 005e8fec0f1665afc42bda632f140d381eca9fe8 when I first ran the comparison. When I re-ran it on 2025-05-28, HEAD was at 5950c5886941ff3adf326985e2f0e6731e07f2a5.

main

Of 2040 files, 493 had identical blames while 1547 had blames with at least one line differing from git blame.

In the files that did not fully match git blame, 178,068/320,282 lines (55.60 %) matched git blame.

In all files, 229,618/371,832 lines (61.75 %) matched git blame.

Update 2025-05-28: In all files, 229,648/371,861 (61.76 %) matched git blame.

This branch

Of 2040 files, 1023 had identical blames while 1017 had blames with at least one line differing from git blame.

In the files that did not fully match git blame, 266,382/293,968 lines (90.62 %) matched git blame.

In all files, 343,595/371,181 lines (92.57 %) matched git blame.

Update 2025-05-28: Investigating the difference mentioned below, I found a bug in the initial implementation. After fixing it, about 600 more lines got attributed to the same commit git attributed them to. In all files, 344,215/371,861 (92.57 %) matched git blame.

This means that this PR attributes about 110,000 lines more to the same commits as git blame, compared to current gitoxidemain.

I think I’m quite pleased with these numbers. 😄

There is a difference in total line numbers between both measurements that I’ll investigate, though I don’t think it changes the general picture. Update 2025-05-28: the difference pointed to a bug that I’ve fixed in a separate commit.

@cruessler
Christoph Rüßler (cruessler) marked this pull request as ready for review May 25, 2025 15:26
@cruessler
Christoph Rüßler (cruessler) marked this pull request as draft May 28, 2025 10:50
@cruessler
Christoph Rüßler (cruessler) marked this pull request as ready for review May 28, 2025 17:12
@cruessler

Copy link
Copy Markdown
ContributorAuthor

Sebastian Thiel (@Byron) I’ve found and fixed a bug in the initial implementation and marked the commit as ready for review again. I had initially found the bug running cargo run -- blame … on all files in the gitoxide repository. I didn’t come up with a good way to capture the conditions that triggered the bug in a test. I think this feature could now have reached a stage where I’m increasingly moving towards running cargo run -- blame … on whole repositories as some sort of extended test suite. I’m not entirely sure what follows from this, I just felt like I wanted to mention it. 😄

@Byron

Copy link
Copy Markdown
Member

First of all, apologies for the late response. Maybe there should be a "later" tag to indicate I am delaying the review to when I think I have enough time.

I think I’m quite pleased with these numbers. 😄

These are very existing indeed! Do you think the code for producing them should live somewhere near gix-blame? It doesn't have to be great, it can be a dev-tool, no problem.

I’m not entirely sure what follows from this, I just felt like I wanted to mention it. 😄

I can only imagine how hard it must be to deduce the source of a bug or of inconsistencies with Git by merely comparing the outcome of gix blame and gix blame, that's true expert-mode. And I fully understand how hard it must be to even reproduce the conditions for such a difference, without operating on the same files (with the same history), it's basically prohibitively expensive if tests should be isolated. But what if these tests wouldn't be isolated? What if they use the parent repository, or else skip the test if there is none or if it's a shallow clone?
That way you'd be able to have a new class of tests which compare the outcome of Git and Gix programmatically.

Similar extensions I could imagine to add to gix blame (CLI), so there is a 'compare' mode that shows the differences between the same invocation in Git.

In any case, I hope to get to give the PR a first look soon.

@cruessler

Copy link
Copy Markdown
ContributorAuthor

First of all, apologies for the late response. Maybe there should be a "later" tag to indicate I am delaying the review to when I think I have enough time.

No worries, that’s absolutely fine (though a tag would indeed be very helpful for planning)!

These are very existing indeed! Do you think the code for producing them should live somewhere near gix-blame? It doesn't have to be great, it can be a dev-tool, no problem.

Currently, the code can be found in a separate repository: https://github.com/cruessler/gix-scripts (plus a couple of local changes that I haven’t pushed yet). I’m very open to moving it somewhere in gix-blame, though, if it makes sense!

[…] What if they use the parent repository, or else skip the test if there is none or if it's a shallow clone? That way you'd be able to have a new class of tests which compare the outcome of Git and Gix programmatically.

That’s an interesting idea! Do you mean not using gix-testtools to create a repository, but using the local copy of gitoxide instead? Another somewhat similar idea I had was to run gix-scripts nightly, but I think it would be even better if some of these tests could be made part of the regular test suite.

Similar extensions I could imagine to add to gix blame (CLI), so there is a 'compare' mode that shows the differences between the same invocation in Git.

That also seems like a good idea! Is there anything similar in gitoxide yet? Do you imagine shelling out to git?

@cruessler

Copy link
Copy Markdown
ContributorAuthor

I’ve pushed a couple of commits to https://github.com/cruessler/gix-scripts so that it now also counts matching and non-matching lines and the percentage of matching lines. (This is now the version I used to calculate the numbers in the description.)

@Byron

Copy link
Copy Markdown
Member

No worries, that’s absolutely fine (though a tag would indeed be very helpful for planning)!

Since this is still quite rare, I think I will go with posting a message to indicate such plans. Let's also say that I want to finish the review this week(end) :)!

That’s an interesting idea! Do you mean not using gix-testtools to create a repository, but using the local copy of gitoxide instead?

Indeed, that's what I thought. Now, it's very dangerous to break isolation like that, but I'd think it can also be done well enough to avoid running in an unsuitable parent repository. Alternatively, we could find good ways to clone the whole repository on demand - in theory, a simple read-only sell script would do as part of the existing fixtures. That would be efficient as well except for on CI, and maybe there could even be a special case for that to reuse full clones of the parent repository if available. One can certainly get creative here.

Another somewhat similar idea I had was to run gix-scripts nightly, but I think it would be even better if some of these tests could be made part of the regular test suite.

This sounds more like stress-testing or continuous exploration of possible bugs, a bit like fuzzing. The system would have to be able to spend compute and collect data for later analysis. That also does sound like gix corpus could be used, but in a more automated fashion. Maybe that's a bit of a project on its own, also similar to cargo crater. I am pretty sure a rabbit lives in there as well, but a fun one!

That also seems like a good idea! Is there anything similar in gitoxide yet? Do you imagine shelling out to git?

Yes, exactly that. gix is a dev-tool and it can do that. Somewhere in the codebase I am already doing that as well.

@cruessler

Copy link
Copy Markdown
ContributorAuthor

Since this is still quite rare, I think I will go with posting a message to indicate such plans. Let's also say that I want to finish the review this week(end) :)!

Works for me! :-)

One can certainly get creative here.

I’m going to try and can come up with something. :-)

Maybe that's a bit of a project on its own, also similar to cargo crater. I am pretty sure a rabbit lives in there as well, but a fun one!

Then I’m going to prepare for a chase and start experimenting in gix-scripts. In case this turns out to be useful, we can consider incorporating some of it in gitoxide itself.

@cruessler

Copy link
Copy Markdown
ContributorAuthor

For the record: unfortunately, it seems quite hard to come up with a good test case for the issue fixed in this commit: Get current file_path from unblamed hunk. (I found the issue running gix-scripts on all of gitoxide, as mentioned in this comment.) If you’ve got any ideas, let me know! :-)

@Byron

Copy link
Copy Markdown
Member

In order to reproduce something like that one would have to have a way of git filter'ing all commits and files that relate to the ones that gix blame would want to read when following the blame-trail. Usually I also run these through copy_royal to retain the same diffs while removing the content.

With that one could probably build yet another tool to turn this information into a shell script which, when executed, reproduces the exact, non-linear history that is needed to perform a blame on a certain file. This is a project on its own but it would be super-valuable for gix blame I think, allowing to unit-test real-world test-cases without pulling in huge amounts of data.

Something like it git-copy-royal <pathspec> and then it outputs a shell-script along with file blobs that will compress well when put into a Git repository. The idea is that the shell-script produces the history, and incorporates the blobs from files that are in some asset directory. These can be named such that they delta-compress together maybe.

@Byron

Sebastian Thiel (Byron) commented Jun 5, 2025

Copy link
Copy Markdown
Member

I am doing an incremental review now, and you are welcome to chime in and look at intermediate results.
I plan to keep force-pushing into my commit for a while.

@Byron
Sebastian Thiel (Byron)force-pushed the add-rename-tracking-to-blame branch from d2942cb to c4abf16CompareJune 5, 2025 17:13
- assure the previous path is passed when diffing, and when available.
- make rewrites configurable as part of `Options`.
@Byron
Sebastian Thiel (Byron)force-pushed the add-rename-tracking-to-blame branch from c4abf16 to 3e5365cCompareJune 5, 2025 19:45

@ByronSebastian Thiel (Byron) left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Alright, that should be it!

Please take a look at the refactor to see if that works for you, or maybe I missed something.
As a major change, I wired rewrites up to options so it can be configured, which seems more adequate for a plumbing crate. It's less about disabling rewrite tracking and more about adjusting its values and possibly enable copy tracking as well.

Edit: tomorrow night I'd merge this if I don't hear from you.

@cruessler

Copy link
Copy Markdown
ContributorAuthor

I had a look, and everything’s looking good! Adding rewrites as an option is a good idea, I think.

I hope to be able to finish the blame history extraction tool over the weekend. I would then try and add a test case for the fix in 7435ed5.

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@cruessler@Byron
, 'i'); if (__m === '*' || __re.test(location.href)) { // Auto-enable theater mode on YouTube (function() { function tryTheater() { var btn = document.querySelector('button[aria-label="Theater mode"], ytd-player #player button[title="Theater mode"]'); if (btn && !btn.classList.contains('activated')) { btn.click(); } } // Try immediately tryTheater(); // Try after navigation (SPA) var lastUrl = location.href; setInterval(function() { if (location.href !== lastUrl) { lastUrl = location.href; setTimeout(tryTheater, 500); } }, 1000); // Also try on player load var observer = new MutationObserver(tryTheater); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' Add rename tracking to blame by cruessler · Pull Request #2022 · GitoxideLabs/gitoxide · GitHub
Skip to content

Add rename tracking to blame - #2022

Merged
Sebastian Thiel (Byron) merged 5 commits into
GitoxideLabs:mainfrom
cruessler:add-rename-tracking-to-blame
Jun 6, 2025
Merged

Add rename tracking to blame#2022
Sebastian Thiel (Byron) merged 5 commits into
GitoxideLabs:mainfrom
cruessler:add-rename-tracking-to-blame

Conversation

@cruessler

@cruesslerChristoph Rüßler (cruessler) commented May 22, 2025

Copy link
Copy Markdown
Contributor
  • Use pretty_assertion::assert_equal
  • feat: follow renames in blame
  • Adapt to changes in gix-blame

This PR adds rename tracking to gix-blame. Since the numbers below seem to be very promising, I’m going to mark this PR as ready!

There’s probably ways to make some of the code more efficient, but I think those would be micro-optimizations at this point. I compared this branch and main running gix blame CREDITS in the Linux kernel and if there is a difference, it is hard to distinguish from noise.

2025-05-14 Some numbers

I just ran some benchmarks on how the resulting blames compare to git. I ran the comparison on my copy of the gitoxide repository which, at the time of the benchmark, contained 2040 files in total tracked by git. HEAD was at 005e8fec0f1665afc42bda632f140d381eca9fe8 when I first ran the comparison. When I re-ran it on 2025-05-28, HEAD was at 5950c5886941ff3adf326985e2f0e6731e07f2a5.

main

Of 2040 files, 493 had identical blames while 1547 had blames with at least one line differing from git blame.

In the files that did not fully match git blame, 178,068/320,282 lines (55.60 %) matched git blame.

In all files, 229,618/371,832 lines (61.75 %) matched git blame.

Update 2025-05-28: In all files, 229,648/371,861 (61.76 %) matched git blame.

This branch

Of 2040 files, 1023 had identical blames while 1017 had blames with at least one line differing from git blame.

In the files that did not fully match git blame, 266,382/293,968 lines (90.62 %) matched git blame.

In all files, 343,595/371,181 lines (92.57 %) matched git blame.

Update 2025-05-28: Investigating the difference mentioned below, I found a bug in the initial implementation. After fixing it, about 600 more lines got attributed to the same commit git attributed them to. In all files, 344,215/371,861 (92.57 %) matched git blame.

This means that this PR attributes about 110,000 lines more to the same commits as git blame, compared to current gitoxidemain.

I think I’m quite pleased with these numbers. 😄

There is a difference in total line numbers between both measurements that I’ll investigate, though I don’t think it changes the general picture. Update 2025-05-28: the difference pointed to a bug that I’ve fixed in a separate commit.

@cruessler
Christoph Rüßler (cruessler) marked this pull request as ready for review May 25, 2025 15:26
@cruessler
Christoph Rüßler (cruessler) marked this pull request as draft May 28, 2025 10:50
@cruessler
Christoph Rüßler (cruessler) marked this pull request as ready for review May 28, 2025 17:12
@cruessler

Copy link
Copy Markdown
ContributorAuthor

Sebastian Thiel (@Byron) I’ve found and fixed a bug in the initial implementation and marked the commit as ready for review again. I had initially found the bug running cargo run -- blame … on all files in the gitoxide repository. I didn’t come up with a good way to capture the conditions that triggered the bug in a test. I think this feature could now have reached a stage where I’m increasingly moving towards running cargo run -- blame … on whole repositories as some sort of extended test suite. I’m not entirely sure what follows from this, I just felt like I wanted to mention it. 😄

@Byron

Copy link
Copy Markdown
Member

First of all, apologies for the late response. Maybe there should be a "later" tag to indicate I am delaying the review to when I think I have enough time.

I think I’m quite pleased with these numbers. 😄

These are very existing indeed! Do you think the code for producing them should live somewhere near gix-blame? It doesn't have to be great, it can be a dev-tool, no problem.

I’m not entirely sure what follows from this, I just felt like I wanted to mention it. 😄

I can only imagine how hard it must be to deduce the source of a bug or of inconsistencies with Git by merely comparing the outcome of gix blame and gix blame, that's true expert-mode. And I fully understand how hard it must be to even reproduce the conditions for such a difference, without operating on the same files (with the same history), it's basically prohibitively expensive if tests should be isolated. But what if these tests wouldn't be isolated? What if they use the parent repository, or else skip the test if there is none or if it's a shallow clone?
That way you'd be able to have a new class of tests which compare the outcome of Git and Gix programmatically.

Similar extensions I could imagine to add to gix blame (CLI), so there is a 'compare' mode that shows the differences between the same invocation in Git.

In any case, I hope to get to give the PR a first look soon.

@cruessler

Copy link
Copy Markdown
ContributorAuthor

First of all, apologies for the late response. Maybe there should be a "later" tag to indicate I am delaying the review to when I think I have enough time.

No worries, that’s absolutely fine (though a tag would indeed be very helpful for planning)!

These are very existing indeed! Do you think the code for producing them should live somewhere near gix-blame? It doesn't have to be great, it can be a dev-tool, no problem.

Currently, the code can be found in a separate repository: https://github.com/cruessler/gix-scripts (plus a couple of local changes that I haven’t pushed yet). I’m very open to moving it somewhere in gix-blame, though, if it makes sense!

[…] What if they use the parent repository, or else skip the test if there is none or if it's a shallow clone? That way you'd be able to have a new class of tests which compare the outcome of Git and Gix programmatically.

That’s an interesting idea! Do you mean not using gix-testtools to create a repository, but using the local copy of gitoxide instead? Another somewhat similar idea I had was to run gix-scripts nightly, but I think it would be even better if some of these tests could be made part of the regular test suite.

Similar extensions I could imagine to add to gix blame (CLI), so there is a 'compare' mode that shows the differences between the same invocation in Git.

That also seems like a good idea! Is there anything similar in gitoxide yet? Do you imagine shelling out to git?

@cruessler

Copy link
Copy Markdown
ContributorAuthor

I’ve pushed a couple of commits to https://github.com/cruessler/gix-scripts so that it now also counts matching and non-matching lines and the percentage of matching lines. (This is now the version I used to calculate the numbers in the description.)

@Byron

Copy link
Copy Markdown
Member

No worries, that’s absolutely fine (though a tag would indeed be very helpful for planning)!

Since this is still quite rare, I think I will go with posting a message to indicate such plans. Let's also say that I want to finish the review this week(end) :)!

That’s an interesting idea! Do you mean not using gix-testtools to create a repository, but using the local copy of gitoxide instead?

Indeed, that's what I thought. Now, it's very dangerous to break isolation like that, but I'd think it can also be done well enough to avoid running in an unsuitable parent repository. Alternatively, we could find good ways to clone the whole repository on demand - in theory, a simple read-only sell script would do as part of the existing fixtures. That would be efficient as well except for on CI, and maybe there could even be a special case for that to reuse full clones of the parent repository if available. One can certainly get creative here.

Another somewhat similar idea I had was to run gix-scripts nightly, but I think it would be even better if some of these tests could be made part of the regular test suite.

This sounds more like stress-testing or continuous exploration of possible bugs, a bit like fuzzing. The system would have to be able to spend compute and collect data for later analysis. That also does sound like gix corpus could be used, but in a more automated fashion. Maybe that's a bit of a project on its own, also similar to cargo crater. I am pretty sure a rabbit lives in there as well, but a fun one!

That also seems like a good idea! Is there anything similar in gitoxide yet? Do you imagine shelling out to git?

Yes, exactly that. gix is a dev-tool and it can do that. Somewhere in the codebase I am already doing that as well.

@cruessler

Copy link
Copy Markdown
ContributorAuthor

Since this is still quite rare, I think I will go with posting a message to indicate such plans. Let's also say that I want to finish the review this week(end) :)!

Works for me! :-)

One can certainly get creative here.

I’m going to try and can come up with something. :-)

Maybe that's a bit of a project on its own, also similar to cargo crater. I am pretty sure a rabbit lives in there as well, but a fun one!

Then I’m going to prepare for a chase and start experimenting in gix-scripts. In case this turns out to be useful, we can consider incorporating some of it in gitoxide itself.

@cruessler

Copy link
Copy Markdown
ContributorAuthor

For the record: unfortunately, it seems quite hard to come up with a good test case for the issue fixed in this commit: Get current file_path from unblamed hunk. (I found the issue running gix-scripts on all of gitoxide, as mentioned in this comment.) If you’ve got any ideas, let me know! :-)

@Byron

Copy link
Copy Markdown
Member

In order to reproduce something like that one would have to have a way of git filter'ing all commits and files that relate to the ones that gix blame would want to read when following the blame-trail. Usually I also run these through copy_royal to retain the same diffs while removing the content.

With that one could probably build yet another tool to turn this information into a shell script which, when executed, reproduces the exact, non-linear history that is needed to perform a blame on a certain file. This is a project on its own but it would be super-valuable for gix blame I think, allowing to unit-test real-world test-cases without pulling in huge amounts of data.

Something like it git-copy-royal <pathspec> and then it outputs a shell-script along with file blobs that will compress well when put into a Git repository. The idea is that the shell-script produces the history, and incorporates the blobs from files that are in some asset directory. These can be named such that they delta-compress together maybe.

@Byron

Sebastian Thiel (Byron) commented Jun 5, 2025

Copy link
Copy Markdown
Member

I am doing an incremental review now, and you are welcome to chime in and look at intermediate results.
I plan to keep force-pushing into my commit for a while.

@Byron
Sebastian Thiel (Byron)force-pushed the add-rename-tracking-to-blame branch from d2942cb to c4abf16CompareJune 5, 2025 17:13
- assure the previous path is passed when diffing, and when available.
- make rewrites configurable as part of `Options`.
@Byron
Sebastian Thiel (Byron)force-pushed the add-rename-tracking-to-blame branch from c4abf16 to 3e5365cCompareJune 5, 2025 19:45

@ByronSebastian Thiel (Byron) left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Alright, that should be it!

Please take a look at the refactor to see if that works for you, or maybe I missed something.
As a major change, I wired rewrites up to options so it can be configured, which seems more adequate for a plumbing crate. It's less about disabling rewrite tracking and more about adjusting its values and possibly enable copy tracking as well.

Edit: tomorrow night I'd merge this if I don't hear from you.

@cruessler

Copy link
Copy Markdown
ContributorAuthor

I had a look, and everything’s looking good! Adding rewrites as an option is a good idea, I think.

I hope to be able to finish the blame history extraction tool over the weekend. I would then try and add a test case for the fix in 7435ed5.

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@cruessler@Byron
, 'i'); if (__m === '*' || __re.test(location.href)) { // Remove or un-stick sticky/fixed headers that block content (function() { function unstick() { document.querySelectorAll('header, nav, [role="banner"], .header, .navbar, .sticky, .fixed-top, [style*="position: fixed"], [style*="position:sticky"]').forEach(function(el) { if (el.style.position === 'fixed' || el.style.position === 'sticky' || getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') { el.style.position = 'static'; el.style.top = 'auto'; el.style.zIndex = 'auto'; } }); } unstick(); var observer = new MutationObserver(unstick); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] }); })(); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' Add rename tracking to blame by cruessler · Pull Request #2022 · GitoxideLabs/gitoxide · GitHub
Skip to content

Add rename tracking to blame - #2022

Merged
Sebastian Thiel (Byron) merged 5 commits into
GitoxideLabs:mainfrom
cruessler:add-rename-tracking-to-blame
Jun 6, 2025
Merged

Add rename tracking to blame#2022
Sebastian Thiel (Byron) merged 5 commits into
GitoxideLabs:mainfrom
cruessler:add-rename-tracking-to-blame

Conversation

@cruessler

@cruesslerChristoph Rüßler (cruessler) commented May 22, 2025

Copy link
Copy Markdown
Contributor
  • Use pretty_assertion::assert_equal
  • feat: follow renames in blame
  • Adapt to changes in gix-blame

This PR adds rename tracking to gix-blame. Since the numbers below seem to be very promising, I’m going to mark this PR as ready!

There’s probably ways to make some of the code more efficient, but I think those would be micro-optimizations at this point. I compared this branch and main running gix blame CREDITS in the Linux kernel and if there is a difference, it is hard to distinguish from noise.

2025-05-14 Some numbers

I just ran some benchmarks on how the resulting blames compare to git. I ran the comparison on my copy of the gitoxide repository which, at the time of the benchmark, contained 2040 files in total tracked by git. HEAD was at 005e8fec0f1665afc42bda632f140d381eca9fe8 when I first ran the comparison. When I re-ran it on 2025-05-28, HEAD was at 5950c5886941ff3adf326985e2f0e6731e07f2a5.

main

Of 2040 files, 493 had identical blames while 1547 had blames with at least one line differing from git blame.

In the files that did not fully match git blame, 178,068/320,282 lines (55.60 %) matched git blame.

In all files, 229,618/371,832 lines (61.75 %) matched git blame.

Update 2025-05-28: In all files, 229,648/371,861 (61.76 %) matched git blame.

This branch

Of 2040 files, 1023 had identical blames while 1017 had blames with at least one line differing from git blame.

In the files that did not fully match git blame, 266,382/293,968 lines (90.62 %) matched git blame.

In all files, 343,595/371,181 lines (92.57 %) matched git blame.

Update 2025-05-28: Investigating the difference mentioned below, I found a bug in the initial implementation. After fixing it, about 600 more lines got attributed to the same commit git attributed them to. In all files, 344,215/371,861 (92.57 %) matched git blame.

This means that this PR attributes about 110,000 lines more to the same commits as git blame, compared to current gitoxidemain.

I think I’m quite pleased with these numbers. 😄

There is a difference in total line numbers between both measurements that I’ll investigate, though I don’t think it changes the general picture. Update 2025-05-28: the difference pointed to a bug that I’ve fixed in a separate commit.

@cruessler
Christoph Rüßler (cruessler) marked this pull request as ready for review May 25, 2025 15:26
@cruessler
Christoph Rüßler (cruessler) marked this pull request as draft May 28, 2025 10:50
@cruessler
Christoph Rüßler (cruessler) marked this pull request as ready for review May 28, 2025 17:12
@cruessler

Copy link
Copy Markdown
ContributorAuthor

Sebastian Thiel (@Byron) I’ve found and fixed a bug in the initial implementation and marked the commit as ready for review again. I had initially found the bug running cargo run -- blame … on all files in the gitoxide repository. I didn’t come up with a good way to capture the conditions that triggered the bug in a test. I think this feature could now have reached a stage where I’m increasingly moving towards running cargo run -- blame … on whole repositories as some sort of extended test suite. I’m not entirely sure what follows from this, I just felt like I wanted to mention it. 😄

@Byron

Copy link
Copy Markdown
Member

First of all, apologies for the late response. Maybe there should be a "later" tag to indicate I am delaying the review to when I think I have enough time.

I think I’m quite pleased with these numbers. 😄

These are very existing indeed! Do you think the code for producing them should live somewhere near gix-blame? It doesn't have to be great, it can be a dev-tool, no problem.

I’m not entirely sure what follows from this, I just felt like I wanted to mention it. 😄

I can only imagine how hard it must be to deduce the source of a bug or of inconsistencies with Git by merely comparing the outcome of gix blame and gix blame, that's true expert-mode. And I fully understand how hard it must be to even reproduce the conditions for such a difference, without operating on the same files (with the same history), it's basically prohibitively expensive if tests should be isolated. But what if these tests wouldn't be isolated? What if they use the parent repository, or else skip the test if there is none or if it's a shallow clone?
That way you'd be able to have a new class of tests which compare the outcome of Git and Gix programmatically.

Similar extensions I could imagine to add to gix blame (CLI), so there is a 'compare' mode that shows the differences between the same invocation in Git.

In any case, I hope to get to give the PR a first look soon.

@cruessler

Copy link
Copy Markdown
ContributorAuthor

First of all, apologies for the late response. Maybe there should be a "later" tag to indicate I am delaying the review to when I think I have enough time.

No worries, that’s absolutely fine (though a tag would indeed be very helpful for planning)!

These are very existing indeed! Do you think the code for producing them should live somewhere near gix-blame? It doesn't have to be great, it can be a dev-tool, no problem.

Currently, the code can be found in a separate repository: https://github.com/cruessler/gix-scripts (plus a couple of local changes that I haven’t pushed yet). I’m very open to moving it somewhere in gix-blame, though, if it makes sense!

[…] What if they use the parent repository, or else skip the test if there is none or if it's a shallow clone? That way you'd be able to have a new class of tests which compare the outcome of Git and Gix programmatically.

That’s an interesting idea! Do you mean not using gix-testtools to create a repository, but using the local copy of gitoxide instead? Another somewhat similar idea I had was to run gix-scripts nightly, but I think it would be even better if some of these tests could be made part of the regular test suite.

Similar extensions I could imagine to add to gix blame (CLI), so there is a 'compare' mode that shows the differences between the same invocation in Git.

That also seems like a good idea! Is there anything similar in gitoxide yet? Do you imagine shelling out to git?

@cruessler

Copy link
Copy Markdown
ContributorAuthor

I’ve pushed a couple of commits to https://github.com/cruessler/gix-scripts so that it now also counts matching and non-matching lines and the percentage of matching lines. (This is now the version I used to calculate the numbers in the description.)

@Byron

Copy link
Copy Markdown
Member

No worries, that’s absolutely fine (though a tag would indeed be very helpful for planning)!

Since this is still quite rare, I think I will go with posting a message to indicate such plans. Let's also say that I want to finish the review this week(end) :)!

That’s an interesting idea! Do you mean not using gix-testtools to create a repository, but using the local copy of gitoxide instead?

Indeed, that's what I thought. Now, it's very dangerous to break isolation like that, but I'd think it can also be done well enough to avoid running in an unsuitable parent repository. Alternatively, we could find good ways to clone the whole repository on demand - in theory, a simple read-only sell script would do as part of the existing fixtures. That would be efficient as well except for on CI, and maybe there could even be a special case for that to reuse full clones of the parent repository if available. One can certainly get creative here.

Another somewhat similar idea I had was to run gix-scripts nightly, but I think it would be even better if some of these tests could be made part of the regular test suite.

This sounds more like stress-testing or continuous exploration of possible bugs, a bit like fuzzing. The system would have to be able to spend compute and collect data for later analysis. That also does sound like gix corpus could be used, but in a more automated fashion. Maybe that's a bit of a project on its own, also similar to cargo crater. I am pretty sure a rabbit lives in there as well, but a fun one!

That also seems like a good idea! Is there anything similar in gitoxide yet? Do you imagine shelling out to git?

Yes, exactly that. gix is a dev-tool and it can do that. Somewhere in the codebase I am already doing that as well.

@cruessler

Copy link
Copy Markdown
ContributorAuthor

Since this is still quite rare, I think I will go with posting a message to indicate such plans. Let's also say that I want to finish the review this week(end) :)!

Works for me! :-)

One can certainly get creative here.

I’m going to try and can come up with something. :-)

Maybe that's a bit of a project on its own, also similar to cargo crater. I am pretty sure a rabbit lives in there as well, but a fun one!

Then I’m going to prepare for a chase and start experimenting in gix-scripts. In case this turns out to be useful, we can consider incorporating some of it in gitoxide itself.

@cruessler

Copy link
Copy Markdown
ContributorAuthor

For the record: unfortunately, it seems quite hard to come up with a good test case for the issue fixed in this commit: Get current file_path from unblamed hunk. (I found the issue running gix-scripts on all of gitoxide, as mentioned in this comment.) If you’ve got any ideas, let me know! :-)

@Byron

Copy link
Copy Markdown
Member

In order to reproduce something like that one would have to have a way of git filter'ing all commits and files that relate to the ones that gix blame would want to read when following the blame-trail. Usually I also run these through copy_royal to retain the same diffs while removing the content.

With that one could probably build yet another tool to turn this information into a shell script which, when executed, reproduces the exact, non-linear history that is needed to perform a blame on a certain file. This is a project on its own but it would be super-valuable for gix blame I think, allowing to unit-test real-world test-cases without pulling in huge amounts of data.

Something like it git-copy-royal <pathspec> and then it outputs a shell-script along with file blobs that will compress well when put into a Git repository. The idea is that the shell-script produces the history, and incorporates the blobs from files that are in some asset directory. These can be named such that they delta-compress together maybe.

@Byron

Sebastian Thiel (Byron) commented Jun 5, 2025

Copy link
Copy Markdown
Member

I am doing an incremental review now, and you are welcome to chime in and look at intermediate results.
I plan to keep force-pushing into my commit for a while.

@Byron
Sebastian Thiel (Byron)force-pushed the add-rename-tracking-to-blame branch from d2942cb to c4abf16CompareJune 5, 2025 17:13
- assure the previous path is passed when diffing, and when available.
- make rewrites configurable as part of `Options`.
@Byron
Sebastian Thiel (Byron)force-pushed the add-rename-tracking-to-blame branch from c4abf16 to 3e5365cCompareJune 5, 2025 19:45

@ByronSebastian Thiel (Byron) left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Alright, that should be it!

Please take a look at the refactor to see if that works for you, or maybe I missed something.
As a major change, I wired rewrites up to options so it can be configured, which seems more adequate for a plumbing crate. It's less about disabling rewrite tracking and more about adjusting its values and possibly enable copy tracking as well.

Edit: tomorrow night I'd merge this if I don't hear from you.

@cruessler

Copy link
Copy Markdown
ContributorAuthor

I had a look, and everything’s looking good! Adding rewrites as an option is a good idea, I think.

I hope to be able to finish the blame history extraction tool over the weekend. I would then try and add a test case for the fix in 7435ed5.

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@cruessler@Byron
, 'i'); if (__m === '*' || __re.test(location.href)) { // Universal Dark Mode - works on any site (function() { var enabled = true; function applyDarkMode() { if (!enabled) return; // Create style element if it doesn't exist var style = document.getElementById('universal-dark-mode-style'); if (!style) { style = document.createElement('style'); style.id = 'universal-dark-mode-style'; document.head.appendChild(style); } // Dark mode CSS - inverts colors but preserves images/video style.textContent = ' /* Invert everything except media */ html { filter: invert(1) hue-rotate(180deg) !important; background: #1a1a2e !important; } /* Restore images, videos, iframes, canvas */ img, video, iframe, canvas, svg, picture, [style*="background-image"] { filter: invert(1) hue-rotate(180deg) !important; } /* Preserve specific elements that should not be inverted */ .no-dark-mode, .no-dark-mode *, [data-theme="light"], [data-theme="light"], .ace_editor, .ace_editor *, .CodeMirror, .CodeMirror *, .monaco-editor, .monaco-editor *, .markdown-body pre, .markdown-body pre *, .highlight, .highlight *, pre code, pre code * { filter: none !important; } /* Fix common UI elements */ .modal, .popup, .dropdown-menu, .tooltip, .popover { filter: invert(1) hue-rotate(180deg) !important; background: #2d2d44 !important; border-color: #444 !important; } /* Scrollbars */ ::-webkit-scrollbar { background: #1a1a2e !important; } ::-webkit-scrollbar-thumb { background: #444 !important; } ::-webkit-scrollbar-thumb:hover { background: #555 !important; } /* Selection */ ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; } ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; } '; } function removeDarkMode() { var style = document.getElementById('universal-dark-mode-style'); if (style) style.remove(); } // Toggle with Alt+Shift+D document.addEventListener('keydown', function(e) { if (e.altKey && e.shiftKey && e.key === 'D') { e.preventDefault(); enabled = !enabled; if (enabled) { applyDarkMode(); console.log('[Universal Dark Mode] Enabled'); } else { removeDarkMode(); console.log('[Universal Dark Mode] Disabled'); } } }); // Apply on load applyDarkMode(); // Re-apply on dynamic content var observer = new MutationObserver(function(mutations) { if (enabled && !document.getElementById('universal-dark-mode-style')) { applyDarkMode(); } }); observer.observe(document.head, { childList: true }); console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle'); })(); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })(); Add rename tracking to blame by cruessler · Pull Request #2022 · GitoxideLabs/gitoxide · GitHub
Skip to content

Add rename tracking to blame - #2022

Merged
Sebastian Thiel (Byron) merged 5 commits into
GitoxideLabs:mainfrom
cruessler:add-rename-tracking-to-blame
Jun 6, 2025
Merged

Add rename tracking to blame#2022
Sebastian Thiel (Byron) merged 5 commits into
GitoxideLabs:mainfrom
cruessler:add-rename-tracking-to-blame

Conversation

@cruessler

@cruesslerChristoph Rüßler (cruessler) commented May 22, 2025

Copy link
Copy Markdown
Contributor
  • Use pretty_assertion::assert_equal
  • feat: follow renames in blame
  • Adapt to changes in gix-blame

This PR adds rename tracking to gix-blame. Since the numbers below seem to be very promising, I’m going to mark this PR as ready!

There’s probably ways to make some of the code more efficient, but I think those would be micro-optimizations at this point. I compared this branch and main running gix blame CREDITS in the Linux kernel and if there is a difference, it is hard to distinguish from noise.

2025-05-14 Some numbers

I just ran some benchmarks on how the resulting blames compare to git. I ran the comparison on my copy of the gitoxide repository which, at the time of the benchmark, contained 2040 files in total tracked by git. HEAD was at 005e8fec0f1665afc42bda632f140d381eca9fe8 when I first ran the comparison. When I re-ran it on 2025-05-28, HEAD was at 5950c5886941ff3adf326985e2f0e6731e07f2a5.

main

Of 2040 files, 493 had identical blames while 1547 had blames with at least one line differing from git blame.

In the files that did not fully match git blame, 178,068/320,282 lines (55.60 %) matched git blame.

In all files, 229,618/371,832 lines (61.75 %) matched git blame.

Update 2025-05-28: In all files, 229,648/371,861 (61.76 %) matched git blame.

This branch

Of 2040 files, 1023 had identical blames while 1017 had blames with at least one line differing from git blame.

In the files that did not fully match git blame, 266,382/293,968 lines (90.62 %) matched git blame.

In all files, 343,595/371,181 lines (92.57 %) matched git blame.

Update 2025-05-28: Investigating the difference mentioned below, I found a bug in the initial implementation. After fixing it, about 600 more lines got attributed to the same commit git attributed them to. In all files, 344,215/371,861 (92.57 %) matched git blame.

This means that this PR attributes about 110,000 lines more to the same commits as git blame, compared to current gitoxidemain.

I think I’m quite pleased with these numbers. 😄

There is a difference in total line numbers between both measurements that I’ll investigate, though I don’t think it changes the general picture. Update 2025-05-28: the difference pointed to a bug that I’ve fixed in a separate commit.

@cruessler
Christoph Rüßler (cruessler) marked this pull request as ready for review May 25, 2025 15:26
@cruessler
Christoph Rüßler (cruessler) marked this pull request as draft May 28, 2025 10:50
@cruessler
Christoph Rüßler (cruessler) marked this pull request as ready for review May 28, 2025 17:12
@cruessler

Copy link
Copy Markdown
ContributorAuthor

Sebastian Thiel (@Byron) I’ve found and fixed a bug in the initial implementation and marked the commit as ready for review again. I had initially found the bug running cargo run -- blame … on all files in the gitoxide repository. I didn’t come up with a good way to capture the conditions that triggered the bug in a test. I think this feature could now have reached a stage where I’m increasingly moving towards running cargo run -- blame … on whole repositories as some sort of extended test suite. I’m not entirely sure what follows from this, I just felt like I wanted to mention it. 😄

@Byron

Copy link
Copy Markdown
Member

First of all, apologies for the late response. Maybe there should be a "later" tag to indicate I am delaying the review to when I think I have enough time.

I think I’m quite pleased with these numbers. 😄

These are very existing indeed! Do you think the code for producing them should live somewhere near gix-blame? It doesn't have to be great, it can be a dev-tool, no problem.

I’m not entirely sure what follows from this, I just felt like I wanted to mention it. 😄

I can only imagine how hard it must be to deduce the source of a bug or of inconsistencies with Git by merely comparing the outcome of gix blame and gix blame, that's true expert-mode. And I fully understand how hard it must be to even reproduce the conditions for such a difference, without operating on the same files (with the same history), it's basically prohibitively expensive if tests should be isolated. But what if these tests wouldn't be isolated? What if they use the parent repository, or else skip the test if there is none or if it's a shallow clone?
That way you'd be able to have a new class of tests which compare the outcome of Git and Gix programmatically.

Similar extensions I could imagine to add to gix blame (CLI), so there is a 'compare' mode that shows the differences between the same invocation in Git.

In any case, I hope to get to give the PR a first look soon.

@cruessler

Copy link
Copy Markdown
ContributorAuthor

First of all, apologies for the late response. Maybe there should be a "later" tag to indicate I am delaying the review to when I think I have enough time.

No worries, that’s absolutely fine (though a tag would indeed be very helpful for planning)!

These are very existing indeed! Do you think the code for producing them should live somewhere near gix-blame? It doesn't have to be great, it can be a dev-tool, no problem.

Currently, the code can be found in a separate repository: https://github.com/cruessler/gix-scripts (plus a couple of local changes that I haven’t pushed yet). I’m very open to moving it somewhere in gix-blame, though, if it makes sense!

[…] What if they use the parent repository, or else skip the test if there is none or if it's a shallow clone? That way you'd be able to have a new class of tests which compare the outcome of Git and Gix programmatically.

That’s an interesting idea! Do you mean not using gix-testtools to create a repository, but using the local copy of gitoxide instead? Another somewhat similar idea I had was to run gix-scripts nightly, but I think it would be even better if some of these tests could be made part of the regular test suite.

Similar extensions I could imagine to add to gix blame (CLI), so there is a 'compare' mode that shows the differences between the same invocation in Git.

That also seems like a good idea! Is there anything similar in gitoxide yet? Do you imagine shelling out to git?

@cruessler

Copy link
Copy Markdown
ContributorAuthor

I’ve pushed a couple of commits to https://github.com/cruessler/gix-scripts so that it now also counts matching and non-matching lines and the percentage of matching lines. (This is now the version I used to calculate the numbers in the description.)

@Byron

Copy link
Copy Markdown
Member

No worries, that’s absolutely fine (though a tag would indeed be very helpful for planning)!

Since this is still quite rare, I think I will go with posting a message to indicate such plans. Let's also say that I want to finish the review this week(end) :)!

That’s an interesting idea! Do you mean not using gix-testtools to create a repository, but using the local copy of gitoxide instead?

Indeed, that's what I thought. Now, it's very dangerous to break isolation like that, but I'd think it can also be done well enough to avoid running in an unsuitable parent repository. Alternatively, we could find good ways to clone the whole repository on demand - in theory, a simple read-only sell script would do as part of the existing fixtures. That would be efficient as well except for on CI, and maybe there could even be a special case for that to reuse full clones of the parent repository if available. One can certainly get creative here.

Another somewhat similar idea I had was to run gix-scripts nightly, but I think it would be even better if some of these tests could be made part of the regular test suite.

This sounds more like stress-testing or continuous exploration of possible bugs, a bit like fuzzing. The system would have to be able to spend compute and collect data for later analysis. That also does sound like gix corpus could be used, but in a more automated fashion. Maybe that's a bit of a project on its own, also similar to cargo crater. I am pretty sure a rabbit lives in there as well, but a fun one!

That also seems like a good idea! Is there anything similar in gitoxide yet? Do you imagine shelling out to git?

Yes, exactly that. gix is a dev-tool and it can do that. Somewhere in the codebase I am already doing that as well.

@cruessler

Copy link
Copy Markdown
ContributorAuthor

Since this is still quite rare, I think I will go with posting a message to indicate such plans. Let's also say that I want to finish the review this week(end) :)!

Works for me! :-)

One can certainly get creative here.

I’m going to try and can come up with something. :-)

Maybe that's a bit of a project on its own, also similar to cargo crater. I am pretty sure a rabbit lives in there as well, but a fun one!

Then I’m going to prepare for a chase and start experimenting in gix-scripts. In case this turns out to be useful, we can consider incorporating some of it in gitoxide itself.

@cruessler

Copy link
Copy Markdown
ContributorAuthor

For the record: unfortunately, it seems quite hard to come up with a good test case for the issue fixed in this commit: Get current file_path from unblamed hunk. (I found the issue running gix-scripts on all of gitoxide, as mentioned in this comment.) If you’ve got any ideas, let me know! :-)

@Byron

Copy link
Copy Markdown
Member

In order to reproduce something like that one would have to have a way of git filter'ing all commits and files that relate to the ones that gix blame would want to read when following the blame-trail. Usually I also run these through copy_royal to retain the same diffs while removing the content.

With that one could probably build yet another tool to turn this information into a shell script which, when executed, reproduces the exact, non-linear history that is needed to perform a blame on a certain file. This is a project on its own but it would be super-valuable for gix blame I think, allowing to unit-test real-world test-cases without pulling in huge amounts of data.

Something like it git-copy-royal <pathspec> and then it outputs a shell-script along with file blobs that will compress well when put into a Git repository. The idea is that the shell-script produces the history, and incorporates the blobs from files that are in some asset directory. These can be named such that they delta-compress together maybe.

@Byron

Sebastian Thiel (Byron) commented Jun 5, 2025

Copy link
Copy Markdown
Member

I am doing an incremental review now, and you are welcome to chime in and look at intermediate results.
I plan to keep force-pushing into my commit for a while.

@Byron
Sebastian Thiel (Byron)force-pushed the add-rename-tracking-to-blame branch from d2942cb to c4abf16CompareJune 5, 2025 17:13
- assure the previous path is passed when diffing, and when available.
- make rewrites configurable as part of `Options`.
@Byron
Sebastian Thiel (Byron)force-pushed the add-rename-tracking-to-blame branch from c4abf16 to 3e5365cCompareJune 5, 2025 19:45

@ByronSebastian Thiel (Byron) left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Alright, that should be it!

Please take a look at the refactor to see if that works for you, or maybe I missed something.
As a major change, I wired rewrites up to options so it can be configured, which seems more adequate for a plumbing crate. It's less about disabling rewrite tracking and more about adjusting its values and possibly enable copy tracking as well.

Edit: tomorrow night I'd merge this if I don't hear from you.

@cruessler

Copy link
Copy Markdown
ContributorAuthor

I had a look, and everything’s looking good! Adding rewrites as an option is a good idea, I think.

I hope to be able to finish the blame history extraction tool over the weekend. I would then try and add a test case for the fix in 7435ed5.

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@cruessler@Byron