Skip to content

Avoid GVFS command locks for read-only Git operations - #2138

Open
Tyrie Vella (tyrielv) wants to merge 1 commit into
microsoft:masterfrom
tyrielv:tyrielv/read-only-command-locks
Open

Tyrie Vella (tyrielv) wants to merge 1 commit into
microsoft:masterfrom
tyrielv:tyrielv/read-only-command-locks

Conversation

@tyrielv

@tyrielv Tyrie Vella (tyrielv) commented Oct 19, 2026 •

Copy link
Copy Markdown
Contributor

Problem and Context

The command hook takes the global GVFS lock for every worktree subcommand, including the read-only worktree list command. During that lock, GVFS rejects new ordinary-file placeholders with FileNotFound. An unrelated process can therefore fail to open a tracked file that exists in the projection.

Several other Git commands also take this lock even though they do not change index membership or tracked working-tree content. Long commands can extend the period in which unrelated first opens fail.

Like blame, default annotate reads working-tree files. This change does not serialize those reads with concurrent worktree mutations. The exclusion also lets default annotate create its own file placeholders.

Changes

  • Exempt worktree list, including porcelain and NUL-delimited output. Keep locks for mutating and unknown worktree subcommands.
  • Add audited exclusions for annotate, check-ref-format, cherry, count-objects, ls-remote, range-diff, shortlog, show-branch, verify-commit, verify-pack, and verify-tag.
  • Keep conservative locks for describe, whose --dirty and --broken modes can write the index. Preserve the existing lock classification for index mutators and arbitrary-command dispatchers.
  • Move the existing hook policy into a partial source file that the unit project also compiles. Add unit tests for both hook phases, command spellings, worktree options, and retained lock cases.
  • Add a deterministic functional test that pauses the post-command chain before GVFS can release an acquired lock, and opens an unmaterialized file from another process during that pause.
  • Add functional tests for read-only commands under lock contention and default-mode annotate on an unmaterialized file. The contention tests assert lock readiness before they run each command and release the test lock holder before each test returns.
  • Add functional tests that verify status and for-each-repo still wait for the lock, with controlled alias configuration in the dispatcher test.

The placeholder rejection policy and alias detection remain unchanged. This change does not introduce deferred file opens.

Exempt worktree list without relaxing locks for other worktree subcommands.
Also exempt audited history, ref-query, object-statistics, and verification
operations. Default annotate follows the existing blame policy for
working-tree reads. Neither command provides snapshot isolation.

Share the hook policy with unit coverage through a partial source file.
Add deterministic first-open coverage during a paused worktree-list command.
Cover read-only commands under contention and preserve normal status waits.
Keep test lock holders alive only for the synchronous test action.
Require lock readiness before the action and cover retained dispatcher waits.
Use producer-shaped pre-command and post-command metadata in the unit cases.

Assisted-by: GPT-6.1 Sol
Signed-off-by: Tyrie Vella <tyrielv@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant