From efaf0be2bcc2dc5def2c559147153aa3cb65459a Mon Sep 17 00:00:00 2001 From: Neil Date: Fri, 11 Sep 2026 23:44:42 -0700 Subject: [PATCH] refactor(worktrees): unify host materialization and clarify settings labels --- docs/plans/workspace-copy-on-write.md | 17 +++++ src/main/ipc/worktree-apfs-clone.ts | 3 - .../ipc/worktree-clone-interruption.test.ts | 2 - .../ipc/worktree-include-copy-budget.test.ts | 6 +- src/main/ipc/worktree-path-materialization.ts | 41 +++++++++++ src/main/ipc/worktree-reflink-clone.test.ts | 4 +- src/main/ipc/worktree-reflink-clone.ts | 5 +- src/main/ipc/worktree-remote.ts | 69 ++++--------------- src/main/ipc/worktree-symlinks.test.ts | 9 +-- .../runtime-local-worktree-materialization.ts | 32 +-------- .../worktree-path-materialization.test.ts | 4 +- src/relay/worktree-path-materialization.ts | 18 +---- .../settings/WorktreeSymlinksSection.tsx | 8 +-- src/renderer/src/i18n/locales/en.json | 6 +- src/renderer/src/i18n/locales/es.json | 6 +- src/renderer/src/i18n/locales/fr.json | 6 +- src/renderer/src/i18n/locales/ja.json | 6 +- src/renderer/src/i18n/locales/ko.json | 6 +- src/renderer/src/i18n/locales/zh.json | 6 +- 19 files changed, 106 insertions(+), 148 deletions(-) create mode 100644 src/main/ipc/worktree-path-materialization.ts diff --git a/docs/plans/workspace-copy-on-write.md b/docs/plans/workspace-copy-on-write.md index 7982fdbff74..2eaf1298265 100644 --- a/docs/plans/workspace-copy-on-write.md +++ b/docs/plans/workspace-copy-on-write.md @@ -192,3 +192,20 @@ Final logs: `/tmp/orca-cow-final-tests.log`, `/tmp/orca-cow-final-tc.log`, `/tmp/orca-cow-final-quality.log`, `/tmp/orca-cow-package.log`, `/tmp/orca-cow-packaged-exercise.log`. Full repository lint/tests and signed release packaging were not run; no broader pass claim is implied. + +## Elegance review + +Desktop creation, runtime creation and SSH/WSL host materialization now use one +`materializeHostWorktreePaths` policy function. Transport validation remains at its +boundary, and desktop timing phases remain intact. Removed unused UUID dependency +hooks left behind by exclusive staging. This pass removes 59 net source/test lines. +An overlapping YAML/include fixture verifies that explicit sharing still wins. +Settings now says “Paths for New Worktrees” and “Configured paths” in all six locales; +the private-copy/shared-fallback explanation is retained. The former “Shared” and +“Linked” labels incorrectly implied a single outcome. + +Affected suites passed (130 tests with four platform skips; a subsequent routing, +overlap and WSL run passed 29 tests). Full typecheck and changed-code quality passed. +The renamed empty and populated states rendered cleanly in an isolated background +Electron app, with Add Path exercised through Playwright CDP and worktree identity +verified. No release-readiness or CI-completion claim is added by this refactor. diff --git a/src/main/ipc/worktree-apfs-clone.ts b/src/main/ipc/worktree-apfs-clone.ts index 4834d7474b7..a9db9b29951 100644 --- a/src/main/ipc/worktree-apfs-clone.ts +++ b/src/main/ipc/worktree-apfs-clone.ts @@ -1,4 +1,3 @@ -import { randomUUID } from 'node:crypto' import { constants, existsSync } from 'node:fs' import { access, chmod, lstat, mkdir, mkdtemp, stat } from 'node:fs/promises' import { dirname, join, resolve } from 'node:path' @@ -18,7 +17,6 @@ type ExecFileAsync = ( export type ApfsCloneDeps = { execFileAsync: ExecFileAsync - randomUUID: () => string } async function resolveHelper(): Promise { @@ -44,7 +42,6 @@ async function resolveHelper(): Promise { } export const defaultApfsCloneDeps: ApfsCloneDeps = { - randomUUID, execFileAsync: async (_file, args, options) => { const result = await runWorktreeCloneProcess({ program: await resolveHelper(), diff --git a/src/main/ipc/worktree-clone-interruption.test.ts b/src/main/ipc/worktree-clone-interruption.test.ts index 3fa3dfab5ef..9e2ef721e18 100644 --- a/src/main/ipc/worktree-clone-interruption.test.ts +++ b/src/main/ipc/worktree-clone-interruption.test.ts @@ -65,7 +65,6 @@ describe('interrupted worktree clones', () => { async (termination) => { const { source, target } = await fixture() const deps: ReflinkCloneDeps = { - randomUUID: () => 'probe', reflinkFileOrFail: async () => {}, reflinkFile: async () => {}, reflinkTree: async (_source, staged) => { @@ -94,7 +93,6 @@ describe('interrupted worktree clones', () => { const { source, target } = await fixture() await expect( cloneWorktreePathWithApfs(source, join(target, 'copy'), true, { - randomUUID: () => 'unused', execFileAsync: async (_file, args) => { if (args[0] === 'probe') { return { stdout: '', stderr: '' } diff --git a/src/main/ipc/worktree-include-copy-budget.test.ts b/src/main/ipc/worktree-include-copy-budget.test.ts index 3603f52ede0..5472b05d6b5 100644 --- a/src/main/ipc/worktree-include-copy-budget.test.ts +++ b/src/main/ipc/worktree-include-copy-budget.test.ts @@ -28,8 +28,7 @@ const NO_REFLINK = { reflinkFileOrFail: async (): Promise => notSupported(), reflinkFile: async (): Promise => notSupported(), reflinkTree: async (): Promise => notSupported(), - publishTree: async (): Promise => notSupported(), - randomUUID: () => 'test' + publishTree: async (): Promise => notSupported() } const posixIt = process.platform === 'win32' ? it.skip : it @@ -457,8 +456,7 @@ describe('createWorktreeCopiedPaths copy budget', () => { const apfsCloneDeps = { execFileAsync: async () => { throw new Error('diskutil unavailable') - }, - randomUUID: () => 'test' + } } const skipped = await createWorktreeCopiedPaths(primary, worktree, ['.env'], { diff --git a/src/main/ipc/worktree-path-materialization.ts b/src/main/ipc/worktree-path-materialization.ts new file mode 100644 index 00000000000..1a070d68ba0 --- /dev/null +++ b/src/main/ipc/worktree-path-materialization.ts @@ -0,0 +1,41 @@ +import { resolveWorktreeIncludePaths } from '../git/worktree-include-file' +import { resolveWorktreeSharedDirectories } from '../git/worktree-shared-directories' +import type { WorktreeCreateTimingRecorder } from '../worktree-create-timing' +import { formatWorktreeIncludeCopyWarning } from './worktree-include-copy-budget' +import { + createWorktreeCopiedPaths, + createWorktreeLinkedPaths, + createWorktreeSharedPaths +} from './worktree-symlinks' + +/** Run on the filesystem owner; configured paths take precedence over YAML and includes. */ +export async function materializeHostWorktreePaths( + source: string, + target: string, + linkedPaths: readonly string[], + time: WorktreeCreateTimingRecorder['time'] = (_phase, operation) => operation() +): Promise { + if (linkedPaths.length) { + await time('create_symlinks', () => createWorktreeLinkedPaths(source, target, linkedPaths)) + } + const [sharedPaths, includePaths] = await Promise.all([ + time('resolve_shared_directories', () => resolveWorktreeSharedDirectories(source)), + time('resolve_worktreeinclude', () => resolveWorktreeIncludePaths(source)) + ]) + if (sharedPaths.length) { + await time('create_shared_directories', () => + createWorktreeSharedPaths(source, target, sharedPaths) + ) + } + if (!includePaths.length) { + return undefined + } + const skipped = await time('copy_worktreeinclude', () => + createWorktreeCopiedPaths(source, target, includePaths) + ) + const warning = formatWorktreeIncludeCopyWarning(skipped) + if (warning) { + console.warn(`[worktree-include] ${warning}`) + } + return warning +} diff --git a/src/main/ipc/worktree-reflink-clone.test.ts b/src/main/ipc/worktree-reflink-clone.test.ts index 759257a0f18..d122c670261 100644 --- a/src/main/ipc/worktree-reflink-clone.test.ts +++ b/src/main/ipc/worktree-reflink-clone.test.ts @@ -47,7 +47,6 @@ function createDeps( cloneError?: string treeError?: string onTree?: (source: string, target: string) => void - uuid?: string } = {} ): ReflinkCloneDeps { return { @@ -72,8 +71,7 @@ function createDeps( }), publishTree: async (source, target) => { cpSync(source, target, { recursive: true, force: false, errorOnExist: false }) - }, - randomUUID: () => options.uuid ?? 'test' + } } } diff --git a/src/main/ipc/worktree-reflink-clone.ts b/src/main/ipc/worktree-reflink-clone.ts index 9697925373b..8b57d97fd88 100644 --- a/src/main/ipc/worktree-reflink-clone.ts +++ b/src/main/ipc/worktree-reflink-clone.ts @@ -1,4 +1,3 @@ -import { randomUUID } from 'node:crypto' import { constants, type Dirent } from 'node:fs' import { chmod, copyFile, link, mkdir, mkdtemp, readdir, rm, rmdir, stat } from 'node:fs/promises' import { dirname, join, sep } from 'node:path' @@ -23,7 +22,6 @@ export type ReflinkCloneDeps = { reflinkTree: (source: string, target: string) => Promise /** Publish an already private tree without copying bytes or replacing files. */ publishTree: (source: string, target: string) => Promise - randomUUID: () => string } // Automatic byte fallback would bypass the materialization's copy budget. @@ -56,8 +54,7 @@ export const defaultReflinkCloneDeps: ReflinkCloneDeps = { if (result.code !== 0) { throw new Error(`cp --link exited ${result.code ?? result.signal}: ${result.stderr.trim()}`) } - }, - randomUUID + } } /** Advisory prediction per filesystem pair; every actual clone must still be strict. */ diff --git a/src/main/ipc/worktree-remote.ts b/src/main/ipc/worktree-remote.ts index c021b576338..3749150f752 100644 --- a/src/main/ipc/worktree-remote.ts +++ b/src/main/ipc/worktree-remote.ts @@ -134,15 +134,8 @@ import { registerCreatedWorktreeRoot, registerWorktreeRootsForRepo } from './registered-worktree-roots-cache' -import { - createWorktreeCopiedPaths, - createWorktreeLinkedPaths, - createWorktreeSharedPaths -} from './worktree-symlinks' -import { formatWorktreeIncludeCopyWarning } from './worktree-include-copy-budget' +import { materializeHostWorktreePaths } from './worktree-path-materialization' import { materializeSshWorktreePaths } from './ssh-worktree-path-materialization' -import { resolveWorktreeIncludePaths } from '../git/worktree-include-file' -import { resolveWorktreeSharedDirectories } from '../git/worktree-shared-directories' import { normalizeSparseDirectories } from './sparse-checkout-directories' import { joinWorktreeRelativePath } from '../runtime/runtime-relative-paths' import type { IFilesystemProvider } from '../providers/types' @@ -2948,55 +2941,19 @@ async function performLocalWorktreeCreate( registerCreatedWorktreeRoot(store, repo.id, created.path) } - let includeCopyWarning: string | undefined - if (localWorktreeGitOptions.wslDistro) { - includeCopyWarning = await materializeWslWorktreePaths( - localWorktreeGitOptions.wslDistro, - repo.path, - created.path, - repo.symlinkPaths ?? [] - ) - } else { - // Why: link user-configured shared paths (e.g. `node_modules`, `.env`) before setup runs so setup scripts see them in place. - const symlinkPaths = repo.symlinkPaths ?? [] - if (symlinkPaths.length > 0) { - await timing.time('create_symlinks', async () => { - await createWorktreeLinkedPaths(repo.path, created.path, symlinkPaths) - }) - } - - // Why: project-level `orca.yaml` shared directories add to (never replace) the per-user - // setting, so a repo's shared dirs reach every teammate (issue #10451). - const [sharedDirectories, includePaths] = await Promise.all([ - timing.time('resolve_shared_directories', () => - resolveWorktreeSharedDirectories(repo.path, localWorktreeGitOptions) - ), - timing.time('resolve_worktreeinclude', () => - resolveWorktreeIncludePaths(repo.path, localWorktreeGitOptions) + const includeCopyWarning = localWorktreeGitOptions.wslDistro + ? await materializeWslWorktreePaths( + localWorktreeGitOptions.wslDistro, + repo.path, + created.path, + repo.symlinkPaths ?? [] + ) + : await materializeHostWorktreePaths( + repo.path, + created.path, + repo.symlinkPaths ?? [], + timing.time ) - ]) - if (sharedDirectories.length > 0) { - await timing.time('create_shared_directories', async () => { - await createWorktreeSharedPaths(repo.path, created.path, sharedDirectories) - }) - } - - // Why: project-level `.worktreeinclude` travels with the repo (issue #7549); copy semantics - // (never symlink) so each worktree owns its files. Paths already linked above are skipped. - if (includePaths.length > 0) { - await timing.time('copy_worktreeinclude', async () => { - const skippedIncludePaths = await createWorktreeCopiedPaths( - repo.path, - created.path, - includePaths - ) - includeCopyWarning = formatWorktreeIncludeCopyWarning(skippedIncludePaths) - if (includeCopyWarning) { - console.warn(`[worktree-include] ${includeCopyWarning}`) - } - }) - } - } // Why: the worktree's base-branch `orca.yaml` is authoritative; we don't re-gate on content parity with the primary checkout since benign divergence silently disabled setup (#1280). let setup: CreateWorktreeResult['setup'] diff --git a/src/main/ipc/worktree-symlinks.test.ts b/src/main/ipc/worktree-symlinks.test.ts index 93998e0f26e..19801e96636 100644 --- a/src/main/ipc/worktree-symlinks.test.ts +++ b/src/main/ipc/worktree-symlinks.test.ts @@ -45,7 +45,6 @@ function notSupported(): never { * decides the outcome. */ function createReflinkCloneDeps(options: { supported: boolean - uuid?: string onReflink?: (source: string, target: string) => void }): ReflinkCloneDepsForTest { return { @@ -65,13 +64,11 @@ function createReflinkCloneDeps(options: { }), publishTree: async (source, target) => { cpSync(source, target, { recursive: true, force: false, errorOnExist: false }) - }, - randomUUID: () => options.uuid ?? 'test' + } } } function createApfsCloneDeps(options: { - uuid?: string onClone?: (args: readonly string[]) => void onProbe?: () => void }): ApfsCloneDepsForTest { @@ -93,7 +90,7 @@ function createApfsCloneDeps(options: { } return { stdout: '', stderr: '' } }) - return { execFileAsync, randomUUID: () => options.uuid ?? 'test' } + return { execFileAsync } } describe('createWorktreeLinkedPaths', () => { @@ -273,7 +270,6 @@ describe('createWorktreeLinkedPaths', () => { writeFileSync(join(primary, '.env'), 'SECRET=1\n') const target = join(worktree, '.env') const deps = createApfsCloneDeps({ - uuid: 'file-race', onClone: (args) => { const tempTarget = args.at(-1) if (!tempTarget) { @@ -550,7 +546,6 @@ describe('createWorktreeLinkedPaths', () => { const target = join(worktree, '.env') const deps = createReflinkCloneDeps({ supported: true, - uuid: 'file-race', onReflink: () => { writeFileSync(target, 'RACE=1\n') } diff --git a/src/main/runtime/runtime-local-worktree-materialization.ts b/src/main/runtime/runtime-local-worktree-materialization.ts index 8b45463a1d0..78ef5e63a08 100644 --- a/src/main/runtime/runtime-local-worktree-materialization.ts +++ b/src/main/runtime/runtime-local-worktree-materialization.ts @@ -6,19 +6,12 @@ import type { GitWorktreeInfo, GitPushTarget, Worktree } from '../../shared/work import type { Repo } from '../../shared/repo-types' import type { CreateWorktreeArgs } from '../../shared/worktree/create-types' import type { TuiAgent } from '../../shared/tui-agent' -import { resolveWorktreeIncludePaths } from '../git/worktree-include-file' -import { formatWorktreeIncludeCopyWarning } from '../ipc/worktree-include-copy-budget' import { getWorktreeCreationLayout, mergeWorktree, resolveWorktreeCreateDisplayNameMeta } from '../ipc/worktree-logic' -import { - createWorktreeCopiedPaths, - createWorktreeLinkedPaths, - createWorktreeSharedPaths -} from '../ipc/worktree-symlinks' -import { resolveWorktreeSharedDirectories } from '../git/worktree-shared-directories' +import { materializeHostWorktreePaths } from '../ipc/worktree-path-materialization' import type { RuntimeManagedWorktreeCreateArgs } from './runtime-managed-worktree-create-types' import type { RemoteTrackingBase } from './runtime-remote-fetch-controller' import type { RuntimeStore } from './runtime-store-contract' @@ -143,29 +136,10 @@ export async function materializeRuntimeLocalWorktree(args: { return { worktree, metadataResult, ...(includeCopyWarning ? { includeCopyWarning } : {}) } } - if ((repo.symlinkPaths ?? []).length > 0) { - await createWorktreeLinkedPaths(repo.path, created.path, repo.symlinkPaths ?? []) - } - // These discoveries are read-only; overlap them, but keep the shared-path - // mutation ahead of include copies below. - const [sharedDirectories, worktreeIncludePaths] = await Promise.all([ - resolveWorktreeSharedDirectories(repo.path, localWorktreeGitOptions), - resolveWorktreeIncludePaths(repo.path, localWorktreeGitOptions) - ]) - if (sharedDirectories.length > 0) { - await createWorktreeSharedPaths(repo.path, created.path, sharedDirectories) - } - if (worktreeIncludePaths.length === 0) { - return { worktree, metadataResult } - } - const skippedIncludePaths = await createWorktreeCopiedPaths( + const includeCopyWarning = await materializeHostWorktreePaths( repo.path, created.path, - worktreeIncludePaths + repo.symlinkPaths ?? [] ) - const includeCopyWarning = formatWorktreeIncludeCopyWarning(skippedIncludePaths) - if (includeCopyWarning) { - console.warn(`[worktree-include] ${includeCopyWarning}`) - } return { worktree, metadataResult, ...(includeCopyWarning ? { includeCopyWarning } : {}) } } diff --git a/src/relay/worktree-path-materialization.test.ts b/src/relay/worktree-path-materialization.test.ts index 48872138fe4..0571b387ffa 100644 --- a/src/relay/worktree-path-materialization.test.ts +++ b/src/relay/worktree-path-materialization.test.ts @@ -11,7 +11,7 @@ afterEach(async () => { }) describe('host-owned worktree path materialization', () => { - it('reads include and sharing configuration from the execution host', async () => { + it('reads host configuration and keeps shared paths ahead of overlapping includes', async () => { const root = await mkdtemp(join(tmpdir(), 'orca-relay-materialization-')) roots.push(root) const source = join(root, 'source') @@ -21,7 +21,7 @@ describe('host-owned worktree path materialization', () => { const initialized = await runProcess({ program: 'git', args: ['init', '-q', source] }) expect(initialized.code).toBe(0) await writeFile(join(source, '.gitignore'), '.env\nshared/\n') - await writeFile(join(source, '.worktreeinclude'), '.env\n') + await writeFile(join(source, '.worktreeinclude'), '.env\nshared\n') await writeFile(join(source, '.env'), 'host-owned value') await mkdir(join(source, 'shared')) await writeFile(join(source, 'shared', 'marker'), 'shared') diff --git a/src/relay/worktree-path-materialization.ts b/src/relay/worktree-path-materialization.ts index 18b261081fc..4f51d7be262 100644 --- a/src/relay/worktree-path-materialization.ts +++ b/src/relay/worktree-path-materialization.ts @@ -1,14 +1,7 @@ import { isAbsolute, resolve } from 'node:path' import { realpath, stat } from 'node:fs/promises' import { expandTilde } from './context' -import { resolveWorktreeIncludePaths } from '../main/git/worktree-include-file' -import { resolveWorktreeSharedDirectories } from '../main/git/worktree-shared-directories' -import { - createWorktreeCopiedPaths, - createWorktreeLinkedPaths, - createWorktreeSharedPaths -} from '../main/ipc/worktree-symlinks' -import { formatWorktreeIncludeCopyWarning } from '../main/ipc/worktree-include-copy-budget' +import { materializeHostWorktreePaths } from '../main/ipc/worktree-path-materialization' import type { WorktreePathMaterializationResult } from '../shared/worktree-path-materialization' export async function materializeRelayWorktreePaths( @@ -37,13 +30,6 @@ export async function materializeRelayWorktreePaths( ) { throw new Error('Worktree materialization requires distinct source and target directories') } - await createWorktreeLinkedPaths(sourcePath, targetPath, linkedPaths) - const [sharedPaths, includePaths] = await Promise.all([ - resolveWorktreeSharedDirectories(sourcePath), - resolveWorktreeIncludePaths(sourcePath) - ]) - await createWorktreeSharedPaths(sourcePath, targetPath, sharedPaths) - const skipped = await createWorktreeCopiedPaths(sourcePath, targetPath, includePaths) - const warning = formatWorktreeIncludeCopyWarning(skipped) + const warning = await materializeHostWorktreePaths(sourcePath, targetPath, linkedPaths) return { supported: true, ...(warning ? { warning } : {}) } } diff --git a/src/renderer/src/components/settings/WorktreeSymlinksSection.tsx b/src/renderer/src/components/settings/WorktreeSymlinksSection.tsx index ff83cc3e4d5..5f351b7b747 100644 --- a/src/renderer/src/components/settings/WorktreeSymlinksSection.tsx +++ b/src/renderer/src/components/settings/WorktreeSymlinksSection.tsx @@ -101,7 +101,7 @@ export function WorktreeSymlinksSection({ {translate( 'auto.components.settings.WorktreeSymlinksSection.4755f120b6', - 'Worktree Shared Paths' + 'Paths for New Worktrees' )}

@@ -217,7 +217,7 @@ export function WorktreeSymlinksSection({

{translate( 'auto.components.settings.WorktreeSymlinksSection.31ebab5403', - 'No shared paths configured for this repository.' + 'No paths configured for this repository.' )}
) : ( @@ -231,7 +231,7 @@ export function WorktreeSymlinksSection({

{translate( 'auto.components.settings.WorktreeSymlinksSection.b814c618e2', - 'Linked paths' + 'Configured paths' )}

diff --git a/src/renderer/src/i18n/locales/en.json b/src/renderer/src/i18n/locales/en.json index 04e9ecf30f7..07336f6d442 100644 --- a/src/renderer/src/i18n/locales/en.json +++ b/src/renderer/src/i18n/locales/en.json @@ -8787,15 +8787,15 @@ }, "WorktreeSymlinksSection": { "1c1e35b219": "Remove {{value0}}", - "b814c618e2": "Linked paths", - "31ebab5403": "No shared paths configured for this repository.", + "b814c618e2": "Configured paths", + "31ebab5403": "No paths configured for this repository.", "ea06227efa": "added", "b2429aeb31": "Add", "ab40b8a5f1": "No matches. Keep typing to add a custom path.", "4cd2a4c077": "Type a path (e.g. .env or node_modules)…", "241325302c": "Add Path", "7ff265071d": "New worktrees get private copy-on-write copies when supported by their host filesystem. Otherwise, these paths link to the primary checkout and share edits.", - "4755f120b6": "Worktree Shared Paths", + "4755f120b6": "Paths for New Worktrees", "b07ef5a8b6": "Paths to materialize from the primary checkout into newly created worktrees.", "d72ba8dc68": "{{value0}} paths", "9ea912d811": "1 path" diff --git a/src/renderer/src/i18n/locales/es.json b/src/renderer/src/i18n/locales/es.json index e5376b58a00..93bef7b2744 100644 --- a/src/renderer/src/i18n/locales/es.json +++ b/src/renderer/src/i18n/locales/es.json @@ -7620,15 +7620,15 @@ }, "WorktreeSymlinksSection": { "1c1e35b219": "Quitar {{value0}}", - "b814c618e2": "Rutas vinculadas", - "31ebab5403": "No hay rutas compartidas configuradas para este repositorio.", + "b814c618e2": "Rutas configuradas", + "31ebab5403": "No hay rutas configuradas para este repositorio.", "ea06227efa": "agregada", "b2429aeb31": "Agregar", "ab40b8a5f1": "No hay coincidencias. Sigue escribiendo para agregar una ruta personalizada.", "4cd2a4c077": "Escribe una ruta (por ejemplo, .env o node_modules)…", "241325302c": "Agregar ruta", "7ff265071d": "Los nuevos worktrees reciben copias privadas mediante copia en escritura cuando el sistema de archivos del host lo permite. De lo contrario, estas rutas enlazan al checkout principal y comparten los cambios.", - "4755f120b6": "Rutas compartidas de worktree", + "4755f120b6": "Rutas para nuevos worktrees", "b07ef5a8b6": "Rutas para materializar desde el checkout principal en worktrees recién creados.", "d72ba8dc68": "{{value0}} rutas", "9ea912d811": "1 ruta" diff --git a/src/renderer/src/i18n/locales/fr.json b/src/renderer/src/i18n/locales/fr.json index c0fef834f20..67123046fcf 100644 --- a/src/renderer/src/i18n/locales/fr.json +++ b/src/renderer/src/i18n/locales/fr.json @@ -8459,15 +8459,15 @@ }, "WorktreeSymlinksSection": { "1c1e35b219": "Supprimer {{value0}}", - "b814c618e2": "Chemins liés", - "31ebab5403": "Aucun chemin partagé configuré pour ce dépôt.", + "b814c618e2": "Chemins configurés", + "31ebab5403": "Aucun chemin configuré pour ce dépôt.", "ea06227efa": "ajouté", "b2429aeb31": "Ajouter", "ab40b8a5f1": "Aucun résultat. Continuez à saisir pour ajouter un chemin personnalisé.", "4cd2a4c077": "Saisissez un chemin (ex. .env ou node_modules)…", "241325302c": "Ajouter un chemin", "7ff265071d": "Les nouveaux worktrees reçoivent des copies privées par copie sur écriture lorsque le système de fichiers de leur hôte le permet. Sinon, ces chemins pointent vers le checkout principal et partagent les modifications.", - "4755f120b6": "Chemins partagés des worktrees", + "4755f120b6": "Chemins pour les nouveaux worktrees", "b07ef5a8b6": "Chemins à matérialiser depuis le checkout principal vers les nouveaux worktrees.", "d72ba8dc68": "{{value0}} chemins", "9ea912d811": "1 chemin" diff --git a/src/renderer/src/i18n/locales/ja.json b/src/renderer/src/i18n/locales/ja.json index aa30795c057..ce1a47b7c88 100644 --- a/src/renderer/src/i18n/locales/ja.json +++ b/src/renderer/src/i18n/locales/ja.json @@ -7642,15 +7642,15 @@ }, "WorktreeSymlinksSection": { "1c1e35b219": "{{value0}} を削除", - "b814c618e2": "リンクされたパス", - "31ebab5403": "このリポジトリには共有パスが設定されていません。", + "b814c618e2": "設定済みのパス", + "31ebab5403": "このリポジトリにはパスが設定されていません。", "ea06227efa": "追加した", "b2429aeb31": "追加", "ab40b8a5f1": "一致はありません。入力を続けてカスタムパスを追加します。", "4cd2a4c077": "パスを入力します (例: .env または node_modules)…", "241325302c": "パスの追加", "7ff265071d": "ホストのファイルシステムが対応している場合、新しいワークツリーには独立したコピーオンライトのコピーが作成されます。それ以外の場合、これらのパスはプライマリチェックアウトへのリンクとなり、編集内容を共有します。", - "4755f120b6": "ワークツリー共有パス", + "4755f120b6": "新しいワークツリーに含めるパス", "b07ef5a8b6": "プライマリチェックアウトから新しく作成されたワークツリーへ配置するパス。", "d72ba8dc68": "{{value0}} パス", "9ea912d811": "1パス" diff --git a/src/renderer/src/i18n/locales/ko.json b/src/renderer/src/i18n/locales/ko.json index 8269513e6cf..8f064fc5cd6 100644 --- a/src/renderer/src/i18n/locales/ko.json +++ b/src/renderer/src/i18n/locales/ko.json @@ -7610,15 +7610,15 @@ }, "WorktreeSymlinksSection": { "1c1e35b219": "{{value0}} 제거", - "b814c618e2": "연결된 경로", - "31ebab5403": "이 repos에 구성된 공유 경로가 없습니다.", + "b814c618e2": "설정된 경로", + "31ebab5403": "이 저장소에 설정된 경로가 없습니다.", "ea06227efa": "추가됨", "b2429aeb31": "추가", "ab40b8a5f1": "일치하는 항목이 없습니다. 사용자 정의 경로를 추가하려면 계속 입력하세요.", "4cd2a4c077": "경로를 입력하세요(예: .env 또는 node_modules)…", "241325302c": "경로 추가", "7ff265071d": "호스트 파일 시스템이 지원하면 새 작업 트리에 독립적인 쓰기 시 복사본을 만듭니다. 지원하지 않으면 이 경로는 기본 체크아웃에 연결되어 변경 사항을 공유합니다.", - "4755f120b6": "작업 트리 공유 경로", + "4755f120b6": "새 워크트리에 포함할 경로", "b07ef5a8b6": "기본 체크아웃에서 새로 생성된 작업 트리에 배치할 경로입니다.", "d72ba8dc68": "경로 {{value0}}개", "9ea912d811": "경로 1개" diff --git a/src/renderer/src/i18n/locales/zh.json b/src/renderer/src/i18n/locales/zh.json index d0522ab2add..9bd0a36cbbd 100644 --- a/src/renderer/src/i18n/locales/zh.json +++ b/src/renderer/src/i18n/locales/zh.json @@ -7671,15 +7671,15 @@ }, "WorktreeSymlinksSection": { "1c1e35b219": "删除 {{value0}}", - "b814c618e2": "链接路径", - "31ebab5403": "此存储库未配置共享路径。", + "b814c618e2": "已配置的路径", + "31ebab5403": "尚未为此仓库配置路径。", "ea06227efa": "额外", "b2429aeb31": "添加", "ab40b8a5f1": "没有匹配项。继续输入以添加自定义路径。", "4cd2a4c077": "输入路径(例如 .env 或 node_modules)...", "241325302c": "添加路径", "7ff265071d": "如果主机文件系统支持,新工作树会获得独立的写时复制副本。否则,这些路径会链接到主检出目录,并共享编辑内容。", - "4755f120b6": "工作树共享路径", + "4755f120b6": "新工作树的路径", "b07ef5a8b6": "从主检出目录放入新建工作树的路径。", "d72ba8dc68": "{{value0}} 路径", "9ea912d811": "1 条路径"