mirror of
https://github.com/jesseduffield/lazygit.git
synced 2026-09-10 07:36:27 -04:00
PipeCommands ran every command in its own goroutine, each doing Start/read-stderr/Wait, with nothing ordering one goroutine's Start against another's Wait. That ordering matters: StdoutPipe registers the parent's read end in cmd.parentIOPipes, and Cmd.Wait closes those descriptors when it returns. The next command's Stdin is that very *os.File, and exec passes a user-supplied *os.File through untouched, so Start hands the child whatever the fd happens to be at that moment. If the producer finished and got reaped before the consumer's goroutine reached Start, that fd was already closed, File.Fd() returned -1, and the child was started with fd 0 closed -- reading nothing at all. The only caller is the pre-2.35 fallback in SaveStagedChanges, which pipes `git stash show -p` into `git apply -R`. Losing that race left git apply with an empty patch, so it failed with "unrecognized input", the following `git stash drop` never ran, and the user was left with a stray stash entry. This turned up as a flaky stash/stash_staged on the git 2.32.0 CI job; the newer-git jobs take the `git stash push --staged` path and never reach this code. Starting every command up front removes the race, and collecting stderr into buffers lets exec's own copying goroutines do the work. That also fixes two lesser problems in the same function: finalErrors was appended to from several goroutines without synchronization, and a failed Start was only logged, so a pipeline that never ran reported success. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|---|---|---|
| .. | ||
| app | ||
| cheatsheet | ||
| commands | ||
| common | ||
| config | ||
| constants | ||
| env | ||
| fakes | ||
| gocui | ||
| gui | ||
| i18n | ||
| integration | ||
| jsonschema | ||
| logs | ||
| snake | ||
| tasks | ||
| theme | ||
| updates | ||
| utils | ||