authorgravatar for julius0216@outlook.comJulius Marminge <julius0216@outlook.com> 2026-07-22 16:19:01+02:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2026-07-22 14:19:01+00:00
log571a8b44bdd4f0f0b0464ef24240021689616e7d
tree667e9f86faca3e6f42d78bdba864ba33916d4920
parentb6e1b39335ffd34583c94f5b1e5e2c80520729fe
signature Signed by PGP key B5690EEEBB952194

Unify temporary worktree branch naming (#4278)


2 files changed, 36 insertions(+), 2 deletions(-)

packages/shared/src/git.test.ts+23
...@@ -71,6 +71,29 @@ describe("isTemporaryWorktreeBranch", () => {...@@ -71,6 +71,29 @@ describe("isTemporaryWorktreeBranch", () => {
71 expect(isTemporaryWorktreeBranch(`${WORKTREE_BRANCH_PREFIX}/DEADBEEF`)).toBe(true);71 expect(isTemporaryWorktreeBranch(`${WORKTREE_BRANCH_PREFIX}/DEADBEEF`)).toBe(true);
72 });72 });
7373
74 it("normalizes a UUID-shaped random callback to the canonical 8-hex form", () => {
75 expect(buildTemporaryWorktreeBranchName(() => "f4ae4e0e-f971-4d48-b4f2-9cf0aa54ab12")).toBe(
76 `${WORKTREE_BRANCH_PREFIX}/f4ae4e0e`,
77 );
78 });
79
80 it("matches legacy UUID-shaped temporary worktree refs from older mobile builds", () => {
81 expect(
82 isTemporaryWorktreeBranch(`${WORKTREE_BRANCH_PREFIX}/f4ae4e0e-f971-4d48-b4f2-9cf0aa54ab12`),
83 ).toBe(true);
84 });
85
86 it("rejects UUID-shaped refs that are not RFC 4122 v4", () => {
87 // version nibble is not 4
88 expect(
89 isTemporaryWorktreeBranch(`${WORKTREE_BRANCH_PREFIX}/f4ae4e0e-f971-1d48-b4f2-9cf0aa54ab12`),
90 ).toBe(false);
91 // variant nibble is not [89ab]
92 expect(
93 isTemporaryWorktreeBranch(`${WORKTREE_BRANCH_PREFIX}/f4ae4e0e-f971-4d48-c4f2-9cf0aa54ab12`),
94 ).toBe(false);
95 });
96
74 it("rejects non-temporary refName names", () => {97 it("rejects non-temporary refName names", () => {
75 expect(isTemporaryWorktreeBranch(`${WORKTREE_BRANCH_PREFIX}/feature/demo`)).toBe(false);98 expect(isTemporaryWorktreeBranch(`${WORKTREE_BRANCH_PREFIX}/feature/demo`)).toBe(false);
76 expect(isTemporaryWorktreeBranch("main")).toBe(false);99 expect(isTemporaryWorktreeBranch("main")).toBe(false);
packages/shared/src/git.ts+13-2
...@@ -11,7 +11,13 @@ import * as Result from "effect/Result";...@@ -11,7 +11,13 @@ import * as Result from "effect/Result";
11import { detectSourceControlProviderFromRemoteUrl } from "./sourceControl.ts";11import { detectSourceControlProviderFromRemoteUrl } from "./sourceControl.ts";
1212
13export const WORKTREE_BRANCH_PREFIX = "t3code";13export const WORKTREE_BRANCH_PREFIX = "t3code";
14const TEMP_WORKTREE_BRANCH_PATTERN = new RegExp(`^${WORKTREE_BRANCH_PREFIX}\\/[0-9a-f]{8}$`);14// Canonical form is `t3code/<8 hex>`. Older mobile builds generated `t3code/<uuid>`
15// via Crypto.randomUUID() (always RFC 4122 v4), so the matcher also accepts exactly
16// that shape — version nibble `4`, variant nibble `[89ab]` — to keep those threads
17// eligible for branch regeneration without loosening beyond what was ever generated.
18const TEMP_WORKTREE_BRANCH_PATTERN = new RegExp(
19 `^${WORKTREE_BRANCH_PREFIX}\\/(?:[0-9a-f]{8}|[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12})$`,
20);
1521
16/**22/**
17 * Sanitize an arbitrary string into a valid, lowercase git refName fragment.23 * Sanitize an arbitrary string into a valid, lowercase git refName fragment.
...@@ -89,7 +95,12 @@ export function deriveLocalBranchNameFromRemoteRef(branchName: string): string {...@@ -89,7 +95,12 @@ export function deriveLocalBranchNameFromRemoteRef(branchName: string): string {
89export function buildTemporaryWorktreeBranchName(95export function buildTemporaryWorktreeBranchName(
90 randomHex: (byteLength: number) => string,96 randomHex: (byteLength: number) => string,
91): string {97): string {
92 const token = randomHex(4).toLowerCase();98 // Normalize to exactly 8 lowercase hex chars so a UUID-shaped callback
99 // still produces the canonical temporary branch form.
100 const token = randomHex(4)
101 .toLowerCase()
102 .replace(/[^0-9a-f]/g, "")
103 .slice(0, 8);
93 return `${WORKTREE_BRANCH_PREFIX}/${token}`;104 return `${WORKTREE_BRANCH_PREFIX}/${token}`;
94}105}
95106