Merge pull request #264 from frizynn/fix/gsd-merge-all-conflicts
fix: auto-resolve .gsd/ planning artifact conflicts during slice merge
This commit is contained in:
commit
40e30f61dc
2 changed files with 49 additions and 3 deletions
|
|
@ -673,10 +673,11 @@ export class GitServiceImpl {
|
|||
try {
|
||||
this.git(mergeArgs);
|
||||
} catch (mergeError) {
|
||||
// Check if conflicts are limited to runtime files we can auto-resolve (#189)
|
||||
// Check if conflicts can be auto-resolved (#189, #218)
|
||||
const conflicted = this.git(["diff", "--name-only", "--diff-filter=U"], { allowFailure: true });
|
||||
if (conflicted) {
|
||||
const conflictedFiles = conflicted.split("\n").filter(Boolean);
|
||||
const allGsd = conflictedFiles.every(f => f.startsWith(".gsd/"));
|
||||
const allRuntime = conflictedFiles.every(f =>
|
||||
RUNTIME_EXCLUSION_PATHS.some(excl => f.startsWith(excl.replace(/\/$/, ""))),
|
||||
);
|
||||
|
|
@ -688,12 +689,21 @@ export class GitServiceImpl {
|
|||
}
|
||||
this.git(["add", "-A"], { allowFailure: true });
|
||||
// Don't throw — let the merge proceed
|
||||
} else if (allGsd) {
|
||||
// Non-runtime .gsd/ conflicts (DECISIONS.md, REQUIREMENTS.md, ROADMAP.md, etc.):
|
||||
// The slice branch has the authoritative .gsd/ state since the LLM just finished
|
||||
// updating these artifacts during complete-slice. Take theirs (the slice branch).
|
||||
for (const f of conflictedFiles) {
|
||||
this.git(["checkout", "--theirs", "--", f], { allowFailure: true });
|
||||
}
|
||||
this.git(["add", "-A"], { allowFailure: true });
|
||||
// Don't throw — let the merge proceed
|
||||
} else {
|
||||
// Non-runtime conflicts: reset and throw as before
|
||||
// Non-.gsd/ conflicts: reset and throw as before
|
||||
this.git(["reset", "--hard", "HEAD"], { allowFailure: true });
|
||||
const msg = mergeError instanceof Error ? mergeError.message : String(mergeError);
|
||||
throw new Error(
|
||||
`${strategy === "merge" ? "Merge" : "Squash-merge"} of "${branch}" into "${mainBranch}" failed with conflicts. ` +
|
||||
`${strategy === "merge" ? "Merge" : "Squash-merge"} of "${branch}" into "${mainBranch}" failed with conflicts in non-.gsd/ files. ` +
|
||||
`Working tree has been reset to a clean state. ` +
|
||||
`Resolve manually: git checkout ${mainBranch} && git merge ${strategy === "merge" ? "--no-ff" : "--squash"} ${branch}\n` +
|
||||
`Original error: ${msg}`,
|
||||
|
|
|
|||
|
|
@ -953,6 +953,42 @@ async function main(): Promise<void> {
|
|||
rmSync(repo, { recursive: true, force: true });
|
||||
}
|
||||
|
||||
// ─── mergeSliceToMain: auto-resolve .gsd/ planning artifact conflicts ──
|
||||
|
||||
console.log("\n=== mergeSliceToMain: auto-resolve .gsd/ planning conflicts ===");
|
||||
|
||||
{
|
||||
const repo = initBranchTestRepo();
|
||||
const svc = new GitServiceImpl(repo);
|
||||
|
||||
// Create a .gsd/ planning artifact on main (simulates reassess-roadmap)
|
||||
createFile(repo, ".gsd/DECISIONS.md", "# Decisions\n\n- D001: Original decision\n");
|
||||
run("git add -A", repo);
|
||||
run("git commit -m 'add decisions on main'", repo);
|
||||
|
||||
// Create slice branch and modify the same .gsd/ file differently
|
||||
svc.ensureSliceBranch("M001", "S01");
|
||||
createFile(repo, ".gsd/DECISIONS.md", "# Decisions\n\n- D001: Original decision\n- D002: New decision from slice\n");
|
||||
createFile(repo, "src/feature.ts", "export const x = 1;");
|
||||
run("git add -A", repo);
|
||||
run("git commit -m 'slice work with .gsd/ changes'", repo);
|
||||
|
||||
// Back on main, modify the same .gsd/ file to create a conflict
|
||||
svc.switchToMain();
|
||||
createFile(repo, ".gsd/DECISIONS.md", "# Decisions\n\n- D001: Updated decision on main\n");
|
||||
run("git add -A", repo);
|
||||
run("git commit -m 'update decisions on main'", repo);
|
||||
|
||||
// Merge should auto-resolve .gsd/ conflicts by taking theirs (slice branch)
|
||||
const result = svc.mergeSliceToMain("M001", "S01", "Feature with .gsd/ conflicts");
|
||||
assertEq(result.deletedBranch, true, ".gsd/ conflict auto-resolved: branch deleted");
|
||||
|
||||
// Verify the merge succeeded and src file is present
|
||||
assert(existsSync(join(repo, "src/feature.ts")), ".gsd/ conflict auto-resolved: src file merged");
|
||||
|
||||
rmSync(repo, { recursive: true, force: true });
|
||||
}
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════════════
|
||||
// S05: Enhanced features — merge guards, snapshots, auto-push, rich commits
|
||||
// ═══════════════════════════════════════════════════════════════════════
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue