From 41418194e9cf296627f1d7ab1a680c98ed10a74a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?T=C3=82CHES?= Date: Fri, 13 Mar 2026 12:22:47 -0600 Subject: [PATCH] fix: untrack runtime files from slice branch before squash-merge (#218) (#220) Squash-merges fail with conflicts in .gsd/metrics.json and .gsd/completed-units.json because these runtime files get tracked on the slice branch. The existing pre-merge untrack only runs on main, so the squash-merge sees modify/delete conflicts. Untrack runtime files from the slice branch before merging, matching the existing main-branch untrack. Also switch runtime conflict auto-resolution from --ours to --theirs as a more correct fallback. Co-authored-by: Claude Opus 4.6 (1M context) --- src/resources/extensions/gsd/git-service.ts | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/resources/extensions/gsd/git-service.ts b/src/resources/extensions/gsd/git-service.ts index 1264dfdab..3a37b6a42 100644 --- a/src/resources/extensions/gsd/git-service.ts +++ b/src/resources/extensions/gsd/git-service.ts @@ -649,6 +649,18 @@ export class GitServiceImpl { this.git(["commit", "-m", "chore: untrack .gsd/ runtime files before merge"], { allowFailure: true }); } + // Also untrack runtime files from the slice branch to prevent + // modify/delete conflicts during squash-merge (#218) + this.git(["checkout", branch]); + for (const exclusion of RUNTIME_EXCLUSION_PATHS) { + this.git(["rm", "--cached", "-r", "--ignore-unmatch", exclusion], { allowFailure: true }); + } + const branchUntrackDiff = this.git(["diff", "--cached", "--stat"], { allowFailure: true }); + if (branchUntrackDiff?.trim()) { + this.git(["commit", "-m", "chore: untrack .gsd/ runtime files before merge"], { allowFailure: true }); + } + this.git(["checkout", mainBranch]); + // Merge slice branch — strategy is configurable via git.merge_strategy // preference. Default: "squash" (preserves existing behavior). // "merge" uses --no-ff which is more resilient to conflicts from @@ -671,7 +683,7 @@ export class GitServiceImpl { if (allRuntime) { // Runtime-only conflicts: take ours and remove from index for (const f of conflictedFiles) { - this.git(["checkout", "--ours", "--", f], { allowFailure: true }); + this.git(["checkout", "--theirs", "--", f], { allowFailure: true }); this.git(["rm", "--cached", "--ignore-unmatch", f], { allowFailure: true }); } this.git(["add", "-A"], { allowFailure: true });