From 8aeb8f244d2c56b5abe79036ffa6c100f104a34d Mon Sep 17 00:00:00 2001 From: Julius Marminge Date: Sun, 4 Oct 2026 19:14:37 -0700 Subject: [PATCH] fix(dev): worktree setup never deletes a real env file The setup action removed each target before symlinking it to the main checkout. Its only guard compared the realpaths of the project root and the worktree, so a run where that check failed replaced the main checkout's real .env files with links to themselves, losing them. Now only an existing symlink is replaced, a real file at the target is left alone, and a source that is not a regular file is skipped with a warning instead of being linked. Co-Authored-By: Claude Opus 5.5 (1M context) --- scripts/setup-worktree.ts | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/scripts/setup-worktree.ts b/scripts/setup-worktree.ts index ea07a8b65ad8..d99de5b543a7 100644 --- a/scripts/setup-worktree.ts +++ b/scripts/setup-worktree.ts @@ -26,15 +26,22 @@ const install = NodeChildProcess.spawnSync("vp i", { }); if (install.status !== 0) process.exit(install.status ?? 1); -// In the main checkout itself, relinking would replace the real env files. -if (NodeFS.realpathSync(projectRoot) !== NodeFS.realpathSync(worktree)) { - for (const file of ENV_FILES) { - const source = NodePath.join(projectRoot, file); - if (!NodeFS.existsSync(source)) continue; - const target = NodePath.join(worktree, file); - NodeFS.rmSync(target, { force: true }); - NodeFS.symlinkSync(source, target); +// Env files live as real files in the main checkout; worktrees only get +// symlinks to them. Only a symlink is ever replaced, so a real env file is +// never deleted, including when this runs in the main checkout itself. +for (const file of ENV_FILES) { + const source = NodePath.join(projectRoot, file); + const sourceStat = NodeFS.lstatSync(source, { throwIfNoEntry: false }); + if (!sourceStat) continue; + if (!sourceStat.isFile()) { + console.warn(`Skipping ${file}: ${source} is not a regular file.`); + continue; } + const target = NodePath.join(worktree, file); + const existing = NodeFS.lstatSync(target, { throwIfNoEntry: false }); + if (existing && !existing.isSymbolicLink()) continue; + if (existing) NodeFS.rmSync(target); + NodeFS.symlinkSync(source, target); } const warm = NodeChildProcess.spawnSync(