Skip to content

Taking a diff hunk rewrites the whole file from the cached comparison, discarding edits or pulls made since the repo was selected #452

Description

@matt-edmondson

What's wrong

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:

  • ShowDiffLeft: ProjectDirector/ProjectDirector.cs:1645-1652
  • ShowDiffRight: :1740-1747

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:

  1. A = one\ntwo\nthree\nfour\n and B = one\nTWO\nthree\nfour\n are diffed.
  2. The user then appends five (new work) to A on disk.
  3. 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.
  • Extract the apply-hunk logic into a static helper so this and Taking one diff hunk rewrites every line ending in the file and strips its UTF-8 BOM #445 can be unit-tested.

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.

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions