From 7a172d86f529cbe8f0dd10ea2483e2f8e740cee4 Mon Sep 17 00:00:00 2001 From: Nikhilesh Nanduri Date: Fri, 15 May 2026 01:51:13 +0530 Subject: [PATCH] fix(gbrain-sync): append .gbrain-source to consumer repo's .gitignore after attach Closes #1384. The v1.29.0.0 changelog promised that .gbrain-source would be added to the consuming repo's .gitignore; the original patch only added it to gstack's own .gitignore. Conductor sibling worktrees sharing the same repo+branch would overwrite each other's per-worktree pin on every pull. Co-Authored-By: Claude Sonnet 4.6 --- bin/gstack-gbrain-sync.ts | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/bin/gstack-gbrain-sync.ts b/bin/gstack-gbrain-sync.ts index 36b265e42d..e6693ea5f9 100644 --- a/bin/gstack-gbrain-sync.ts +++ b/bin/gstack-gbrain-sync.ts @@ -408,6 +408,24 @@ async function runCodeImport(args: CliArgs): Promise { }; } + // After a successful attach, ensure .gbrain-source is in the consumer repo's + // .gitignore. The v1.29.0.0 changelog promised this; the original patch only + // added it to gstack's own .gitignore, not the consuming repo's. Without this, + // `git add -A` in any Conductor sibling worktree can commit the pin and silently + // override other worktrees' per-worktree source IDs on next pull. + try { + const gitignorePath = join(root, ".gitignore"); + let existing = ""; + try { existing = readFileSync(gitignorePath, "utf-8"); } catch { /* will create */ } + if (!existing.split("\n").some((line) => line.trim() === ".gbrain-source")) { + const sep = existing.length > 0 && !existing.endsWith("\n") ? "\n" : ""; + writeFileSync(gitignorePath, existing + sep + ".gbrain-source\n"); + } + } catch { + // Non-fatal — unwritable .gitignore (read-only checkout, weird perms) should + // not fail the stage. The user will need to add the entry manually. + } + return { name: "code", ran: true,