diff --git a/docs/technical/TASK_AUTO_COMMIT_WORKFLOW_2026-04-20.md b/docs/technical/TASK_AUTO_COMMIT_WORKFLOW_2026-04-20.md index 874b52b5..56c89fa8 100644 --- a/docs/technical/TASK_AUTO_COMMIT_WORKFLOW_2026-04-20.md +++ b/docs/technical/TASK_AUTO_COMMIT_WORKFLOW_2026-04-20.md @@ -47,6 +47,7 @@ node scripts/commit-task.mjs \ 3. 指定文件没有改动时不会创建空提交。 4. 脚本不会自动把未指定文件加入提交。 5. 脚本不做 `amend`,不改写历史。 +6. 即使索引里已经有其他已暂存文件,脚本也只会提交本次显式传入的文件。 ## 5. 适用范围 @@ -76,3 +77,4 @@ node scripts/commit-task.mjs \ 1. `scripts/commit-task.test.ts` 2. 覆盖“只提交指定文件,保留未指定改动在工作区”的核心行为 +3. 覆盖“已有其他 staged 改动时不混入当前提交”的边界行为 diff --git a/scripts/commit-task.mjs b/scripts/commit-task.mjs index a9600054..7ac8b99e 100644 --- a/scripts/commit-task.mjs +++ b/scripts/commit-task.mjs @@ -54,4 +54,4 @@ if (!stagedOutput) { fail('暂存后没有检测到可提交内容'); } -runGit(['commit', '-m', message], { stdio: 'inherit' }); +runGit(['commit', '-m', message, '--', ...fileArgs], { stdio: 'inherit' }); diff --git a/scripts/commit-task.test.ts b/scripts/commit-task.test.ts index a2a43715..b3e3b9cd 100644 --- a/scripts/commit-task.test.ts +++ b/scripts/commit-task.test.ts @@ -1,6 +1,6 @@ -import { mkdtempSync, mkdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs'; +import { mkdtempSync, mkdirSync, rmSync, writeFileSync } from 'node:fs'; import { tmpdir } from 'node:os'; -import { dirname, resolve } from 'node:path'; +import { resolve } from 'node:path'; import { spawnSync } from 'node:child_process'; import { afterEach, describe, expect, it } from 'vitest'; @@ -84,4 +84,53 @@ describe('commit-task script', () => { expect(statusResult.stdout).toContain(' M notes/other.md'); expect(statusResult.stdout).not.toContain('docs/task.md'); }); + + it('does not include unrelated staged files in the commit', () => { + const repoRoot = mkdtempSync(resolve(tmpdir(), 'genarrative-commit-task-')); + tempDirs.push(repoRoot); + + mustRun('git', ['init'], repoRoot); + mustRun('git', ['config', 'user.name', 'Codex Test'], repoRoot); + mustRun('git', ['config', 'user.email', 'codex@example.com'], repoRoot); + + mkdirSync(resolve(repoRoot, 'docs'), { recursive: true }); + mkdirSync(resolve(repoRoot, 'notes'), { recursive: true }); + writeFileSync(resolve(repoRoot, 'docs', 'task.md'), 'v1\n', 'utf8'); + writeFileSync(resolve(repoRoot, 'notes', 'other.md'), 'other v1\n', 'utf8'); + + mustRun('git', ['add', '.'], repoRoot); + mustRun('git', ['commit', '-m', 'init'], repoRoot); + + writeFileSync(resolve(repoRoot, 'docs', 'task.md'), 'v2\n', 'utf8'); + writeFileSync(resolve(repoRoot, 'notes', 'other.md'), 'other v2\n', 'utf8'); + mustRun('git', ['add', 'notes/other.md'], repoRoot); + + const scriptPath = resolve('/home/Genarrative/scripts/commit-task.mjs'); + mustRun( + 'node', + [scriptPath, '-m', '只提交任务文件', 'docs/task.md'], + repoRoot, + { + GENARRATIVE_COMMIT_REPO_ROOT: repoRoot, + }, + ); + + const committedTaskContent = mustRun( + 'git', + ['show', 'HEAD:docs/task.md'], + repoRoot, + ).stdout; + expect(committedTaskContent).toBe('v2\n'); + + const committedOtherContent = mustRun( + 'git', + ['show', 'HEAD:notes/other.md'], + repoRoot, + ).stdout; + expect(committedOtherContent).toBe('other v1\n'); + + const statusResult = mustRun('git', ['status', '--short'], repoRoot); + expect(statusResult.stdout).toContain('M notes/other.md'); + expect(statusResult.stdout).not.toContain('docs/task.md'); + }); });