Skip to content

Change-Detection: Set GIT_OPTIONAL_LOCKS=0 to avoid blocking commits#34726

Merged
valentinpalkovic merged 1 commit into
nextfrom
valentin/fix-git-optional-locks
May 7, 2026
Merged

Change-Detection: Set GIT_OPTIONAL_LOCKS=0 to avoid blocking commits#34726
valentinpalkovic merged 1 commit into
nextfrom
valentin/fix-git-optional-locks

Conversation

@valentinpalkovic
Copy link
Copy Markdown
Contributor

@valentinpalkovic valentinpalkovic commented May 6, 2026

Closes #

What I did

When the Storybook dev server runs with change detection enabled, the user's shell git add/git commit intermittently fails with:

fatal: Unable to create '.git/index.lock': File exists.

GitDiffProvider (in code/core/src/core-server/change-detection/) shells out to git frequently — every file change debounces into a scan that runs five git diff/ls-files commands in parallel, and every git ref change re-runs isWorkingTreeClean() (git status --porcelain). Both git status and git diff opportunistically refresh the index stat cache, which means git briefly takes .git/index.lock during what looks like a read-only call. When the user types git commit in another terminal, it races the dev server and loses.

This PR sets GIT_OPTIONAL_LOCKS=0 on the execa env for every git invocation in GitDiffProvider. That env var tells git to skip the optional stat-cache refresh during read-only commands. The diff/status output stays correct; we only skip the cache update. This is the standard fix VSCode and other editors use for the same reason.

Checklist for Contributors

Testing

The changes in this PR are covered in the following automated tests:

  • stories
  • unit tests
  • integration tests
  • end-to-end tests

The existing GitDiffProvider.test.ts continues to pass (13/13). No new tests are added because the assertion would be "execa was called with a specific env" which over-specifies an implementation detail; the user-visible behavior is "concurrent commits no longer fail," which is verified manually.

Manual testing

  1. cd code && yarn storybook:ui (or run any sandbox dev server in a repo).
  2. In another terminal, repeatedly run touch code/core/src/foo.ts && git add code/core/src/foo.ts && git commit -m wip while the dev server is running.
  3. Before this fix: occasionally fails with fatal: Unable to create '.git/index.lock': File exists.
  4. After this fix: commits always succeed regardless of dev server activity.

Documentation

  • Add or update documentation reflecting your changes
  • If you are deprecating/removing a feature, make sure to update MIGRATION.MD

Checklist for Maintainers

  • When this PR is ready for testing, make sure to add ci:normal, ci:merged or ci:daily GH label to it to run a specific set of sandboxes. The particular set of sandboxes can be found in code/lib/cli-storybook/src/sandbox-templates.ts

  • Make sure this PR contains one of the labels below:

    Available labels
    • bug: Internal changes that fixes incorrect behavior.
    • maintenance: User-facing maintenance tasks.
    • dependencies: Upgrading (sometimes downgrading) dependencies.
    • build: Internal-facing build tooling & test updates. Will not show up in release changelog.
    • cleanup: Minor cleanup style change. Will not show up in release changelog.
    • documentation: Documentation only changes. Will not show up in release changelog.
    • feature request: Introducing a new feature.
    • BREAKING CHANGE: Changes that break compatibility in some way with current major version.
    • other: Changes that don't fit in the above categories.

🦋 Canary release

This PR does not have a canary release associated. You can request a canary release of this pull request by mentioning the @storybookjs/core team here.

core team members can create a canary release here or locally with gh workflow run --repo storybookjs/storybook publish.yml --field pr=<PR_NUMBER>

Summary by CodeRabbit

Bug Fixes

  • Improved stability of git operations by preventing lock file conflicts that could temporarily disrupt repository indexing and analysis during intensive operations.

…mits

`git status --porcelain` and `git diff` opportunistically refresh the
index stat-cache and write to `.git/index.lock` while doing so. The
change-detection scan invokes these commands frequently (every file
change is debounced into a scan; every git ref change re-runs
`isWorkingTreeClean()`), so the running dev server constantly grabs
`.git/index.lock`. When the user runs `git add`/`git commit` in their
shell, it races the dev server and fails with:

    fatal: Unable to create '.git/index.lock': File exists.

Setting `GIT_OPTIONAL_LOCKS=0` on the execa env tells git to skip the
optional stat-cache refresh during read-only operations. Output of
`git status` / `git diff` remains correct; only the cache update is
skipped. This is the standard fix used by editors like VSCode for the
same reason.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@valentinpalkovic valentinpalkovic changed the title fix(change-detection): set GIT_OPTIONAL_LOCKS=0 to avoid blocking commits Change-Detection: Set GIT_OPTIONAL_LOCKS=0 to avoid blocking commits May 6, 2026
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 6, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: db8c6ebd-5fe6-4d85-a93f-0c8074a6abe3

📥 Commits

Reviewing files that changed from the base of the PR and between 62d53db and 83a7e31.

📒 Files selected for processing (1)
  • code/core/src/core-server/change-detection/GitDiffProvider.ts

📝 Walkthrough

Walkthrough

GitDiffProvider.ts is modified to disable optional git locks by adding the GIT_OPTIONAL_LOCKS: '0' environment variable to two git command invocations: getRepoRoot (rev-parse) and runGitCommand. Comments explain this prevents .git/index.lock contention during operations.

Changes

Git Lock Contention Prevention

Layer / File(s) Summary
Core Implementation
code/core/src/core-server/change-detection/GitDiffProvider.ts
getRepoRoot and runGitCommand methods now pass env: { GIT_OPTIONAL_LOCKS: '0' } to execa invocations with explanatory comments. Prevents .git/index.lock creation during stat-cache refreshes and git operations.

Estimated code review effort

🎯 1 (Trivial) | ⏱️ ~3 minutes

Possibly related PRs

  • storybookjs/storybook#34420: Modifies the same GitDiffProvider.ts file and git command invocation routines (getRepoRoot / runGitCommand).
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch

Comment @coderabbitai help to get the list of available commands and usage tips.

@ghengeveld ghengeveld self-requested a review May 6, 2026 14:13
@valentinpalkovic valentinpalkovic self-assigned this May 7, 2026
@valentinpalkovic valentinpalkovic merged commit a6c78c5 into next May 7, 2026
146 of 152 checks passed
@valentinpalkovic valentinpalkovic deleted the valentin/fix-git-optional-locks branch May 7, 2026 07:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants