Skip to content

Prevent stale index.lock files from diffs rendered through a pty on Windows - #5888

Open
stefanhaller wants to merge 3 commits into
masterfrom
prevent-stale-index-lock-windows
Open

Prevent stale index.lock files from diffs rendered through a pty on Windows#5888
stefanhaller wants to merge 3 commits into
masterfrom
prevent-stale-index-lock-windows

Conversation

@stefanhaller

Copy link
Copy Markdown
Collaborator

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 98801da 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.

…indows

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 98801da 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>
@stefanhaller stefanhaller added the bug Something isn't working label Aug 3, 2026
stefanhaller and others added 2 commits August 3, 2026 19:27
…ty on Windows

Pty commands are not always direct git invocations: user-configured
commands like branchLogCmd can be arbitrary command lines, e.g.
wrapping git in 'sh -c' to pipe the log through sed. Injecting git
flags after argv[0] of such a command corrupts it (the shell tries to
run the config value as its -c script). Only inject into direct git
invocations; the wrapped commands are log commands, which never take
the index lock, so the protection isn't needed there.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ty on Windows

Re-wrap the doc comment; the previous fixup left ragged line breaks.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant