mirror of
https://github.com/jesseduffield/lazygit.git
synced 2026-08-24 02:24:25 -05:00
At the end of a diff against the worktree, git re-reads and refreshes
the index and writes it back if it found stale stat information
(diff.autoRefreshIndex, on by default). It holds index.lock for the
whole refresh; GIT_OPTIONAL_LOCKS does not cover this lock, and the
window scales with the size of the repository (~150ms for a 6k-file
repository with a warm stat cache).
On Windows, a pty task that is stopped because the user moved on
terminates its git process at an arbitrary point: tearing down the
pseudoconsole delivers CTRL_CLOSE_EVENT, which git leaves to the
default handler, which simply calls ExitProcess. If that lands inside
the refresh, a stale index.lock is left behind and the next git
command chokes on it. This is the same problem that 98801da106 fixed
by no longer killing git processes; the ConPTY support added in 0.63
reintroduced it through the close event.
Disable the automatic refresh for pty-rendered commands. They can
afford it: the refresh only persists refreshed stat information, and
lazygit's foreground git status refreshes -- which never run in a pty
and are never killed -- already write that back on every user action
and on terminal focus-in. The cost is that while the on-disk stat
cache is stale, an external differ is invoked even for files whose
stat information changed but whose content didn't, showing them as
empty diffs; this heals with the next foreground refresh, which also
re-renders the view.
Unix keeps the refresh: a stopped pty child gets SIGTERM there, and
git's signal handlers remove its lock files, so the lock window is
harmless. The rawGit renderer keeps it too: its tasks don't run in a
pty and are never killed on Windows -- they either run to completion
or die on a broken pipe mid-output, before the refresh begins.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
30 lines
939 B
Go
30 lines
939 B
Go
package gui
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
)
|
|
|
|
func TestWithPtyGitConfig(t *testing.T) {
|
|
args := []string{"git", "-C", "/repo", "diff", "--color=always"}
|
|
|
|
assert.Equal(t,
|
|
[]string{"git", "-c", "diff.autoRefreshIndex=false", "-C", "/repo", "diff", "--color=always"},
|
|
withPtyGitConfig(args, "windows"))
|
|
|
|
assert.Equal(t, args, withPtyGitConfig(args, "linux"))
|
|
assert.Equal(t, args, withPtyGitConfig(args, "darwin"))
|
|
|
|
// A user-configured command that wraps git in a shell must not have git
|
|
// flags injected into it.
|
|
shellArgs := []string{"sh", "-c", "git log --graph {{branchName}} -- | sed -e s/x/y/"}
|
|
assert.Equal(t, shellArgs, withPtyGitConfig(shellArgs, "windows"))
|
|
|
|
// The guard recognizes git regardless of case and extension.
|
|
exeArgs := []string{"GIT.EXE", "diff"}
|
|
assert.Equal(t,
|
|
[]string{"GIT.EXE", "-c", "diff.autoRefreshIndex=false", "diff"},
|
|
withPtyGitConfig(exeArgs, "windows"))
|
|
}
|