From 6815d1fc05545f83a7ec2227fdd4f3392390f4c2 Mon Sep 17 00:00:00 2001 From: neverland Date: Thu, 6 Aug 2026 10:31:20 +0800 Subject: [PATCH] fix(setup): avoid redundant hooks config writes --- packages/rstack/src/setup/install.ts | 8 +++++++- packages/rstack/tests/setup/install.test.ts | 12 ++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/packages/rstack/src/setup/install.ts b/packages/rstack/src/setup/install.ts index dabab0d..e73fdef 100644 --- a/packages/rstack/src/setup/install.ts +++ b/packages/rstack/src/setup/install.ts @@ -126,9 +126,10 @@ export const installHooks = ({ const directory = path.join(cwd, resolvedDir, '_'); const files = Object.entries(createHookFiles()); + const hooksPathMatches = path.resolve(cwd, configuredHooksPath) === directory; // Skip all writes only when the config, generated content, and executable modes match. const unchanged = - path.resolve(cwd, configuredHooksPath) === directory && + hooksPathMatches && isCurrentFile(path.join(directory, '.gitignore'), gitignore) && files.every(([name, content]) => isCurrentFile(path.join(directory, name), content, true)); @@ -151,6 +152,11 @@ export const installHooks = ({ return fail('write-failed', `Failed to write Git hook files: ${message}`); } + // Avoid rewriting .git/config when only the generated files needed repair. + if (hooksPathMatches) { + return { status: 'installed', hooksPath }; + } + // Point Git at the generated directory only after every runtime file is ready. const configured = runGit(cwd, ['config', '--local', 'core.hooksPath', hooksPath]); if (configured.error || configured.status === null) { diff --git a/packages/rstack/tests/setup/install.test.ts b/packages/rstack/tests/setup/install.test.ts index 643000b..44aef2a 100644 --- a/packages/rstack/tests/setup/install.test.ts +++ b/packages/rstack/tests/setup/install.test.ts @@ -50,6 +50,18 @@ test.runIf(process.platform !== 'win32')('restores executable mode on existing s }); }); +test('repairs generated files without rewriting an unchanged hooksPath', () => { + withRepository((cwd) => { + expect(installHooks({ cwd }).status).toBe('installed'); + const runner = path.join(cwd, hooksPath, 'runner'); + writeFileSync(runner, 'stale\n'); + writeFileSync(path.join(cwd, '.git', 'config.lock'), 'locked'); + + expect(installHooks({ cwd })).toEqual({ status: 'installed', hooksPath }); + expect(readFileSync(runner, 'utf8')).toBe(createHookFiles().runner); + }); +}); + test('skips non-Git directories without creating files', () => { withDirectory((cwd) => { expect(installHooks({ cwd })).toEqual({