Merge pull request #4066 from mastertyko/fix/2156-clean-merged-worktree-branch
This commit is contained in:
commit
3ecaf1eb35
2 changed files with 67 additions and 2 deletions
|
|
@ -2043,7 +2043,7 @@ export function mergeMilestoneToMain(
|
|||
// 12. Remove worktree directory first (must happen before branch deletion)
|
||||
try {
|
||||
removeWorktree(originalBasePath_, milestoneId, {
|
||||
branch: null as unknown as string,
|
||||
branch: milestoneBranch,
|
||||
deleteBranch: false,
|
||||
});
|
||||
} catch (err) {
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@
|
|||
|
||||
import { describe, test, afterEach } from "node:test";
|
||||
import assert from "node:assert/strict";
|
||||
import { mkdtempSync, mkdirSync, writeFileSync, rmSync, existsSync, realpathSync, readFileSync } from "node:fs";
|
||||
import { mkdtempSync, mkdirSync, writeFileSync, rmSync, existsSync, realpathSync, readFileSync, symlinkSync, unlinkSync } from "node:fs";
|
||||
import { join } from "node:path";
|
||||
import { tmpdir } from "node:os";
|
||||
import { execSync } from "node:child_process";
|
||||
|
|
@ -44,6 +44,27 @@ function createTempRepo(): string {
|
|||
return dir;
|
||||
}
|
||||
|
||||
function createTempRepoWithExternalGsd(): { repo: string; externalState: string } {
|
||||
const realTmp = realpathSync(tmpdir());
|
||||
const repo = realpathSync(mkdtempSync(join(realTmp, "wt-ms-merge-ext-test-")));
|
||||
const externalState = realpathSync(mkdtempSync(join(realTmp, "wt-ms-merge-ext-state-")));
|
||||
|
||||
run("git init", repo);
|
||||
run("git config user.email test@test.com", repo);
|
||||
run("git config user.name Test", repo);
|
||||
|
||||
mkdirSync(join(externalState, "worktrees"), { recursive: true });
|
||||
symlinkSync(externalState, join(repo, ".gsd"));
|
||||
|
||||
writeFileSync(join(repo, "README.md"), "# test\n");
|
||||
writeFileSync(join(externalState, "STATE.md"), "# State\n");
|
||||
run("git add .", repo);
|
||||
run("git commit -m init", repo);
|
||||
run("git branch -M main", repo);
|
||||
|
||||
return { repo, externalState };
|
||||
}
|
||||
|
||||
/** Minimal roadmap content for mergeMilestoneToMain. */
|
||||
function makeRoadmap(milestoneId: string, title: string, slices: Array<{ id: string; title: string }>): string {
|
||||
const sliceLines = slices.map(s => `- [x] **${s.id}: ${s.title}**`).join("\n");
|
||||
|
|
@ -87,6 +108,12 @@ describe("auto-worktree-milestone-merge", { timeout: 300_000 }, () => {
|
|||
return d;
|
||||
}
|
||||
|
||||
function freshRepoWithExternalGsd(): { repo: string; externalState: string } {
|
||||
const { repo, externalState } = createTempRepoWithExternalGsd();
|
||||
tempDirs.push(repo, externalState);
|
||||
return { repo, externalState };
|
||||
}
|
||||
|
||||
afterEach(() => {
|
||||
process.chdir(savedCwd);
|
||||
for (const d of tempDirs) {
|
||||
|
|
@ -638,6 +665,44 @@ describe("auto-worktree-milestone-merge", { timeout: 300_000 }, () => {
|
|||
"#1906: codeFilesChanged must be false when only .gsd/ files were merged");
|
||||
});
|
||||
|
||||
test("#2156: mergeMilestoneToMain removes external-state worktrees using the milestone branch name", () => {
|
||||
const { repo, externalState } = freshRepoWithExternalGsd();
|
||||
const wtPath = createAutoWorktree(repo, "M215");
|
||||
|
||||
addSliceToMilestone(repo, wtPath, "M215", "S01", "External cleanup", [
|
||||
{ file: "external-cleanup.ts", content: "export const externalCleanup = true;\n", message: "add external cleanup" },
|
||||
]);
|
||||
|
||||
const realWtPath = realpathSync(wtPath);
|
||||
assert.ok(
|
||||
realWtPath.startsWith(externalState),
|
||||
`worktree should be registered under external .gsd state, got ${realWtPath}`,
|
||||
);
|
||||
|
||||
// Recreate the exact divergence from #1852: local .gsd/ is replaced with a
|
||||
// stale real directory, so worktreePath() no longer matches git's record.
|
||||
unlinkSync(join(repo, ".gsd"));
|
||||
mkdirSync(join(repo, ".gsd", "worktrees", "M215"), { recursive: true });
|
||||
writeFileSync(join(repo, ".gsd", "STATE.md"), "# Local stale state\n");
|
||||
writeFileSync(join(repo, ".gsd", "worktrees", "M215", "stale.txt"), "stale local artifact\n");
|
||||
|
||||
const roadmap = makeRoadmap("M215", "External cleanup", [
|
||||
{ id: "S01", title: "External cleanup" },
|
||||
]);
|
||||
|
||||
mergeMilestoneToMain(repo, "M215", roadmap);
|
||||
|
||||
assert.ok(
|
||||
!run("git worktree list", repo).includes("M215"),
|
||||
"merged milestone worktree should be removed from git worktree list",
|
||||
);
|
||||
assert.ok(!existsSync(realWtPath), "real external worktree directory should be removed");
|
||||
assert.ok(
|
||||
!run("git branch", repo).includes("milestone/M215"),
|
||||
"milestone branch should be deleted after merge cleanup",
|
||||
);
|
||||
});
|
||||
|
||||
test("#2912: MERGE_HEAD cleaned up after squash-merge conflict", () => {
|
||||
const repo = freshRepo();
|
||||
const wtPath = createAutoWorktree(repo, "M291");
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue