Keep new worktrees clean when setup changes are uncommitted (#3311)

* fix(worktrees): preserve selected base config

New worktrees were overwriting the selected ref's paseo.json with source-checkout bytes, which could create an accidental revert in an otherwise fresh workspace. Keep committed base config authoritative and warn when locally saved setup changes still need to be committed.

* fix(worktrees): seed config exclusively

* fix(projects): refresh config status on focus
This commit is contained in:
Mohamed Boudra
2026-08-13 12:02:15 +02:00
committed by GitHub
parent 9a7301d9a0
commit c190fed27c
23 changed files with 460 additions and 55 deletions
+15 -13
View File
@@ -1,7 +1,14 @@
import { execFile } from "child_process";
import { promisify } from "util";
import { existsSync, mkdirSync, realpathSync, rmSync, statSync } from "fs";
import { readFile, rm, stat } from "fs/promises";
import {
constants as fsConstants,
existsSync,
mkdirSync,
realpathSync,
rmSync,
statSync,
} from "fs";
import { copyFile, rm, stat } from "fs/promises";
import { join, basename, dirname, isAbsolute, resolve, sep } from "path";
import net from "node:net";
import { createHash } from "node:crypto";
@@ -33,7 +40,6 @@ import {
import { runGitCommand } from "./run-git-command.js";
import { spawnProcess } from "./spawn.js";
import { resolvePaseoHome } from "../server/paseo-home.js";
import { writeFileAtomic } from "../server/atomic-file.js";
import { createExternalProcessEnv } from "../server/paseo-env.js";
import { parseGitRevParsePath, resolveGitRevParsePath } from "./git-rev-parse-path.js";
import { validateBranchSlug } from "@getpaseo/protocol/branch-slug";
@@ -794,20 +800,16 @@ export async function runWorktreeTeardownCommands(options: {
return results;
}
export async function copySourcePaseoConfigFile(options: {
export async function seedPaseoConfigFile(options: {
sourceCwd: string;
targetCwd: string;
}): Promise<void> {
const sourceConfigPath = join(options.sourceCwd, "paseo.json");
const targetConfigPath = join(options.targetCwd, "paseo.json");
let sourceConfig: Buffer;
try {
sourceConfig = await readFile(sourceConfigPath);
} catch (error) {
if ((error as NodeJS.ErrnoException).code === "ENOENT") return;
throw error;
}
await writeFileAtomic(targetConfigPath, sourceConfig);
await copyFile(sourceConfigPath, targetConfigPath, fsConstants.COPYFILE_EXCL).catch((error) => {
const code = (error as NodeJS.ErrnoException).code;
if (code !== "EEXIST" && code !== "ENOENT") throw error;
});
}
/**
@@ -1257,7 +1259,7 @@ export const createWorktree = async ({
: {}),
});
await copySourcePaseoConfigFile({ sourceCwd: cwd, targetCwd: worktreePath });
await seedPaseoConfigFile({ sourceCwd: cwd, targetCwd: worktreePath });
if (runSetup) {
await runWorktreeSetupCommands({