From 71c5413e5cb20ea025ae365e6f36501331973062 Mon Sep 17 00:00:00 2001 From: Xinchen Lee Date: Sat, 22 Aug 2026 23:11:27 +0800 Subject: [PATCH] fix(git): hide spawned git windows on Windows (#301) --- src/git.ts | 1 + tests/git-spawn.spec.ts | 41 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+) create mode 100644 tests/git-spawn.spec.ts diff --git a/src/git.ts b/src/git.ts index 5077205..a5bab5e 100644 --- a/src/git.ts +++ b/src/git.ts @@ -96,6 +96,7 @@ function runGit(cwd: string, args: string[], timeoutMs = 30_000): Promise((resolvePromise, reject) => { const child = spawn('git', full, { stdio: ['ignore', 'pipe', 'pipe'], + windowsHide: true, env: { ...process.env, GIT_OPTIONAL_LOCKS: '0' }, }) let stdout = '' diff --git a/tests/git-spawn.spec.ts b/tests/git-spawn.spec.ts new file mode 100644 index 0000000..eab01ec --- /dev/null +++ b/tests/git-spawn.spec.ts @@ -0,0 +1,41 @@ +import { EventEmitter } from 'node:events' +import { PassThrough } from 'node:stream' +import { afterEach, describe, expect, it, vi } from 'vitest' + +const { spawnMock } = vi.hoisted(() => ({ spawnMock: vi.fn() })) + +vi.mock('node:child_process', () => ({ spawn: spawnMock })) + +import { isGitRepo } from '../src/git.ts' + +afterEach(() => { + spawnMock.mockReset() +}) + +describe('git subprocess spawning', () => { + it('hides spawned git windows', async () => { + spawnMock.mockImplementation(() => { + const child = new EventEmitter() + const stdout = new PassThrough() + const stderr = new PassThrough() + Object.assign(child, { stdout, stderr, kill: vi.fn() }) + + queueMicrotask(() => { + stdout.end('true\n') + stderr.end() + child.emit('close', 0) + }) + + return child + }) + + await expect(isGitRepo('C:\\repo')).resolves.toBe(true) + + expect(spawnMock).toHaveBeenCalledTimes(1) + expect(spawnMock).toHaveBeenCalledWith( + 'git', + ['-C', 'C:\\repo', '--no-pager', '-c', 'color.ui=false', 'rev-parse', '--is-inside-work-tree'], + expect.objectContaining({ windowsHide: true }), + ) + }) +})