Skip to content

fix(diff): compare files byte-accurately instead of by normalized lines - #3471

Open
Hydr0gen19 wants to merge 1 commit into
rtk-ai:developfrom
Hydr0gen19:fix/issue-3469
Open

fix(diff): compare files byte-accurately instead of by normalized lines#3471
Hydr0gen19 wants to merge 1 commit into
rtk-ai:developfrom
Hydr0gen19:fix/issue-3469

Conversation

@Hydr0gen19

Copy link
Copy Markdown

Summary

  • rtk diff a b compared files with str::lines(), which drops the line terminator. CRLF vs LF and a missing final newline produced an empty change list, so byte-different files were reported as [ok] Files are identical and exited 0. Comparison is now byte-accurate: only strictly equal contents exit 0.
  • When the bytes differ but every line matches, the terminators are the only possible cause, so the output says that explicitly instead of claiming the files are identical.
  • Added --ignore-whitespace to keep the lenient comparison available on request (trims trailing whitespace, ignores line endings and the final newline).

Fixes #3469

Why this matters beyond rtk diff

src/discover/rules.rs rewrites plain diff <args> to rtk diff, so an agent
running diff a b got the false-equal answer and the 0 exit code without ever
asking for rtk. That is exactly the case the issue describes as breaking
diff-based equality checks.

Behaviour

Input Before After
identical bytes [ok] Files are identical, exit 0 unchanged
CRLF vs LF [ok] Files are identical, exit 0 identical line content; files differ in line endings or the final newline, exit 1
final newline present vs absent [ok] Files are identical, exit 0 same as above, exit 1
line content differs change list, exit 1 unchanged
--ignore-whitespace, whitespace-only difference n/a [ok] Files are identical (ignoring whitespace), exit 0

Trailing-space differences were already reported as changes before this PR; they
still are, and --ignore-whitespace now suppresses them.

Note: for very small files guard::never_worse still prefers the raw content
over the condensed message, as it does for every other rtk diff output. The
exit code — the part scripts rely on — is correct in every case.

On the added flag

--ignore-whitespace is the one part of this PR that is not strictly the bug
fix. It is here because the triage comment on the issue asks for the lenient
comparison to stay available behind an explicit flag, and without it this change
removes a behaviour and leaves nothing in its place. It is about ten isolated
lines — happy to drop it and keep the fix minimal if you would rather.

It deliberately has no -w short form: in GNU diff, -w means "ignore all
white space", which is a broader thing than what this does.

Test plan

  • cargo fmt --all --check && cargo clippy --all-targets && cargo test
    (clippy clean; see note below on two pre-existing flaky tests)
  • Unit tests added in src/cmds/git/diff_cmd.rs: CRLF vs LF, missing final
    newline, trailing space, byte-identical CRLF files, and both
    --ignore-whitespace paths. They fail on develop and pass here.
  • Manual testing:
$ printf 'alpha\r\nbeta\r\n' > crlf.txt; printf 'alpha\nbeta\n' > lf.txt

# before
$ rtk diff crlf.txt lf.txt
[ok] Files are identical
$ echo $?
0

# after
$ rtk diff crlf.txt lf.txt
crlf.txt → lf.txt
   identical line content; files differ in line endings or the final newline
$ echo $?
1

$ rtk diff --ignore-whitespace crlf.txt lf.txt
[ok] Files are identical (ignoring whitespace)
$ echo $?
0

Two tests (core::tracking::tests::test_timed_execution_* and
cmds::dotnet::dotnet_trx::tests::test_parse_trx_files_in_dir_since_ignores_older_files)
fail intermittently on cargo test --all in my environment and pass when run on
their own. They are unrelated to this change — different runs fail on different
tests, and nothing here touches tracking or dotnet.

Docs

docs/usage/FEATURES.md — added the --ignore-whitespace option and a note on
the byte-accurate comparison and exit codes.

`rtk diff a b` split both files with `str::lines()`, which drops the line
terminator. CRLF vs LF and a missing final newline therefore produced an
empty change list, so byte-different files were reported as
"[ok] Files are identical" and exited 0.

Since the `diff` rewrite rule routes plain `diff a b` through rtk, this
made rtk unusable as an equality oracle in scripts and agent workflows.

Byte equality is now the only path to exit 0. When the contents differ
but every line matches, the terminators are the only possible cause and
the output says so instead of claiming the files are identical.

`--ignore-whitespace` keeps the lenient comparison available: it trims
trailing whitespace and ignores line endings and the final newline.
Sign up for free to 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.

1 participant