From e877a2a54634e0f3cf7d57cc95a1f8a486ae476f Mon Sep 17 00:00:00 2001 From: Sina Hinderks Date: Sat, 20 Dec 2025 02:40:15 +0100 Subject: [PATCH] fix: stage/discard/unstage hunk There is a regression bug regarding staging, discarding, and unstaging hunks. Depending on the data, these actions may be ignored or only partially executed. The following script generates a repository in the current directory (named after the current directory) with four examples. Save the script as `create-hunk-regression.sh`, make it executable with `chmod +x create-hunk-regression.sh`, and start it with `./create-hunk-regression.sh`. (Tested on Linux, should also work on Windows.) ```bash #!/usr/bin/env bash set -e dir=$(basename $(pwd)) rm -rf "$dir" git init -b main "$dir" && cd "$dir" echo -n '1n2n3n4n' | tr 'rn' '\r\n' > cannot-stage-hunks.txt echo -n '2rn3rn' | tr 'rn' '\r\n' > partially-stages-hunks.txt echo -n 'test1rnrnrnrntest3rn' | tr 'rn' '\r\n' > partially-stages-or-discards-hunk.txt echo -n '1rn2rn3rn4rn' | tr 'rn' '\r\n' > cannot-unstage-hunks.txt git add . git commit -m 'initial commit' echo -n '1rn2n3n4rn' | tr 'rn' '\r\n' > cannot-stage-hunks.txt echo -n '1rn2rn3rn4rn' | tr 'rn' '\r\n' > partially-stages-hunks.txt echo -n 'test1rnrntest2rnrntest3rn' | tr 'rn' '\r\n' > partially-stages-or-discards-hunk.txt echo -n '1n2rn3rn4n' | tr 'rn' '\r\n' > cannot-unstage-hunks.txt git add cannot-unstage-hunks.txt ``` For the examples to fully work you should configure Git/SourceGit the following way: - set `core.autocrlf` to `false` - do not enable `--ignore-cr-at-eol` in diff - do not ignore wwhitespace changes This regression was introduced in commit 5c9d96, where breaking up the diff into lines was changed from explicitly doing it to using the stream function `ReadLineAsync`. Whereas the explicit code handled CR and LF correctly, the stream function handles CR, CR/LF and LF the same way, so that for Windows newlines (CR/LF) the CR will be lost. The fix for this regression is going back to the explicit code and ignoring `ReadLineAsync` for reading diffs. This should fix at least partially issues #1950 and #1995. --- src/Commands/Diff.cs | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/Commands/Diff.cs b/src/Commands/Diff.cs index 3fdc62259..680aff63d 100644 --- a/src/Commands/Diff.cs +++ b/src/Commands/Diff.cs @@ -46,9 +46,22 @@ public Diff(string repo, Models.DiffOption opt, int unified, bool ignoreWhitespa proc.StartInfo = CreateGitStartInfo(true); proc.Start(); - while (await proc.StandardOutput.ReadLineAsync().ConfigureAwait(false) is { } line) + var text = await proc.StandardOutput.ReadToEndAsync().ConfigureAwait(false); + + var start = 0; + var end = text.IndexOf('\n', start); + while (end > 0) + { + var line = text[start..end]; ParseLine(line); + start = end + 1; + end = text.IndexOf('\n', start); + } + + if (start < text.Length) + ParseLine(text[start..]); + await proc.WaitForExitAsync().ConfigureAwait(false); } catch