fix(auto-worktree): auto-commit project root dirty state before milestone merge (#1130)

This commit is contained in:
Tom Boucher 2026-03-18 10:23:39 -04:00 committed by GitHub
parent 3c0125555b
commit 03caf9c958
8 changed files with 26 additions and 0 deletions

View file

@ -512,6 +512,11 @@ export function mergeMilestoneToMain(
const previousCwd = process.cwd();
process.chdir(originalBasePath_);
// 3a. Auto-commit any dirty state in the project root that syncStateToProjectRoot
// wrote during execution. Without this, the squash merge can fail with
// "Your local changes to the following files would be overwritten by merge" (#1127).
autoCommitDirtyState(originalBasePath_);
// 4. Resolve integration branch — prefer milestone metadata, fall back to preferences / "main"
const prefs = loadEffectiveGSDPreferences()?.preferences?.git ?? {};
const integrationBranch = readIntegrationBranch(originalBasePath_, milestoneId);

View file

@ -37,6 +37,9 @@ function createTempRepo(): string {
run("git config user.email test@test.com", dir);
run("git config user.name Test", dir);
writeFileSync(join(dir, "README.md"), "# test\n");
// Mirror production: .gsd/worktrees/ is gitignored so autoCommitDirtyState
// doesn't pick up the worktrees directory as dirty state (#1127 fix).
writeFileSync(join(dir, ".gitignore"), ".gsd/worktrees/\n");
run("git add .", dir);
run("git commit -m init", dir);
run("git branch -M main", dir);

View file

@ -32,6 +32,9 @@ function createTempRepo(): string {
run("git config user.email test@test.com", dir);
run("git config user.name Test", dir);
writeFileSync(join(dir, "README.md"), "# test\n");
// Mirror production: GSD runtime dirs are gitignored so autoCommitDirtyState
// doesn't pick up the worktrees directory as dirty state (#1127 fix).
writeFileSync(join(dir, ".gitignore"), ".gsd/worktrees/\n");
mkdirSync(join(dir, ".gsd"), { recursive: true });
writeFileSync(join(dir, ".gsd", "STATE.md"), "# State\n");
run("git add .", dir);

View file

@ -75,6 +75,9 @@ function createFeatureBranchRepo(featureBranch: string): string {
// Initial commit on main
writeFileSync(join(dir, "README.md"), "# project\n");
// Mirror production: GSD runtime dirs are gitignored so autoCommitDirtyState
// doesn't pick up the worktrees directory as dirty state (#1127 fix).
writeFileSync(join(dir, ".gitignore"), ".gsd/worktrees/\n");
mkdirSync(join(dir, ".gsd"), { recursive: true });
writeFileSync(join(dir, ".gsd", "STATE.md"), "# State\n");
run("git add .", dir);

View file

@ -38,6 +38,9 @@ function createTempRepo(): string {
run("git config user.email test@test.com", dir);
run("git config user.name Test", dir);
writeFileSync(join(dir, "README.md"), "# test\n");
// Mirror production: .gsd/worktrees/ is gitignored so autoCommitDirtyState
// doesn't pick up the worktrees directory as dirty state (#1127 fix).
writeFileSync(join(dir, ".gitignore"), ".gsd/worktrees/\n");
run("git add .", dir);
run("git commit -m init", dir);
run("git branch -M main", dir);

View file

@ -51,6 +51,9 @@ function createTempRepo(): string {
run("git config user.email test@test.com", dir);
run("git config user.name Test", dir);
writeFileSync(join(dir, "README.md"), "# test\n");
// Mirror production: .gsd/worktrees/ is gitignored so autoCommitDirtyState
// doesn't pick up the worktrees directory as dirty state (#1127 fix).
writeFileSync(join(dir, ".gitignore"), ".gsd/worktrees/\n");
mkdirSync(join(dir, ".gsd"), { recursive: true });
writeFileSync(join(dir, ".gsd", "STATE.md"), "# State\n");
run("git add .", dir);

View file

@ -28,6 +28,9 @@ function createTempRepo(): string {
run("git config user.email test@test.com", dir);
run("git config user.name Test", dir);
writeFileSync(join(dir, "README.md"), "# test\n");
// Mirror production: .gsd/worktrees/ is gitignored so autoCommitDirtyState
// doesn't pick up the worktrees directory as dirty state (#1127 fix).
writeFileSync(join(dir, ".gitignore"), ".gsd/worktrees/\n");
run("git add .", dir);
run("git commit -m init", dir);
run("git branch -M main", dir);

View file

@ -38,6 +38,9 @@ function createTempRepo(): string {
run("git config user.email test@test.com", dir);
run("git config user.name Test", dir);
writeFileSync(join(dir, "README.md"), "# test\n");
// Mirror production: .gsd/worktrees/ is gitignored so autoCommitDirtyState
// doesn't pick up the worktrees directory as dirty state (#1127 fix).
writeFileSync(join(dir, ".gitignore"), ".gsd/worktrees/\n");
mkdirSync(join(dir, ".gsd"), { recursive: true });
writeFileSync(join(dir, ".gsd", "STATE.md"), "# State\n");
run("git add .", dir);