Open
Conversation
…rations isomorphic-git's GitIndexManager uses an in-memory AsyncLock that only serializes within a single Node.js process. When SF CLI and the VS Code extension both access the same source tracking index as separate processes, the index file gets corrupted. Add a reentrant withGitLock() wrapper using lockInit from @salesforce/core (proper-lockfile) around getStatus(), commitChanges(), gitInit(), and delete(). No new dependencies. Closes forcedotcom/cli#3328
…xManager.acquire Co-authored-by: Luke Cotter <lcotter@certinia.com>
There was a problem hiding this comment.
Pull request overview
Adds cross-process locking around ShadowRepo operations that touch the isomorphic-git index to prevent concurrent access corruption when multiple Node processes (e.g., SF CLI + VS Code extension) operate on the same shadow repo.
Changes:
- Introduces a
withGitLock()helper using@salesforce/corelockInitand wrapsgitInit(),getStatus(),commitChanges(), anddelete(). - Refactors
commitChanges()to write blobs and apply index updates in a singleGitIndexManager.acquire()call before committing. - Updates/adds unit tests to validate lock acquisition/release, caching behavior, reentrancy, and error cases.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
src/shared/local/localShadowRepo.ts |
Adds cross-process index locking and refactors index updates in commitChanges() |
test/unit/localShadowRepo.test.ts |
Adds unit tests for lock behavior and updates blob-write expectations |
test/unit/localDetectMovedFiles.test.ts |
Updates moved-file tests to assert commit behavior consistent with the new implementation |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
…uccessful release
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds cross-process file locking around all
ShadowRepomethods that read or write the isomorphic-git index file, preventing the intermittentInvalid checksum in GitIndex buffererrors that occur when SF CLI and the VS Code Salesforce Extension operate concurrently.The lock uses
lockInitfrom@salesforce/core(which wrapsproper-lockfile), already a transitive dependency. No new dependencies are introduced.Problem
isomorphic-git's
GitIndexManageruses an in-memoryAsyncLockthat only serializes within a single Node.js process. The actual filesystem lock is commented out. When two separate processes (SF CLI in the terminal and the VS Code extension running in the background) both access.sf/orgs/<orgId>/localSourceTracking/index, the index file gets corrupted.This has been reported across both repos for 3+ years: forcedotcom/cli#3328, forcedotcom/cli#2422, forcedotcom/cli#2483, isomorphic-git/isomorphic-git#1828, isomorphic-git/isomorphic-git#1721. The isomorphic-git maintainers have stated cross-process coordination is the integrator's responsibility.
Changes
Single file changed:
src/shared/local/localShadowRepo.tslockInitfrom@salesforce/corewithGitLock()private method that acquires a cross-process file lock on<gitDir>/indexviaproper-lockfile's atomicmkdir-based mechanismgetStatus(),commitChanges(),gitInit(), anddelete()withwithGitLock()withGitLock()is reentrant within the same process (tracked via a boolean flag) to handle the internal call chaingetStatus()→detectMovedFiles()→commitChanges()→getStatus(true)without deadlockingReads are locked too; a concurrent write can leave a partially-written index that
statusMatrixwould misparse.Caveats
proper-lockfile's lock only works if all processes check for it. SF CLI and the VS Code extension bundle their own copies of@salesforce/source-tracking. Full protection is only in effect once both consumers ship this update. During the transition (one patched, one not), the collision window is reduced but not eliminated.Test plan
yarn compile- cleanyarn test- all 105 tests pass (98 existing + 7 new)yarn lint- cleannpx knip- no new unused exports or dependenciescommitChanges()(verified viaindex.lockdirectory presence)getStatus()commitChanges()(no files)getStatus()(no filesystem access)getStatus()→detectMovedFiles()→commitChanges()completes without deadlockdelete()succeeds despite removing the lock directorysf project deploy previewcommands serialize correctly (second process waits for first to release lock, both complete cleanly)