What's wrong
The similar-repo comparison diffs every tracked path that two repositories share as text, and never checks whether the file is binary.
DiffRepos (ProjectDirector/ProjectDirector.cs ~L1392-1397) reads each matched file through ReadFileOrEmpty, which calls File.ReadAllText (~L1411), and then runs Differ.Instance.CreateLineDiffs on the result.
ShowComparedRepo (~L1544-1548) lists every file whose diff has changed lines. A binary that differs between the two repos, such as icon.png or a vendored .dll, is listed with nonsense line counts, and clicking it opens the side-by-side view with hunk arrows.
- The hunk arrows in
ShowDiffLeft and ShowDiffRight rebuild the file from diff.PiecesOld/diff.PiecesNew, joined with Environment.NewLine, and write it with File.WriteAllText (~L1651, ~L1746).
File.ReadAllText decodes as UTF-8, so every invalid byte sequence becomes U+FFFD, and File.WriteAllText writes it back as EF BF BD. Joining with Environment.NewLine also rewrites every 0x0A/0x0D byte. What gets written is neither the source binary, nor the destination binary, nor the selected hunk. It is corrupted, including the "unchanged" bytes around the hunk.
Failure scenario
- Two sibling repositories both track
icon.png, and the images differ.
- Select repo A, open the comparison with repo B, and click
icon.png in "Similar Files".
- Click any hunk arrow.
icon.png in the target repo is overwritten with mangled bytes and no longer opens as an image. Nothing warns the user, and the app's Commit button stages it with add --all.
Large binaries, such as LFS assets, are also fully read and line-diffed against every sibling on each selection, which is wasted work.
Suggested fix
- In
DiffRepos, classify each matched path as binary before diffing. Git's heuristic is a NUL byte in the first 8000 bytes; git check-attr / git diff --no-index --numstat also work. Compare a binary path by bytes or hash (identical vs differs), and don't build a line diff for it.
- In
ShowComparedRepo, mark binary entries and offer no per-hunk arrows for them. Copying the whole file is the only sensible action for a binary.
- Optionally compare files above a size cap by hash instead of line-diffing them.
Acceptance criteria
- A differing binary tracked by both repos never shows hunk-take arrows.
- No code path calls
File.WriteAllText on a file detected as binary.
- A test runs the diff on two repos whose shared
.png differs and asserts that no line diff with hunks is produced for it.
What's wrong
The similar-repo comparison diffs every tracked path that two repositories share as text, and never checks whether the file is binary.
DiffRepos(ProjectDirector/ProjectDirector.cs~L1392-1397) reads each matched file throughReadFileOrEmpty, which callsFile.ReadAllText(~L1411), and then runsDiffer.Instance.CreateLineDiffson the result.ShowComparedRepo(~L1544-1548) lists every file whose diff has changed lines. A binary that differs between the two repos, such asicon.pngor a vendored.dll, is listed with nonsense line counts, and clicking it opens the side-by-side view with hunk arrows.ShowDiffLeftandShowDiffRightrebuild the file fromdiff.PiecesOld/diff.PiecesNew, joined withEnvironment.NewLine, and write it withFile.WriteAllText(~L1651, ~L1746).File.ReadAllTextdecodes as UTF-8, so every invalid byte sequence becomes U+FFFD, andFile.WriteAllTextwrites it back asEF BF BD. Joining withEnvironment.NewLinealso rewrites every0x0A/0x0Dbyte. What gets written is neither the source binary, nor the destination binary, nor the selected hunk. It is corrupted, including the "unchanged" bytes around the hunk.Failure scenario
icon.png, and the images differ.icon.pngin "Similar Files".icon.pngin the target repo is overwritten with mangled bytes and no longer opens as an image. Nothing warns the user, and the app's Commit button stages it withadd --all.Large binaries, such as LFS assets, are also fully read and line-diffed against every sibling on each selection, which is wasted work.
Suggested fix
DiffRepos, classify each matched path as binary before diffing. Git's heuristic is a NUL byte in the first 8000 bytes;git check-attr/git diff --no-index --numstatalso work. Compare a binary path by bytes or hash (identical vs differs), and don't build a line diff for it.ShowComparedRepo, mark binary entries and offer no per-hunk arrows for them. Copying the whole file is the only sensible action for a binary.Acceptance criteria
File.WriteAllTexton a file detected as binary..pngdiffers and asserts that no line diff with hunks is produced for it.