You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The take-left and take-right arrows in the file diff view rebuild the entire destination file from the DiffResult that was cached when the comparison ran, then write it with File.WriteAllText:
The prologue and epilogue lines come from diff.PiecesOld / diff.PiecesNew. Nothing re-reads the file or checks that it still matches that snapshot. The comparison is recomputed only on selection or refresh (CompareSiblingsAsync via SwitchPage/RefreshPage), and after a take on that same file (RefreshFileDiff). In normal use the snapshot goes stale:
the user keeps editing the file in an IDE while the diff view is open;
Pull or Pull All fast-forwards the working tree underneath the view;
a propagation, or a take in another sibling's comparison, rewrites the file.
The next arrow click silently restores the old content of every line outside the hunk.
Evidence
A probe ran the exact ShowDiffRight take logic:
A = one\ntwo\nthree\nfour\n and B = one\nTWO\nthree\nfour\n are diffed.
The user then appends five (new work) to A on disk.
B's hunk is taken into A.
Result on disk: one\nTWO\nthree\nfour\n. The new line is gone, and the only visible sign is that git no longer shows the change.
This is separate from #445 (line endings and BOM of the file that was read). Here the lost data is content that changed after the read.
Suggested fix
On take, re-read both files and compare them with the text the cached diff was built from. Keep the source strings, or a hash of them, next to the DiffResult. If they differ, recompute with DiffSingleFile, refuse the take, and log "file changed on disk; diff refreshed".
Alternatively, apply the hunk to a freshly read copy, and refuse if the hunk's context lines no longer match.
If the destination file is edited after the diff was shown, clicking a take arrow never discards the edit. The take is either refused with a log line or applied to the current content.
What's wrong
The take-left and take-right arrows in the file diff view rebuild the entire destination file from the
DiffResultthat was cached when the comparison ran, then write it withFile.WriteAllText:ShowDiffLeft:ProjectDirector/ProjectDirector.cs:1645-1652ShowDiffRight::1740-1747The prologue and epilogue lines come from
diff.PiecesOld/diff.PiecesNew. Nothing re-reads the file or checks that it still matches that snapshot. The comparison is recomputed only on selection or refresh (CompareSiblingsAsyncviaSwitchPage/RefreshPage), and after a take on that same file (RefreshFileDiff). In normal use the snapshot goes stale:The next arrow click silently restores the old content of every line outside the hunk.
Evidence
A probe ran the exact
ShowDiffRighttake logic:one\ntwo\nthree\nfour\nand B =one\nTWO\nthree\nfour\nare diffed.five (new work)to A on disk.Result on disk:
one\nTWO\nthree\nfour\n. The new line is gone, and the only visible sign is that git no longer shows the change.This is separate from #445 (line endings and BOM of the file that was read). Here the lost data is content that changed after the read.
Suggested fix
DiffResult. If they differ, recompute withDiffSingleFile, refuse the take, and log "file changed on disk; diff refreshed".Acceptance criteria
If the destination file is edited after the diff was shown, clicking a take arrow never discards the edit. The take is either refused with a log line or applied to the current content.