Skip to content

Commit c08e4cd

Browse files
committed
fix(worktree): 删除时按当前真实分支清理已改名的 worktree 分支
产品层面: - 修复用户在创建子 worktree 后手动重命名分支时,删除 worktree 仍沿用旧分支名,导致专用分支残留的问题。 - 保持 detached HEAD 等原有兜底行为不变,避免删除流程在无有效当前分支时误删错误引用。 技术层面: - 在 `removeWorktreeAsync` 中将删除分支前的 `wtBranch` 解析调整为“优先读取当前 worktree 真实分支,再回退到元数据记录”。 - 继续复用既有 `resolveWorktreeBranchNameAsync`,确保分支信息在 worktree 目录被移除前完成解析。 - 补充回归测试,覆盖 worktree 分支被手动改名后仍能正确删除 worktree 与对应分支的场景。 验证: - `npx vitest run electron/git/worktreeMetaFallback.test.ts electron/git/worktreeBaseBranchOwner.test.ts` Signed-off-by: Lulu <58587930+lulu-sk@users.noreply.github.com>
1 parent d5489d1 commit c08e4cd

File tree

2 files changed

+50
-3
lines changed

2 files changed

+50
-3
lines changed

electron/git/worktreeMetaFallback.test.ts

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -268,5 +268,47 @@ describe("worktree meta 缺失回退(recycle/reset/remove)", () => {
268268
},
269269
{ timeout: 120_000 }
270270
);
271+
272+
it(
273+
"remove:当 worktree 分支已被手动改名时,应按当前真实分支完成删除",
274+
async () => {
275+
const repo = await fsp.mkdtemp(path.join(os.tmpdir(), "codexflow-wt-remove-renamed-main-"));
276+
const wtParent = await fsp.mkdtemp(path.join(os.tmpdir(), "codexflow-wt-remove-renamed-child-parent-"));
277+
const wtDir = path.join(wtParent, "wt");
278+
const userData = await fsp.mkdtemp(path.join(os.tmpdir(), "codexflow-userdata-"));
279+
userDataDir = userData;
280+
281+
try {
282+
await git(repo, ["init"]);
283+
await git(repo, ["config", "user.name", "CodexFlow"]);
284+
await git(repo, ["config", "user.email", "codexflow@example.com"]);
285+
await git(repo, ["config", "core.autocrlf", "false"]);
286+
await git(repo, ["config", "core.eol", "lf"]);
287+
288+
await git(repo, ["checkout", "-b", "main"]);
289+
await fsp.writeFile(path.join(repo, "a.txt"), "A\n", "utf8");
290+
await git(repo, ["add", "a.txt"]);
291+
await git(repo, ["commit", "-m", "main: init"]);
292+
293+
await git(repo, ["worktree", "add", "-b", "wt", wtDir, "main"]);
294+
await git(wtDir, ["branch", "-m", "wt-renamed"]);
295+
296+
const res = await removeWorktreeAsync({ worktreePath: wtDir, deleteBranch: true });
297+
expect(res.ok).toBe(true);
298+
if (res.ok) {
299+
expect(res.removedWorktree).toBe(true);
300+
expect(res.removedBranch).toBe(true);
301+
}
302+
303+
const renamedRef = await gitTry(repo, ["show-ref", "--verify", "refs/heads/wt-renamed"]);
304+
expect(renamedRef.ok).toBe(false);
305+
} finally {
306+
try { await fsp.rm(wtParent, { recursive: true, force: true }); } catch {}
307+
try { await fsp.rm(repo, { recursive: true, force: true }); } catch {}
308+
try { await fsp.rm(userData, { recursive: true, force: true }); } catch {}
309+
}
310+
},
311+
{ timeout: 120_000 }
312+
);
271313
});
272314

electron/git/worktreeOps.ts

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1797,11 +1797,16 @@ export async function removeWorktreeAsync(req: RemoveWorktreeRequest): Promise<R
17971797
repoMainPath = inferred.repoMainPath;
17981798
}
17991799

1800-
// 中文说明:deleteBranch=true 时需要的关键信息尽量在 remove 之前解析(避免目录被移除后无法读取)
1800+
// 中文说明:deleteBranch=true 时需要的关键信息尽量在 remove 之前解析(避免目录被移除后无法读取)。
1801+
// - 优先读取 worktree 当前真实分支,兼容用户在创建后手动改名导致元数据过期的场景;
1802+
// - 若当前为 detached HEAD 或解析失败,再回退到创建记录中的 wtBranch。
18011803
let resolvedWtBranch = String(meta?.wtBranch || "").trim();
1802-
if (req.deleteBranch && !resolvedWtBranch) {
1804+
if (req.deleteBranch) {
18031805
const inferred = await resolveWorktreeBranchNameAsync({ repoDir: repoMainPath, worktreePath: wt, gitPath, timeoutMs: 12_000 });
1804-
if (inferred.ok && !inferred.detached) resolvedWtBranch = String(inferred.branch || "").trim();
1806+
if (inferred.ok && !inferred.detached) {
1807+
const inferredBranch = String(inferred.branch || "").trim();
1808+
if (inferredBranch) resolvedWtBranch = inferredBranch;
1809+
}
18051810
}
18061811

18071812
let baseRefForMergedCheck = String(meta?.baseBranch || "").trim();

0 commit comments

Comments
 (0)