From 001cea3eb0692a406766eb34e5927a4a5c240be9 Mon Sep 17 00:00:00 2001 From: Roo Code Date: Thu, 26 Feb 2026 14:39:26 +0000 Subject: [PATCH 1/2] feat: use hard links for file copies when processing .worktreeinclude Adds an optional useHardLinks parameter to copyWorktreeIncludeFiles that creates hard links instead of full copies when the filesystem supports them. This saves disk space and speeds up worktree creation for large directories like node_modules. - Add hardLinkWithFallback method that falls back to copy on failure - Add hardLinkDirectoryRecursive for recursive directory hard-linking - Thread useHardLinks option through handler and message types - Add "Use hard links" checkbox to CreateWorktreeModal (defaults to on) - Add i18n keys for the new UI elements - Add tests for hard link behavior including inode verification Closes #11758 --- .../__tests__/worktree-include.spec.ts | 94 ++++++++++++++ .../core/src/worktree/worktree-include.ts | 120 ++++++++++++++++-- packages/types/src/vscode-extension-host.ts | 1 + src/core/webview/webviewMessageHandler.ts | 1 + src/core/webview/worktree/handlers.ts | 2 + .../worktrees/CreateWorktreeModal.tsx | 24 +++- webview-ui/src/i18n/locales/en/worktrees.json | 2 + 7 files changed, 233 insertions(+), 11 deletions(-) diff --git a/packages/core/src/worktree/__tests__/worktree-include.spec.ts b/packages/core/src/worktree/__tests__/worktree-include.spec.ts index 88069b95da6..743430b38f9 100644 --- a/packages/core/src/worktree/__tests__/worktree-include.spec.ts +++ b/packages/core/src/worktree/__tests__/worktree-include.spec.ts @@ -302,5 +302,99 @@ describe("WorktreeIncludeService", () => { expect(result).toContain("node_modules") }) + + describe("useHardLinks", () => { + it("should hard-link single files when useHardLinks is true", async () => { + await fs.writeFile(path.join(sourceDir, ".worktreeinclude"), ".env.local") + await fs.writeFile(path.join(sourceDir, ".gitignore"), ".env.local") + await fs.writeFile(path.join(sourceDir, ".env.local"), "LOCAL_VAR=value") + + const result = await service.copyWorktreeIncludeFiles(sourceDir, targetDir, undefined, true) + + expect(result).toContain(".env.local") + const copiedContent = await fs.readFile(path.join(targetDir, ".env.local"), "utf-8") + expect(copiedContent).toBe("LOCAL_VAR=value") + + // Verify it's a hard link (same inode) + const sourceStats = await fs.stat(path.join(sourceDir, ".env.local")) + const targetStats = await fs.stat(path.join(targetDir, ".env.local")) + expect(targetStats.ino).toBe(sourceStats.ino) + }) + + it("should hard-link directory contents recursively when useHardLinks is true", async () => { + await fs.writeFile(path.join(sourceDir, ".worktreeinclude"), "node_modules") + await fs.writeFile(path.join(sourceDir, ".gitignore"), "node_modules") + await fs.mkdir(path.join(sourceDir, "node_modules", "pkg"), { recursive: true }) + await fs.writeFile(path.join(sourceDir, "node_modules", "pkg", "index.js"), "module.exports = {}") + await fs.writeFile(path.join(sourceDir, "node_modules", "test.txt"), "test") + + const result = await service.copyWorktreeIncludeFiles(sourceDir, targetDir, undefined, true) + + expect(result).toContain("node_modules") + + // Verify file contents + const copiedContent = await fs.readFile( + path.join(targetDir, "node_modules", "pkg", "index.js"), + "utf-8", + ) + expect(copiedContent).toBe("module.exports = {}") + + // Verify hard links (same inode) + const sourceStats = await fs.stat(path.join(sourceDir, "node_modules", "test.txt")) + const targetStats = await fs.stat(path.join(targetDir, "node_modules", "test.txt")) + expect(targetStats.ino).toBe(sourceStats.ino) + }) + + it("should fall back to copy when hard link fails (e.g., cross-device)", async () => { + // Even if hard linking were to fail, the fallback ensures files are still copied + await fs.writeFile(path.join(sourceDir, ".worktreeinclude"), ".env.local") + await fs.writeFile(path.join(sourceDir, ".gitignore"), ".env.local") + await fs.writeFile(path.join(sourceDir, ".env.local"), "LOCAL_VAR=value") + + // We can't easily simulate cross-device in a unit test, but we can verify + // that when useHardLinks is true, the file is still accessible in the target + const result = await service.copyWorktreeIncludeFiles(sourceDir, targetDir, undefined, true) + + expect(result).toContain(".env.local") + const copiedContent = await fs.readFile(path.join(targetDir, ".env.local"), "utf-8") + expect(copiedContent).toBe("LOCAL_VAR=value") + }) + + it("should perform regular copies when useHardLinks is false", async () => { + await fs.writeFile(path.join(sourceDir, ".worktreeinclude"), ".env.local") + await fs.writeFile(path.join(sourceDir, ".gitignore"), ".env.local") + await fs.writeFile(path.join(sourceDir, ".env.local"), "LOCAL_VAR=value") + + const result = await service.copyWorktreeIncludeFiles(sourceDir, targetDir, undefined, false) + + expect(result).toContain(".env.local") + const copiedContent = await fs.readFile(path.join(targetDir, ".env.local"), "utf-8") + expect(copiedContent).toBe("LOCAL_VAR=value") + + // Verify it's NOT a hard link (different inode for regular copy) + const sourceStats = await fs.stat(path.join(sourceDir, ".env.local")) + const targetStats = await fs.stat(path.join(targetDir, ".env.local")) + expect(targetStats.ino).not.toBe(sourceStats.ino) + }) + + it("should report progress when hard-linking directories", async () => { + await fs.writeFile(path.join(sourceDir, ".worktreeinclude"), "node_modules") + await fs.writeFile(path.join(sourceDir, ".gitignore"), "node_modules") + await fs.mkdir(path.join(sourceDir, "node_modules"), { recursive: true }) + await fs.writeFile(path.join(sourceDir, "node_modules", "test.txt"), "test content") + + const progressCalls: Array<{ bytesCopied: number; itemName: string }> = [] + const onProgress = vi.fn((progress: { bytesCopied: number; itemName: string }) => { + progressCalls.push({ ...progress }) + }) + + await service.copyWorktreeIncludeFiles(sourceDir, targetDir, onProgress, true) + + expect(onProgress).toHaveBeenCalled() + expect(progressCalls.length).toBeGreaterThan(0) + const finalCall = progressCalls[progressCalls.length - 1] + expect(finalCall?.bytesCopied).toBeGreaterThan(0) + }) + }) }) }) diff --git a/packages/core/src/worktree/worktree-include.ts b/packages/core/src/worktree/worktree-include.ts index 09156eb28c2..d40c76f60df 100644 --- a/packages/core/src/worktree/worktree-include.ts +++ b/packages/core/src/worktree/worktree-include.ts @@ -112,12 +112,14 @@ export class WorktreeIncludeService { * @param sourceDir - The source directory containing the files to copy * @param targetDir - The target directory where files will be copied * @param onProgress - Optional callback to report copy progress (size-based) + * @param useHardLinks - If true, use hard links instead of copies when possible (defaults to false) * @returns Array of copied file/directory paths */ async copyWorktreeIncludeFiles( sourceDir: string, targetDir: string, onProgress?: CopyProgressCallback, + useHardLinks?: boolean, ): Promise { const worktreeIncludePath = path.join(sourceDir, ".worktreeinclude") const gitignorePath = path.join(sourceDir, ".gitignore") @@ -180,21 +182,37 @@ export class WorktreeIncludeService { const stats = await fs.stat(sourcePath) if (stats.isDirectory()) { - // Copy directory with progress tracking - bytesCopied = await this.copyDirectoryWithProgress( - sourcePath, - targetPath, - item, - bytesCopied, - onProgress, - ) + if (useHardLinks) { + // Recursively hard-link directory contents + bytesCopied = await this.hardLinkDirectoryWithProgress( + sourcePath, + targetPath, + item, + bytesCopied, + onProgress, + ) + } else { + // Copy directory with progress tracking + bytesCopied = await this.copyDirectoryWithProgress( + sourcePath, + targetPath, + item, + bytesCopied, + onProgress, + ) + } } else { // Report progress before copying onProgress?.({ bytesCopied, itemName: item }) // Ensure parent directory exists await fs.mkdir(path.dirname(targetPath), { recursive: true }) - await fs.copyFile(sourcePath, targetPath) + + if (useHardLinks) { + await this.hardLinkWithFallback(sourcePath, targetPath) + } else { + await fs.copyFile(sourcePath, targetPath) + } // Update bytes copied bytesCopied += this.getSizeOnDisk(stats) @@ -372,6 +390,90 @@ export class WorktreeIncludeService { return bytesCopiedBefore + finalSize } + /** + * Create a hard link for a single file, falling back to copy if hard linking fails + * (e.g., cross-device link, unsupported filesystem, or permissions issue). + */ + private async hardLinkWithFallback(source: string, target: string): Promise { + try { + await fs.link(source, target) + } catch { + // Fallback to regular copy if hard link fails + await fs.copyFile(source, target) + } + } + + /** + * Recursively hard-link all files in a directory from source to target. + * Creates the directory structure with fs.mkdir and hard-links each file. + * Falls back to copyDirectoryWithProgress if the initial hard-link attempt fails. + * Returns the updated bytesCopied count. + */ + private async hardLinkDirectoryWithProgress( + source: string, + target: string, + itemName: string, + bytesCopiedBefore: number, + onProgress?: CopyProgressCallback, + ): Promise { + try { + const bytesCopied = await this.hardLinkDirectoryRecursive( + source, + target, + itemName, + bytesCopiedBefore, + onProgress, + ) + return bytesCopied + } catch { + // If recursive hard-linking fails entirely, fall back to native copy + return this.copyDirectoryWithProgress(source, target, itemName, bytesCopiedBefore, onProgress) + } + } + + /** + * Recursively walk a directory, creating directories and hard-linking files. + * Reports progress as files are linked. + */ + private async hardLinkDirectoryRecursive( + source: string, + target: string, + itemName: string, + bytesCopiedBefore: number, + onProgress?: CopyProgressCallback, + ): Promise { + await fs.mkdir(target, { recursive: true }) + + const entries = await fs.readdir(source, { withFileTypes: true }) + let bytesCopied = bytesCopiedBefore + + for (const entry of entries) { + const sourcePath = path.join(source, entry.name) + const targetPath = path.join(target, entry.name) + + if (entry.isDirectory()) { + bytesCopied = await this.hardLinkDirectoryRecursive( + sourcePath, + targetPath, + itemName, + bytesCopied, + onProgress, + ) + } else if (entry.isFile()) { + await this.hardLinkWithFallback(sourcePath, targetPath) + const stats = await fs.stat(sourcePath) + bytesCopied += this.getSizeOnDisk(stats) + + onProgress?.({ + bytesCopied, + itemName, + }) + } + } + + return bytesCopied + } + /** * Parse a .gitignore-style file and return the patterns */ diff --git a/packages/types/src/vscode-extension-host.ts b/packages/types/src/vscode-extension-host.ts index 253ce3e55d5..cddaf6a8df2 100644 --- a/packages/types/src/vscode-extension-host.ts +++ b/packages/types/src/vscode-extension-host.ts @@ -686,6 +686,7 @@ export interface WebviewMessage { worktreeCreateNewBranch?: boolean worktreeForce?: boolean worktreeNewWindow?: boolean + worktreeUseHardLinks?: boolean worktreeIncludeContent?: string } diff --git a/src/core/webview/webviewMessageHandler.ts b/src/core/webview/webviewMessageHandler.ts index 4ec715cf104..6c47fd32a40 100644 --- a/src/core/webview/webviewMessageHandler.ts +++ b/src/core/webview/webviewMessageHandler.ts @@ -3390,6 +3390,7 @@ export const webviewMessageHandler = async ( copyProgressItemName: progress.itemName, }) }, + message.worktreeUseHardLinks, ) await provider.postMessageToWebview({ type: "worktreeResult", success, text }) diff --git a/src/core/webview/worktree/handlers.ts b/src/core/webview/worktree/handlers.ts index 67c88b910ee..aa6efc7b64d 100644 --- a/src/core/webview/worktree/handlers.ts +++ b/src/core/webview/worktree/handlers.ts @@ -137,6 +137,7 @@ export async function handleCreateWorktree( createNewBranch?: boolean }, onCopyProgress?: CopyProgressCallback, + useHardLinks?: boolean, ): Promise { const cwd = provider.cwd @@ -158,6 +159,7 @@ export async function handleCreateWorktree( cwd, result.worktree.path, onCopyProgress, + useHardLinks, ) if (copiedItems.length > 0) { result.message += ` (copied ${copiedItems.length} item(s) from .worktreeinclude)` diff --git a/webview-ui/src/components/worktrees/CreateWorktreeModal.tsx b/webview-ui/src/components/worktrees/CreateWorktreeModal.tsx index 84743c16503..0e482d8b03e 100644 --- a/webview-ui/src/components/worktrees/CreateWorktreeModal.tsx +++ b/webview-ui/src/components/worktrees/CreateWorktreeModal.tsx @@ -7,7 +7,7 @@ import { vscode } from "@/utils/vscode" import { useAppTranslation } from "@/i18n/TranslationContext" import { Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle, Button, Input } from "@/components/ui" import { SearchableSelect, type SearchableSelectOption } from "@/components/ui/searchable-select" -import { CornerDownRight, Folder, FolderSearch, Info } from "lucide-react" +import { CornerDownRight, Folder, FolderSearch, Info, Link } from "lucide-react" interface CreateWorktreeModalProps { open: boolean @@ -34,6 +34,9 @@ export const CreateWorktreeModal = ({ const [branches, setBranches] = useState(null) const [includeStatus, setIncludeStatus] = useState(null) + // Hard links option + const [useHardLinks, setUseHardLinks] = useState(true) + // UI state const [isCreating, setIsCreating] = useState(false) const [error, setError] = useState(null) @@ -121,8 +124,9 @@ export const CreateWorktreeModal = ({ worktreeBranch: branchName, worktreeBaseBranch: baseBranch, worktreeCreateNewBranch: true, + worktreeUseHardLinks: useHardLinks, }) - }, [worktreePath, branchName, baseBranch]) + }, [worktreePath, branchName, baseBranch, useHardLinks]) const isValid = branchName.trim() && worktreePath.trim() && baseBranch.trim() @@ -215,6 +219,22 @@ export const CreateWorktreeModal = ({ /> + {/* Hard links option - only show when .worktreeinclude exists */} + {includeStatus?.exists && ( +
+ + +
+ )} + {/* Error message */} {error && (
diff --git a/webview-ui/src/i18n/locales/en/worktrees.json b/webview-ui/src/i18n/locales/en/worktrees.json index a9c901ede01..4fe10ae93dc 100644 --- a/webview-ui/src/i18n/locales/en/worktrees.json +++ b/webview-ui/src/i18n/locales/en/worktrees.json @@ -43,6 +43,8 @@ "creating": "Creating...", "copyingFiles": "Copying files...", "copyingProgress": "{{item}} — {{copied}} copied", + "useHardLinks": "Use hard links for included files", + "useHardLinksTooltip": "Creates hard links instead of copies, saving disk space and speeding up worktree creation. Disable if source and target are on different filesystems.", "cancel": "Cancel", "deleteWorktree": "Delete Worktree", From d81072e142631504317345afb7922eaaf7b22c5f Mon Sep 17 00:00:00 2001 From: Roo Code Date: Thu, 26 Feb 2026 15:05:26 +0000 Subject: [PATCH 2/2] feat: add missing worktree hard links translations for all locales --- webview-ui/src/i18n/locales/ca/worktrees.json | 2 ++ webview-ui/src/i18n/locales/de/worktrees.json | 2 ++ webview-ui/src/i18n/locales/es/worktrees.json | 2 ++ webview-ui/src/i18n/locales/fr/worktrees.json | 2 ++ webview-ui/src/i18n/locales/hi/worktrees.json | 2 ++ webview-ui/src/i18n/locales/id/worktrees.json | 2 ++ webview-ui/src/i18n/locales/it/worktrees.json | 2 ++ webview-ui/src/i18n/locales/ja/worktrees.json | 2 ++ webview-ui/src/i18n/locales/ko/worktrees.json | 2 ++ webview-ui/src/i18n/locales/nl/worktrees.json | 2 ++ webview-ui/src/i18n/locales/pl/worktrees.json | 2 ++ webview-ui/src/i18n/locales/pt-BR/worktrees.json | 2 ++ webview-ui/src/i18n/locales/ru/worktrees.json | 2 ++ webview-ui/src/i18n/locales/tr/worktrees.json | 2 ++ webview-ui/src/i18n/locales/vi/worktrees.json | 2 ++ webview-ui/src/i18n/locales/zh-CN/worktrees.json | 2 ++ webview-ui/src/i18n/locales/zh-TW/worktrees.json | 2 ++ 17 files changed, 34 insertions(+) diff --git a/webview-ui/src/i18n/locales/ca/worktrees.json b/webview-ui/src/i18n/locales/ca/worktrees.json index e84c8a716bf..d1afb419740 100644 --- a/webview-ui/src/i18n/locales/ca/worktrees.json +++ b/webview-ui/src/i18n/locales/ca/worktrees.json @@ -43,6 +43,8 @@ "creating": "S'està creant...", "copyingFiles": "S'estan copiant fitxers...", "copyingProgress": "{{item}} — {{copied}} copiat", + "useHardLinks": "Utilitza enllaços durs per als fitxers inclosos", + "useHardLinksTooltip": "Crea enllaços durs en lloc de còpies, estalviant espai de disc i accelerant la creació del worktree. Desactiva-ho si l'origen i el destí són en sistemes de fitxers diferents.", "cancel": "Cancel·la", "deleteWorktree": "Suprimeix worktree", diff --git a/webview-ui/src/i18n/locales/de/worktrees.json b/webview-ui/src/i18n/locales/de/worktrees.json index eed464fd5ee..c9aa52da258 100644 --- a/webview-ui/src/i18n/locales/de/worktrees.json +++ b/webview-ui/src/i18n/locales/de/worktrees.json @@ -43,6 +43,8 @@ "creating": "Wird erstellt...", "copyingFiles": "Dateien werden kopiert...", "copyingProgress": "{{item}} — {{copied}} kopiert", + "useHardLinks": "Hardlinks für eingeschlossene Dateien verwenden", + "useHardLinksTooltip": "Erstellt Hardlinks statt Kopien, spart Speicherplatz und beschleunigt die Worktree-Erstellung. Deaktiviere dies, wenn Quelle und Ziel auf verschiedenen Dateisystemen liegen.", "cancel": "Abbrechen", "deleteWorktree": "Worktree löschen", diff --git a/webview-ui/src/i18n/locales/es/worktrees.json b/webview-ui/src/i18n/locales/es/worktrees.json index f78203d06db..f63ae0dda8d 100644 --- a/webview-ui/src/i18n/locales/es/worktrees.json +++ b/webview-ui/src/i18n/locales/es/worktrees.json @@ -43,6 +43,8 @@ "creating": "Creando...", "copyingFiles": "Copiando archivos...", "copyingProgress": "{{item}} — {{copied}} copiado", + "useHardLinks": "Usar enlaces duros para archivos incluidos", + "useHardLinksTooltip": "Crea enlaces duros en lugar de copias, ahorrando espacio en disco y acelerando la creación del worktree. Desactívalo si el origen y el destino están en sistemas de archivos diferentes.", "cancel": "Cancelar", "deleteWorktree": "Eliminar Worktree", diff --git a/webview-ui/src/i18n/locales/fr/worktrees.json b/webview-ui/src/i18n/locales/fr/worktrees.json index 2cc8bfca0dd..d1ecb0fc0e9 100644 --- a/webview-ui/src/i18n/locales/fr/worktrees.json +++ b/webview-ui/src/i18n/locales/fr/worktrees.json @@ -43,6 +43,8 @@ "creating": "Création...", "copyingFiles": "Copie des fichiers...", "copyingProgress": "{{item}} — {{copied}} copié", + "useHardLinks": "Utiliser des liens physiques pour les fichiers inclus", + "useHardLinksTooltip": "Crée des liens physiques au lieu de copies, économisant de l'espace disque et accélérant la création du worktree. Désactive cette option si la source et la cible sont sur des systèmes de fichiers différents.", "cancel": "Annuler", "deleteWorktree": "Supprimer le worktree", diff --git a/webview-ui/src/i18n/locales/hi/worktrees.json b/webview-ui/src/i18n/locales/hi/worktrees.json index e568c3844d7..5864df06f52 100644 --- a/webview-ui/src/i18n/locales/hi/worktrees.json +++ b/webview-ui/src/i18n/locales/hi/worktrees.json @@ -43,6 +43,8 @@ "creating": "बनाया जा रहा है...", "copyingFiles": "फ़ाइलें कॉपी की जा रही हैं...", "copyingProgress": "{{item}} — {{copied}} कॉपी किया गया", + "useHardLinks": "शामिल फ़ाइलों के लिए हार्ड लिंक का उपयोग करें", + "useHardLinksTooltip": "कॉपी के बजाय हार्ड लिंक बनाता है, डिस्क स्थान बचाता है और worktree निर्माण को तेज़ करता है। यदि स्रोत और लक्ष्य अलग-अलग फ़ाइल सिस्टम पर हैं तो इसे अक्षम करें।", "cancel": "रद्द करें", "deleteWorktree": "Worktree हटाएँ", diff --git a/webview-ui/src/i18n/locales/id/worktrees.json b/webview-ui/src/i18n/locales/id/worktrees.json index f3dc9449160..217976a8ebb 100644 --- a/webview-ui/src/i18n/locales/id/worktrees.json +++ b/webview-ui/src/i18n/locales/id/worktrees.json @@ -43,6 +43,8 @@ "creating": "Membuat...", "copyingFiles": "Menyalin file...", "copyingProgress": "{{item}} — {{copied}} disalin", + "useHardLinks": "Gunakan hard link untuk file yang disertakan", + "useHardLinksTooltip": "Membuat hard link alih-alih salinan, menghemat ruang disk dan mempercepat pembuatan worktree. Nonaktifkan jika sumber dan target berada di sistem file yang berbeda.", "cancel": "Batal", "deleteWorktree": "Hapus Worktree", diff --git a/webview-ui/src/i18n/locales/it/worktrees.json b/webview-ui/src/i18n/locales/it/worktrees.json index dda88fa53c1..6924dbbee00 100644 --- a/webview-ui/src/i18n/locales/it/worktrees.json +++ b/webview-ui/src/i18n/locales/it/worktrees.json @@ -43,6 +43,8 @@ "creating": "Creazione...", "copyingFiles": "Copia dei file...", "copyingProgress": "{{item}} — {{copied}} copiato", + "useHardLinks": "Usa hard link per i file inclusi", + "useHardLinksTooltip": "Crea hard link invece di copie, risparmiando spazio su disco e velocizzando la creazione del worktree. Disattiva se origine e destinazione sono su filesystem diversi.", "cancel": "Annulla", "deleteWorktree": "Elimina Worktree", diff --git a/webview-ui/src/i18n/locales/ja/worktrees.json b/webview-ui/src/i18n/locales/ja/worktrees.json index f07bd3ea48c..142a3e2c11d 100644 --- a/webview-ui/src/i18n/locales/ja/worktrees.json +++ b/webview-ui/src/i18n/locales/ja/worktrees.json @@ -43,6 +43,8 @@ "creating": "作成中...", "copyingFiles": "ファイルをコピー中...", "copyingProgress": "{{item}} — {{copied}} コピー済み", + "useHardLinks": "インクルードファイルにハードリンクを使用する", + "useHardLinksTooltip": "コピーの代わりにハードリンクを作成し、ディスク容量を節約してworktreeの作成を高速化します。ソースとターゲットが異なるファイルシステムにある場合は無効にしてください。", "cancel": "キャンセル", "deleteWorktree": "Worktree を削除", diff --git a/webview-ui/src/i18n/locales/ko/worktrees.json b/webview-ui/src/i18n/locales/ko/worktrees.json index 388a508a9b5..8ba0c8dc21e 100644 --- a/webview-ui/src/i18n/locales/ko/worktrees.json +++ b/webview-ui/src/i18n/locales/ko/worktrees.json @@ -43,6 +43,8 @@ "creating": "만드는 중...", "copyingFiles": "파일 복사 중...", "copyingProgress": "{{item}} — {{copied}} 복사됨", + "useHardLinks": "포함된 파일에 하드 링크 사용", + "useHardLinksTooltip": "복사 대신 하드 링크를 생성하여 디스크 공간을 절약하고 worktree 생성 속도를 높입니다. 소스와 대상이 다른 파일 시스템에 있는 경우 비활성화하세요.", "cancel": "취소", "deleteWorktree": "Worktree 삭제", diff --git a/webview-ui/src/i18n/locales/nl/worktrees.json b/webview-ui/src/i18n/locales/nl/worktrees.json index 8602d48527d..5ca64fa1769 100644 --- a/webview-ui/src/i18n/locales/nl/worktrees.json +++ b/webview-ui/src/i18n/locales/nl/worktrees.json @@ -43,6 +43,8 @@ "creating": "Bezig met aanmaken...", "copyingFiles": "Bestanden kopiëren...", "copyingProgress": "{{item}} — {{copied}} gekopieerd", + "useHardLinks": "Gebruik harde links voor meegeleverde bestanden", + "useHardLinksTooltip": "Maakt harde links aan in plaats van kopieën, bespaart schijfruimte en versnelt het aanmaken van de worktree. Schakel uit als bron en doel op verschillende bestandssystemen staan.", "cancel": "Annuleren", "deleteWorktree": "Worktree verwijderen", diff --git a/webview-ui/src/i18n/locales/pl/worktrees.json b/webview-ui/src/i18n/locales/pl/worktrees.json index 58fa26f7ac1..a0b0be89fe1 100644 --- a/webview-ui/src/i18n/locales/pl/worktrees.json +++ b/webview-ui/src/i18n/locales/pl/worktrees.json @@ -43,6 +43,8 @@ "creating": "Tworzenie...", "copyingFiles": "Kopiowanie plików...", "copyingProgress": "{{item}} — {{copied}} skopiowano", + "useHardLinks": "Użyj twardych dowiązań dla dołączonych plików", + "useHardLinksTooltip": "Tworzy twarde dowiązania zamiast kopii, oszczędzając miejsce na dysku i przyspieszając tworzenie worktree. Wyłącz, jeśli źródło i cel znajdują się na różnych systemach plików.", "cancel": "Anuluj", "deleteWorktree": "Usuń Worktree", diff --git a/webview-ui/src/i18n/locales/pt-BR/worktrees.json b/webview-ui/src/i18n/locales/pt-BR/worktrees.json index 4e438d6a9c4..b1de478d32c 100644 --- a/webview-ui/src/i18n/locales/pt-BR/worktrees.json +++ b/webview-ui/src/i18n/locales/pt-BR/worktrees.json @@ -43,6 +43,8 @@ "creating": "Criando...", "copyingFiles": "Copiando arquivos...", "copyingProgress": "{{item}} — {{copied}} copiado", + "useHardLinks": "Usar hard links para arquivos incluídos", + "useHardLinksTooltip": "Cria hard links em vez de cópias, economizando espaço em disco e acelerando a criação do worktree. Desative se a origem e o destino estiverem em sistemas de arquivos diferentes.", "cancel": "Cancelar", "deleteWorktree": "Excluir Worktree", diff --git a/webview-ui/src/i18n/locales/ru/worktrees.json b/webview-ui/src/i18n/locales/ru/worktrees.json index a3ea03c3ef4..f4b9c5ae906 100644 --- a/webview-ui/src/i18n/locales/ru/worktrees.json +++ b/webview-ui/src/i18n/locales/ru/worktrees.json @@ -43,6 +43,8 @@ "creating": "Создание...", "copyingFiles": "Копирование файлов...", "copyingProgress": "{{item}} — {{copied}} скопировано", + "useHardLinks": "Использовать жёсткие ссылки для включённых файлов", + "useHardLinksTooltip": "Создаёт жёсткие ссылки вместо копий, экономя место на диске и ускоряя создание worktree. Отключи, если источник и цель находятся на разных файловых системах.", "cancel": "Отмена", "deleteWorktree": "Удалить Worktree", diff --git a/webview-ui/src/i18n/locales/tr/worktrees.json b/webview-ui/src/i18n/locales/tr/worktrees.json index 50e5a3ba827..ae79db13d76 100644 --- a/webview-ui/src/i18n/locales/tr/worktrees.json +++ b/webview-ui/src/i18n/locales/tr/worktrees.json @@ -43,6 +43,8 @@ "creating": "Oluşturuluyor...", "copyingFiles": "Dosyalar kopyalanıyor...", "copyingProgress": "{{item}} — {{copied}} kopyalandı", + "useHardLinks": "Dahil edilen dosyalar için sabit bağlantı kullan", + "useHardLinksTooltip": "Kopya yerine sabit bağlantılar oluşturur, disk alanından tasarruf sağlar ve worktree oluşturmayı hızlandırır. Kaynak ve hedef farklı dosya sistemlerindeyse devre dışı bırak.", "cancel": "İptal", "deleteWorktree": "Worktree'yi sil", diff --git a/webview-ui/src/i18n/locales/vi/worktrees.json b/webview-ui/src/i18n/locales/vi/worktrees.json index 28b80891c69..c0f82ffab0e 100644 --- a/webview-ui/src/i18n/locales/vi/worktrees.json +++ b/webview-ui/src/i18n/locales/vi/worktrees.json @@ -43,6 +43,8 @@ "creating": "Đang tạo...", "copyingFiles": "Đang sao chép tệp...", "copyingProgress": "{{item}} — {{copied}} đã sao chép", + "useHardLinks": "Sử dụng liên kết cứng cho các tệp được bao gồm", + "useHardLinksTooltip": "Tạo liên kết cứng thay vì bản sao, tiết kiệm dung lượng đĩa và tăng tốc tạo worktree. Tắt nếu nguồn và đích nằm trên các hệ thống tệp khác nhau.", "cancel": "Hủy", "deleteWorktree": "Xóa Worktree", diff --git a/webview-ui/src/i18n/locales/zh-CN/worktrees.json b/webview-ui/src/i18n/locales/zh-CN/worktrees.json index 2ff06dd9a77..298817e6526 100644 --- a/webview-ui/src/i18n/locales/zh-CN/worktrees.json +++ b/webview-ui/src/i18n/locales/zh-CN/worktrees.json @@ -43,6 +43,8 @@ "creating": "正在创建...", "copyingFiles": "正在复制文件...", "copyingProgress": "{{item}} — {{copied}} 已复制", + "useHardLinks": "为包含的文件使用硬链接", + "useHardLinksTooltip": "创建硬链接而非副本,节省磁盘空间并加快 worktree 创建速度。如果源和目标位于不同的文件系统上,请禁用此选项。", "cancel": "取消", "deleteWorktree": "删除 Worktree", diff --git a/webview-ui/src/i18n/locales/zh-TW/worktrees.json b/webview-ui/src/i18n/locales/zh-TW/worktrees.json index fe80cfb214b..2cecaa12b22 100644 --- a/webview-ui/src/i18n/locales/zh-TW/worktrees.json +++ b/webview-ui/src/i18n/locales/zh-TW/worktrees.json @@ -43,6 +43,8 @@ "creating": "正在建立...", "copyingFiles": "正在複製檔案...", "copyingProgress": "{{item}} — {{copied}} 已複製", + "useHardLinks": "為包含的檔案使用硬連結", + "useHardLinksTooltip": "建立硬連結而非副本,節省磁碟空間並加快 worktree 建立速度。如果來源和目標位於不同的檔案系統上,請停用此選項。", "cancel": "取消", "deleteWorktree": "刪除 Worktree",