Skip to content
30 changes: 29 additions & 1 deletion apps/server/src/vcs/GitVcsDriverCore.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5097,15 +5097,18 @@ it.layer(layerTest)("GitVcsDriver core integration", (it) => {
}),
);

it.effect("keeps generated worktree folders short without changing long branch names", () =>
it.effect("keeps generated worktree folders short and valid on Windows", () =>
Effect.gen(function* () {
const platform = yield* HostProcess.Platform;
const pathService = yield* Path.Path;
const cwd = yield* makeTmpDir();
const { initialBranch } = yield* initRepoWithCommit(cwd);
const worktreesDirectory = yield* makeTmpDir("custom-worktrees-");
const driver = yield* GitVcsDriver.GitVcsDriver;
const folders = new Set<string>();
const branches = [
"fix-a-b",
"console",
`feature/${"a".repeat(90)}/${"b".repeat(90)}/${"c".repeat(90)}`,
`feature/${"a".repeat(90)}/${"b".repeat(90)}/${"d".repeat(90)}`,
`feature/${"a".repeat(40)}/5fac`,
Expand All @@ -5115,6 +5118,27 @@ it.layer(layerTest)("GitVcsDriver core integration", (it) => {
"界".repeat(80),
"z".repeat(40),
"z".repeat(41),
// The files ref backend cannot create or lock these branch names on Windows.
...(platform === "win32"
? []
: [
"fix/a<b",
"fix/a>b",
"fix/a|b",
"con",
"prn",
"prn.txt",
"aux.c",
"lpt0",
"COM¹",
"COM².txt",
"LPT³",
"CONIN$",
"CONIN$.txt",
"CONOUT$",
"CONOUT$.txt",
`nul.${"n".repeat(40)}`,
]),
];
for (const branch of branches) {
const created = yield* driver.createWorktree(
Expand All @@ -5123,6 +5147,10 @@ it.layer(layerTest)("GitVcsDriver core integration", (it) => {
);
const folder = pathService.basename(created.worktree.path);
assert.isAtMost(Buffer.byteLength(folder), 40);
assert.notMatch(
folder,
/[<>"|]|^(con|prn|aux|nul|com[0-9¹²³]|lpt[0-9¹²³]|conin\$|conout\$)(\.|$)/i,
);
assert.equal(yield* git(created.worktree.path, ["branch", "--show-current"]), branch);
assert.include(
yield* git(cwd, ["-c", "core.quotePath=false", "worktree", "list", "--porcelain"]),
Expand Down
6 changes: 5 additions & 1 deletion apps/server/src/vcs/GitVcsDriverCore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4247,9 +4247,13 @@ export const makeGitVcsDriverCore = Effect.fn("makeGitVcsDriverCore")(function*
}
const identity = `${yield* readGitCommonDir(input.cwd)}\0${targetBranch}`;
const hash = yield* digest.digest(Digest.sha256, new TextEncoder().encode(identity));
// Git refs already exclude Windows' other invalid characters and trailing dots or spaces.
const windowsSafeName = targetBranch
.replace(/[/<>"|]/g, "-")
.replace(/^(con|prn|aux|nul|com[0-9¹²³]|lpt[0-9¹²³]|conin\$|conout\$)(\.|$)/i, "$1-");
// UTF-8 bytes bound UTF-16 length too, leaving room for files on Windows.
let prefix = "";
for (const character of targetBranch.replace(/\//g, "-")) {
for (const character of windowsSafeName) {
if (Buffer.byteLength(prefix + character) > 23) break;
prefix += character;
}
Expand Down
Loading