From a37220b2371c79faa12dfd7be81edb5f2927bc02 Mon Sep 17 00:00:00 2001 From: JonathanLab Date: Tue, 10 Feb 2026 11:16:28 +0000 Subject: [PATCH] fix: limit git processes Handle misusage of simplegit by instead not creating a git client for every thing --- packages/git/src/operation-manager.ts | 36 ++++++++++++++++++++------- 1 file changed, 27 insertions(+), 9 deletions(-) diff --git a/packages/git/src/operation-manager.ts b/packages/git/src/operation-manager.ts index be7bd051a..e5e55b84d 100644 --- a/packages/git/src/operation-manager.ts +++ b/packages/git/src/operation-manager.ts @@ -1,9 +1,10 @@ -import { createGitClient } from "./client.js"; +import { createGitClient, type GitClient } from "./client.js"; import { removeLock, waitForUnlock } from "./lock-detector.js"; import { AsyncReaderWriterLock } from "./rw-lock.js"; interface RepoState { lock: AsyncReaderWriterLock; + client: GitClient; lastAccess: number; } @@ -29,7 +30,11 @@ class GitOperationManagerImpl { private getRepoState(repoPath: string): RepoState { let state = this.repoStates.get(repoPath); if (!state) { - state = { lock: new AsyncReaderWriterLock(), lastAccess: Date.now() }; + state = { + lock: new AsyncReaderWriterLock(), + client: createGitClient(repoPath), + lastAccess: Date.now(), + }; this.repoStates.set(repoPath, state); } state.lastAccess = Date.now(); @@ -47,18 +52,25 @@ class GitOperationManagerImpl { async executeRead( repoPath: string, - operation: (git: ReturnType) => Promise, + operation: (git: GitClient) => Promise, options?: ExecuteOptions, ): Promise { - const git = createGitClient(repoPath, { - abortSignal: options?.signal, - }).env({ GIT_OPTIONAL_LOCKS: "0" }); + const state = this.getRepoState(repoPath); + + if (options?.signal) { + const scopedGit = createGitClient(repoPath, { + abortSignal: options.signal, + }); + return operation(scopedGit.env({ GIT_OPTIONAL_LOCKS: "0" })); + } + + const git = state.client.env({ GIT_OPTIONAL_LOCKS: "0" }); return operation(git); } async executeWrite( repoPath: string, - operation: (git: ReturnType) => Promise, + operation: (git: GitClient) => Promise, options?: ExecuteOptions, ): Promise { const state = this.getRepoState(repoPath); @@ -75,8 +87,14 @@ class GitOperationManagerImpl { await state.lock.acquireWrite(); try { - const git = createGitClient(repoPath, { abortSignal: options?.signal }); - return await operation(git); + if (options?.signal) { + const scopedGit = createGitClient(repoPath, { + abortSignal: options.signal, + }); + return await operation(scopedGit); + } + + return await operation(state.client); } catch (error) { if (options?.signal?.aborted) { await removeLock(repoPath).catch(() => {});