diff --git a/src/main/git/status.test.ts b/src/main/git/status.test.ts index 252b23ff608..e8d1aac8249 100644 --- a/src/main/git/status.test.ts +++ b/src/main/git/status.test.ts @@ -210,6 +210,26 @@ describe('bulk git helpers', () => { expect(rmMock).not.toHaveBeenCalled() }) + it('handles large tracked path lists during bulk discard classification', async () => { + const trackedStdout = Array.from({ length: 150_000 }, (_, index) => `docs/file-${index}.ts`) + .join('\0') + .concat('\0') + gitExecFileAsyncMock.mockResolvedValueOnce({ stdout: trackedStdout }).mockResolvedValueOnce({ + stdout: '' + }) + + await bulkDiscardChanges('/repo', ['docs']) + + expect(gitExecFileAsyncMock).toHaveBeenNthCalledWith( + 2, + ['restore', '--worktree', '--source=HEAD', '--', ':(literal)docs'], + { + cwd: '/repo' + } + ) + expect(rmMock).not.toHaveBeenCalled() + }) + it('rejects bulk discard paths that traverse outside the worktree', async () => { await expect(bulkDiscardChanges('/repo', ['src/file.ts', '../outside.txt'])).rejects.toThrow( 'resolves outside the worktree' diff --git a/src/main/git/status.ts b/src/main/git/status.ts index 5ab2c757d83..a72c9141907 100644 --- a/src/main/git/status.ts +++ b/src/main/git/status.ts @@ -1158,7 +1158,13 @@ async function listTrackedPathSpecs( cwd: worktreePath } ) - trackedPaths.push(...stdout.split('\0').filter(Boolean)) + // Why: a tracked directory can contain enough paths for push(...split) + // to exceed the JavaScript argument limit before discard decisions run. + for (const trackedPath of stdout.split('\0')) { + if (trackedPath) { + trackedPaths.push(trackedPath) + } + } } return trackedPaths }