Repository navigation
Conversation
…e revisions difft reports only the new path of a renamed file, so the old content was looked up at the new path and came back empty. With edits, the stale highlights on the empty lines crashed rendering with an out-of-range end_col. The rename map is now built before content lookup and supplies the old path, while the status difft reported is kept so rows are built as a change. The rename map also passed a single revision straight to `git diff --name-status`, which compares it against the working tree. It now resolves the revision the same way as the content diff (`rev^..rev`).
…e revisions Explain in the rename map why a single revision is resolved as `rev^..rev`: the map decides where a renamed file's old content is read from, so it must compare the same two sides as the content diff.
git --numstat keys a rename as `old => new` (or `dir/{old => new}`), so the
lookup by the new path missed and renamed files showed +0/-0. The numstat
parser now keys renames by their new path.
A pure rename comes from difft as unchanged with no line alignment, so it
rendered as an empty view. Identical content without alignment is now
aligned line by line and shown, with no hunks.
jj hands difft the two revisions as whole directory trees, so a renamed file arrives as a deletion of the old path and a creation of the new one, and its contents are never compared. The view showed the renamed file as entirely added, with an empty old side. For each rename that `jj diff --summary` reports, the old and new contents are now diffed by difft directly, as a pair of files named like the new path so the language is detected the same way. When that fails, the entry is kept as jj reported it. git diffs are unaffected.
The tests build real git and jj repositories (jj both colocated with git and not) and check the native library's output for renames: single revisions, ranges, staged and working-copy changes, moves within and across directories, several renames at once, and that unrelated deletions and additions or copies are not paired. Each suite is skipped when the native library, difft or the VCS binary is missing. The test init now adds the plugin to the runtime path by its absolute path. With a relative path, the library loader linked the built library through a broken relative symlink and silently fell back to a downloaded library.
Author
|
Disclaimer: shamelessly vibecoded. Manually tested with git only. I’d appreciate it if you could let me know whether you accept AI-assisted contributions, including bug fixes and/or new features. I’m already making some changes for my own use on my fork, but I’d be happy to prepare them as contributions to the official repository as well (possible followup jrosiek#2) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Renamed files were not shown correctly, for both git and jj:
empty. Rendering then crashed with an out-of-range
end_col, because thehighlights still pointed into lines that were never loaded.
:Difft <rev>): rename detection compared therevision with the working tree instead of with its parent. It missed the
revision's own renames and picked up unrelated renames from the working tree.
--numstatreports a rename asold => new(ordir/{old => new}), so the lookup by the new path failed and renamed filesshowed +0/-0.
with no line alignment, so the view was empty.
jj diff --tool difftgives difft the two revisions aswhole directory trees. A renamed file reaches difft as a deletion of the old
path and a creation of the new one, so its contents were never compared. The
file showed as entirely added, with an empty old side.
Changes
old content is read from its old path. For a single revision, the rename map
now uses the same
rev^..revrange as the content diff.--numstatentries for renames are keyed by their new path.pure rename shows its content, with no hunks.
jj diff --summaryreports is diffed by running diffton the old and new contents directly. The two temporary files keep the new
file's name, so difft detects the same language. If that run fails, the entry
is kept as jj reported it.
tests/minimal_init.luanow adds the plugin to the runtime path by itsabsolute path. With a relative path, the library loader linked the built
library through a broken relative symlink and silently fell back to a
previously downloaded library.
Testing
--numstatrenames, the jj summary braceforms (
{a => b},dir/{a => b},{a => sub/a}), ignoring copies, rename-maparguments for a single revision, aligning a pure rename, and pairing jj
renames. The tests that run difft skip when it is not installed.
tests/rename_spec.luaruns the native library against real scratchrepositories:
directories, a deletion next to an unrelated addition, and a working-tree
rename that must not leak into a commit diff.
several renames in one revision, highlighting only the edited line, language
detection, and copies kept as additions.
missing.
main, 26 of the 32end-to-end cases fail. The 6 that pass are guards that unrelated files are
not paired.
Known limitations
colocated with git. This is unchanged.
Cin--summary) are still shown as plain additions.🤖 Generated with Claude Code