Remove Merge button from worktrees (#10924)

Co-authored-by: Roo Code <roomote@roocode.com>
This commit is contained in:
Daniel 2026-01-23 16:55:46 -05:00 committed by GitHub
parent 85f42dca83
commit 2d2ed15bfb
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
26 changed files with 2 additions and 604 deletions

View file

@ -9,8 +9,6 @@ export type {
WorktreeResult,
BranchInfo,
CreateWorktreeOptions,
MergeWorktreeOptions,
MergeWorktreeResult,
WorktreeIncludeStatus,
WorktreeListResponse,
WorktreeDefaultsResponse,

View file

@ -9,14 +9,7 @@ import { exec, execFile } from "child_process"
import * as path from "path"
import { promisify } from "util"
import type {
BranchInfo,
CreateWorktreeOptions,
MergeWorktreeOptions,
MergeWorktreeResult,
Worktree,
WorktreeResult,
} from "./types.js"
import type { BranchInfo, CreateWorktreeOptions, Worktree, WorktreeResult } from "./types.js"
const execAsync = promisify(exec)
const execFileAsync = promisify(execFile)
@ -233,128 +226,6 @@ export class WorktreeService {
}
}
/**
* Merge a worktree branch into target branch
*/
async mergeWorktree(cwd: string, options: MergeWorktreeOptions): Promise<MergeWorktreeResult> {
const { worktreePath, targetBranch, deleteAfterMerge } = options
try {
// Get the worktree info to find its branch
const worktrees = await this.listWorktrees(cwd)
const worktree = worktrees.find((wt) => this.normalizePath(wt.path) === this.normalizePath(worktreePath))
if (!worktree) {
return {
success: false,
message: "Worktree not found",
hasConflicts: false,
conflictingFiles: [],
}
}
const sourceBranch = worktree.branch
if (!sourceBranch) {
return {
success: false,
message: "Worktree has detached HEAD - cannot merge",
hasConflicts: false,
conflictingFiles: [],
}
}
// Find the worktree that has the target branch checked out
const targetWorktree = worktrees.find((wt) => wt.branch === targetBranch)
const mergeCwd = targetWorktree ? targetWorktree.path : cwd
// Check for uncommitted changes in source worktree
try {
const { stdout: statusOutput } = await execAsync("git status --porcelain", { cwd: worktreePath })
if (statusOutput.trim()) {
return {
success: false,
message: "Source worktree has uncommitted changes. Please commit or stash them first.",
hasConflicts: false,
conflictingFiles: [],
sourceBranch,
targetBranch,
}
}
} catch {
// Continue if status check fails
}
// Ensure we're on the target branch
await execFileAsync("git", ["checkout", targetBranch], { cwd: mergeCwd })
// Attempt the merge
try {
await execFileAsync("git", ["merge", sourceBranch, "--no-edit"], { cwd: mergeCwd })
// Merge succeeded
if (deleteAfterMerge) {
await this.deleteWorktree(cwd, worktreePath, false)
}
return {
success: true,
message: `Successfully merged ${sourceBranch} into ${targetBranch}`,
hasConflicts: false,
conflictingFiles: [],
sourceBranch,
targetBranch,
}
} catch (mergeError) {
// Check for merge conflicts
try {
const { stdout: conflictOutput } = await execAsync("git diff --name-only --diff-filter=U", {
cwd: mergeCwd,
})
const conflictingFiles = conflictOutput.trim().split("\n").filter(Boolean)
// Abort the merge to leave repo in clean state
await execAsync("git merge --abort", { cwd: mergeCwd })
return {
success: false,
message: `Merge conflicts detected in ${conflictingFiles.length} file(s)`,
hasConflicts: true,
conflictingFiles,
sourceBranch,
targetBranch,
}
} catch {
// If we can't get conflicts, just report the error
const errorMessage = mergeError instanceof Error ? mergeError.message : String(mergeError)
// Try to abort any in-progress merge
try {
await execAsync("git merge --abort", { cwd: mergeCwd })
} catch {
// Ignore abort errors
}
return {
success: false,
message: `Merge failed: ${errorMessage}`,
hasConflicts: false,
conflictingFiles: [],
sourceBranch,
targetBranch,
}
}
}
} catch (error) {
const errorMessage = error instanceof Error ? error.message : String(error)
return {
success: false,
message: `Merge failed: ${errorMessage}`,
hasConflicts: false,
conflictingFiles: [],
}
}
}
/**
* Checkout a branch in the current worktree
*/

View file

@ -107,7 +107,6 @@ export interface ExtensionMessage {
| "worktreeDefaults"
| "worktreeIncludeStatus"
| "branchWorktreeIncludeResult"
| "mergeWorktreeResult"
text?: string
payload?: any // eslint-disable-line @typescript-eslint/no-explicit-any
checkpointWarning?: {
@ -251,10 +250,6 @@ export interface ExtensionMessage {
worktreeIncludeStatus?: WorktreeIncludeStatus
hasGitignore?: boolean
gitignoreContent?: string
hasConflicts?: boolean
conflictingFiles?: string[]
sourceBranch?: string
targetBranch?: string
// branchWorktreeIncludeResult
branch?: string
hasWorktreeInclude?: boolean
@ -605,7 +600,6 @@ export interface WebviewMessage {
| "checkBranchWorktreeInclude"
| "createWorktreeInclude"
| "checkoutBranch"
| "mergeWorktree"
text?: string
editedMessageContent?: string
tab?: "settings" | "history" | "mcp" | "modes" | "chat" | "marketplace" | "cloud"
@ -702,8 +696,6 @@ export interface WebviewMessage {
worktreeCreateNewBranch?: boolean
worktreeForce?: boolean
worktreeNewWindow?: boolean
worktreeTargetBranch?: string
worktreeDeleteAfterMerge?: boolean
worktreeIncludeContent?: string
}

View file

@ -65,36 +65,6 @@ export interface CreateWorktreeOptions {
createNewBranch?: boolean
}
/**
* Options for merging a worktree branch
*/
export interface MergeWorktreeOptions {
/** Path to the worktree being merged */
worktreePath: string
/** Target branch to merge into */
targetBranch: string
/** If true, delete the worktree after successful merge */
deleteAfterMerge?: boolean
}
/**
* Result of a merge operation
*/
export interface MergeWorktreeResult {
/** Whether the merge succeeded */
success: boolean
/** Human-readable message describing the result */
message: string
/** Whether there are merge conflicts */
hasConflicts: boolean
/** List of files with conflicts */
conflictingFiles: string[]
/** Source branch that was merged */
sourceBranch?: string
/** Target branch that was merged into */
targetBranch?: string
}
/**
* Status of .worktreeinclude file
*/

View file

@ -78,7 +78,6 @@ import {
handleCheckBranchWorktreeInclude,
handleCreateWorktreeInclude,
handleCheckoutBranch,
handleMergeWorktree,
} from "./worktree"
export const webviewMessageHandler = async (
@ -3557,38 +3556,6 @@ export const webviewMessageHandler = async (
break
}
case "mergeWorktree": {
try {
const result = await handleMergeWorktree(provider, {
worktreePath: message.worktreePath!,
targetBranch: message.worktreeTargetBranch!,
deleteAfterMerge: message.worktreeDeleteAfterMerge,
})
await provider.postMessageToWebview({
type: "mergeWorktreeResult",
success: result.success,
text: result.message,
hasConflicts: result.hasConflicts,
conflictingFiles: result.conflictingFiles,
sourceBranch: result.sourceBranch,
targetBranch: result.targetBranch,
})
} catch (error) {
const errorMessage = error instanceof Error ? error.message : String(error)
await provider.postMessageToWebview({
type: "mergeWorktreeResult",
success: false,
text: errorMessage,
hasConflicts: false,
conflictingFiles: [],
})
}
break
}
default: {
// console.log(`Unhandled message type: ${message.type}`)
//

View file

@ -12,7 +12,6 @@ import * as os from "os"
import type {
WorktreeResult,
BranchInfo,
MergeWorktreeResult,
WorktreeIncludeStatus,
WorktreeListResponse,
WorktreeDefaultsResponse,
@ -278,15 +277,3 @@ export async function handleCheckoutBranch(provider: ClineProvider, branch: stri
const cwd = provider.cwd
return worktreeService.checkoutBranch(cwd, branch)
}
export async function handleMergeWorktree(
provider: ClineProvider,
options: {
worktreePath: string
targetBranch: string
deleteAfterMerge?: boolean
},
): Promise<MergeWorktreeResult> {
const cwd = provider.cwd
return worktreeService.mergeWorktree(cwd, options)
}

View file

@ -16,7 +16,6 @@ export {
handleCheckBranchWorktreeInclude,
handleCreateWorktreeInclude,
handleCheckoutBranch,
handleMergeWorktree,
} from "./handlers"
// Re-export types from @roo-code/types for convenience

View file

@ -1,6 +1,6 @@
import { useState, useEffect, useCallback } from "react"
import type { Worktree, WorktreeListResponse, MergeWorktreeResult, WorktreeIncludeStatus } from "@roo-code/types"
import type { Worktree, WorktreeListResponse, WorktreeIncludeStatus } from "@roo-code/types"
import { Badge, Button, StandardTooltip } from "@/components/ui"
import { useAppTranslation } from "@/i18n/TranslationContext"
@ -35,13 +35,6 @@ export const WorktreesView = ({ onDone }: WorktreesViewProps) => {
const [showCreateModal, setShowCreateModal] = useState(false)
const [deleteWorktree, setDeleteWorktree] = useState<Worktree | null>(null)
// Merge state
const [mergeWorktree, setMergeWorktree] = useState<Worktree | null>(null)
const [mergeTargetBranch, setMergeTargetBranch] = useState("")
const [mergeDeleteAfter, setMergeDeleteAfter] = useState(false)
const [isMerging, setIsMerging] = useState(false)
const [mergeResult, setMergeResult] = useState<MergeWorktreeResult | null>(null)
// Fetch worktrees list
const fetchWorktrees = useCallback(() => {
vscode.postMessage({ type: "listWorktrees" })
@ -81,22 +74,6 @@ export const WorktreesView = ({ onDone }: WorktreesViewProps) => {
setIsCreatingInclude(false)
break
}
case "mergeWorktreeResult": {
setIsMerging(false)
// Map ExtensionMessage format (text) to MergeWorktreeResult format (message)
setMergeResult({
success: message.success,
message: message.text || "",
hasConflicts: message.hasConflicts || false,
conflictingFiles: message.conflictingFiles || [],
sourceBranch: message.sourceBranch,
targetBranch: message.targetBranch,
})
if (message.success) {
fetchWorktrees()
}
break
}
}
}
@ -146,31 +123,6 @@ export const WorktreesView = ({ onDone }: WorktreesViewProps) => {
})
}, [])
// Handle merge
const handleMerge = useCallback(() => {
if (!mergeWorktree) return
setIsMerging(true)
vscode.postMessage({
type: "mergeWorktree",
worktreePath: mergeWorktree.path,
worktreeTargetBranch: mergeTargetBranch,
worktreeDeleteAfterMerge: mergeDeleteAfter,
})
}, [mergeWorktree, mergeTargetBranch, mergeDeleteAfter])
// Handle "Ask Roo to resolve conflicts"
const handleAskRooResolve = useCallback(() => {
if (!mergeResult) return
// Create a new task with conflict resolution instructions
const conflictMessage = `Please help me resolve merge conflicts in the following files:\n\n${mergeResult.conflictingFiles.map((f) => `- ${f}`).join("\n")}\n\nThe merge was from branch "${mergeResult.sourceBranch}" into "${mergeResult.targetBranch}".`
vscode.postMessage({
type: "newTask",
text: conflictMessage,
})
setMergeWorktree(null)
setMergeResult(null)
}, [mergeResult])
// Render error states
if (!isGitRepo) {
return (
@ -227,9 +179,6 @@ export const WorktreesView = ({ onDone }: WorktreesViewProps) => {
)
}
// Find the primary (bare/main) worktree for merge target.
const primaryWorktree = worktrees.find((w) => w.isBare || worktrees.indexOf(w) === 0)
return (
<Tab>
<TabHeader className="flex flex-col gap-2">
@ -336,22 +285,6 @@ export const WorktreesView = ({ onDone }: WorktreesViewProps) => {
</StandardTooltip>
</>
)}
{!worktree.isBare &&
worktree.branch &&
primaryWorktree &&
worktree.branch !== primaryWorktree.branch && (
<StandardTooltip content={t("worktrees:merge")}>
<Button
variant="ghost"
size="sm"
onClick={() => {
setMergeWorktree(worktree)
setMergeTargetBranch(primaryWorktree.branch || "main")
}}>
<span className="codicon codicon-git-merge" />
</Button>
</StandardTooltip>
)}
{!worktree.isBare && !worktree.isCurrent && (
<StandardTooltip content={t("worktrees:delete")}>
<Button
@ -400,127 +333,6 @@ export const WorktreesView = ({ onDone }: WorktreesViewProps) => {
}}
/>
)}
{/* Merge Modal */}
{mergeWorktree && !mergeResult && (
<div className="fixed inset-0 bg-black/50 flex items-center justify-center z-50">
<div className="bg-vscode-editor-background border border-vscode-panel-border rounded-lg p-4 max-w-md w-full mx-4">
<h3 className="text-lg font-medium text-vscode-foreground mb-4">
{t("worktrees:mergeBranch")}
</h3>
<p className="text-sm text-vscode-descriptionForeground mb-4">
{t("worktrees:mergeDescription", {
source: mergeWorktree.branch,
target: mergeTargetBranch,
})}
</p>
<div className="mb-4">
<label className="flex items-center gap-2 text-sm text-vscode-foreground">
<input
type="checkbox"
checked={mergeDeleteAfter}
onChange={(e) => setMergeDeleteAfter(e.target.checked)}
/>
{t("worktrees:deleteAfterMerge")}
</label>
</div>
<div className="flex justify-end gap-2">
<Button variant="secondary" onClick={() => setMergeWorktree(null)}>
{t("worktrees:cancel")}
</Button>
<Button onClick={handleMerge} disabled={isMerging}>
{isMerging ? (
<>
<span className="codicon codicon-loading codicon-modifier-spin mr-2" />
{t("worktrees:merging")}
</>
) : (
t("worktrees:merge")
)}
</Button>
</div>
</div>
</div>
)}
{/* Merge Result Modal */}
{mergeResult && (
<div className="fixed inset-0 bg-black/50 flex items-center justify-center z-50">
<div className="bg-vscode-editor-background border border-vscode-panel-border rounded-lg p-4 max-w-md w-full mx-4">
{mergeResult.success ? (
<>
<div className="flex items-center gap-2 mb-4">
<span className="codicon codicon-check text-vscode-charts-green text-2xl" />
<h3 className="text-lg font-medium text-vscode-foreground">
{t("worktrees:mergeSuccess")}
</h3>
</div>
<p className="text-sm text-vscode-descriptionForeground mb-4">{mergeResult.message}</p>
<div className="flex justify-end">
<Button
onClick={() => {
setMergeWorktree(null)
setMergeResult(null)
}}>
{t("worktrees:done")}
</Button>
</div>
</>
) : mergeResult.hasConflicts ? (
<>
<div className="flex items-center gap-2 mb-4">
<span className="codicon codicon-warning text-vscode-charts-yellow text-2xl" />
<h3 className="text-lg font-medium text-vscode-foreground">
{t("worktrees:mergeConflicts")}
</h3>
</div>
<p className="text-sm text-vscode-descriptionForeground mb-2">
{t("worktrees:conflictsDescription")}
</p>
<div className="bg-vscode-input-background rounded p-2 mb-4 max-h-32 overflow-y-auto">
{mergeResult.conflictingFiles.map((file) => (
<div key={file} className="text-xs text-vscode-foreground font-mono">
{file}
</div>
))}
</div>
<div className="flex justify-end gap-2">
<Button
variant="secondary"
onClick={() => {
setMergeWorktree(null)
setMergeResult(null)
}}>
{t("worktrees:resolveManually")}
</Button>
<Button onClick={handleAskRooResolve}>{t("worktrees:askRooResolve")}</Button>
</div>
</>
) : (
<>
<div className="flex items-center gap-2 mb-4">
<span className="codicon codicon-error text-vscode-errorForeground text-2xl" />
<h3 className="text-lg font-medium text-vscode-foreground">
{t("worktrees:mergeFailed")}
</h3>
</div>
<p className="text-sm text-vscode-descriptionForeground mb-4">{mergeResult.message}</p>
<div className="flex justify-end">
<Button
onClick={() => {
setMergeWorktree(null)
setMergeResult(null)
}}>
{t("worktrees:close")}
</Button>
</div>
</>
)}
</div>
</div>
)}
</Tab>
)
}

View file

@ -20,7 +20,6 @@
"openInCurrentWindow": "Obre a la finestra actual",
"openInNewWindow": "Obre en una finestra nova",
"merge": "Fusiona",
"delete": "Suprimeix",
"newWorktree": "Worktree nou",
@ -55,15 +54,5 @@
"worktreeIsLocked": "el worktree està bloquejat",
"deleting": "S'està suprimint...",
"mergeBranch": "Fusiona branca",
"mergeDescription": "Fusiona '{{source}}' a '{{target}}'",
"deleteAfterMerge": "Suprimeix el worktree després d'una fusió correcta",
"merging": "S'està fusionant...",
"mergeSuccess": "Fusió correcta",
"mergeConflicts": "Conflictes de fusió",
"conflictsDescription": "Els fitxers següents tenen conflictes que s'han de resoldre:",
"mergeFailed": "Fusió fallida",
"resolveManually": "Ho resoldré manualment",
"askRooResolve": "Demana a Roo que ho resolgui",
"close": "Tanca"
}

View file

@ -20,7 +20,6 @@
"openInCurrentWindow": "Im aktuellen Fenster öffnen",
"openInNewWindow": "In neuem Fenster öffnen",
"merge": "Mergen",
"delete": "Löschen",
"newWorktree": "Neuer Worktree",
@ -55,15 +54,5 @@
"worktreeIsLocked": "Worktree ist gesperrt",
"deleting": "Wird gelöscht...",
"mergeBranch": "Branch mergen",
"mergeDescription": "'{{source}}' in '{{target}}' mergen",
"deleteAfterMerge": "Worktree nach erfolgreichem Merge löschen",
"merging": "Wird gemergt...",
"mergeSuccess": "Merge erfolgreich",
"mergeConflicts": "Merge-Konflikte",
"conflictsDescription": "Die folgenden Dateien haben Konflikte, die gelöst werden müssen:",
"mergeFailed": "Merge fehlgeschlagen",
"resolveManually": "Ich löse das manuell",
"askRooResolve": "Roo zum Lösen fragen",
"close": "Schließen"
}

View file

@ -20,7 +20,6 @@
"openInCurrentWindow": "Open in current window",
"openInNewWindow": "Open in new window",
"merge": "Merge",
"delete": "Delete",
"newWorktree": "New Worktree",
@ -55,15 +54,5 @@
"worktreeIsLocked": "worktree is locked",
"deleting": "Deleting...",
"mergeBranch": "Merge Branch",
"mergeDescription": "Merge '{{source}}' into '{{target}}'",
"deleteAfterMerge": "Delete worktree after successful merge",
"merging": "Merging...",
"mergeSuccess": "Merge Successful",
"mergeConflicts": "Merge Conflicts",
"conflictsDescription": "The following files have conflicts that need to be resolved:",
"mergeFailed": "Merge Failed",
"resolveManually": "I'll Resolve Manually",
"askRooResolve": "Ask Roo to Resolve",
"close": "Close"
}

View file

@ -20,7 +20,6 @@
"openInCurrentWindow": "Abrir en la ventana actual",
"openInNewWindow": "Abrir en una ventana nueva",
"merge": "Fusionar",
"delete": "Eliminar",
"newWorktree": "Nuevo Worktree",
@ -55,15 +54,5 @@
"worktreeIsLocked": "el worktree está bloqueado",
"deleting": "Eliminando...",
"mergeBranch": "Fusionar rama",
"mergeDescription": "Fusionar '{{source}}' en '{{target}}'",
"deleteAfterMerge": "Eliminar el worktree después de una fusión exitosa",
"merging": "Fusionando...",
"mergeSuccess": "Fusión exitosa",
"mergeConflicts": "Conflictos de fusión",
"conflictsDescription": "Los siguientes archivos tienen conflictos que deben resolverse:",
"mergeFailed": "Fusión fallida",
"resolveManually": "Lo resolveré manualmente",
"askRooResolve": "Pedirle a Roo que lo resuelva",
"close": "Cerrar"
}

View file

@ -20,7 +20,6 @@
"openInCurrentWindow": "Ouvrir dans la fenêtre actuelle",
"openInNewWindow": "Ouvrir dans une nouvelle fenêtre",
"merge": "Fusionner",
"delete": "Supprimer",
"newWorktree": "Nouveau Worktree",
@ -55,15 +54,5 @@
"worktreeIsLocked": "le worktree est verrouillé",
"deleting": "Suppression...",
"mergeBranch": "Fusionner la branche",
"mergeDescription": "Fusionner '{{source}}' dans '{{target}}'",
"deleteAfterMerge": "Supprimer le worktree après une fusion réussie",
"merging": "Fusion...",
"mergeSuccess": "Fusion réussie",
"mergeConflicts": "Conflits de fusion",
"conflictsDescription": "Les fichiers suivants ont des conflits à résoudre :",
"mergeFailed": "Échec de la fusion",
"resolveManually": "Je vais le résoudre manuellement",
"askRooResolve": "Demander à Roo de résoudre",
"close": "Fermer"
}

View file

@ -20,7 +20,6 @@
"openInCurrentWindow": "वर्तमान विंडो में खोलें",
"openInNewWindow": "नई विंडो में खोलें",
"merge": "मर्ज",
"delete": "हटाएँ",
"newWorktree": "नया Worktree",
@ -55,15 +54,5 @@
"worktreeIsLocked": "worktree लॉक्ड है",
"deleting": "हटाया जा रहा है...",
"mergeBranch": "ब्रांच मर्ज करें",
"mergeDescription": "'{{source}}' को '{{target}}' में मर्ज करें",
"deleteAfterMerge": "सफल मर्ज के बाद worktree हटाएँ",
"merging": "मर्ज किया जा रहा है...",
"mergeSuccess": "मर्ज सफल",
"mergeConflicts": "मर्ज कॉन्फ्लिक्ट",
"conflictsDescription": "निम्नलिखित फ़ाइलों में कॉन्फ्लिक्ट हैं जिन्हें हल करना होगा:",
"mergeFailed": "मर्ज विफल",
"resolveManually": "मैं मैन्युअली हल करूँगा",
"askRooResolve": "Roo से हल करवाएँ",
"close": "बंद करें"
}

View file

@ -20,7 +20,6 @@
"openInCurrentWindow": "Buka di jendela saat ini",
"openInNewWindow": "Buka di jendela baru",
"merge": "Merge",
"delete": "Hapus",
"newWorktree": "Worktree Baru",
@ -55,15 +54,5 @@
"worktreeIsLocked": "worktree terkunci",
"deleting": "Menghapus...",
"mergeBranch": "Merge Branch",
"mergeDescription": "Merge '{{source}}' ke '{{target}}'",
"deleteAfterMerge": "Hapus worktree setelah merge berhasil",
"merging": "Menggabungkan...",
"mergeSuccess": "Merge Berhasil",
"mergeConflicts": "Konflik Merge",
"conflictsDescription": "File berikut memiliki konflik yang perlu diselesaikan:",
"mergeFailed": "Merge Gagal",
"resolveManually": "Aku akan menyelesaikannya manual",
"askRooResolve": "Minta Roo untuk menyelesaikan",
"close": "Tutup"
}

View file

@ -20,7 +20,6 @@
"openInCurrentWindow": "Apri nella finestra corrente",
"openInNewWindow": "Apri in una nuova finestra",
"merge": "Unisci",
"delete": "Elimina",
"newWorktree": "Nuovo Worktree",
@ -55,15 +54,5 @@
"worktreeIsLocked": "il worktree è bloccato",
"deleting": "Eliminazione...",
"mergeBranch": "Unisci Branch",
"mergeDescription": "Unisci '{{source}}' in '{{target}}'",
"deleteAfterMerge": "Elimina il worktree dopo un merge riuscito",
"merging": "Merge in corso...",
"mergeSuccess": "Merge riuscito",
"mergeConflicts": "Conflitti di merge",
"conflictsDescription": "I seguenti file hanno conflitti che devono essere risolti:",
"mergeFailed": "Merge fallito",
"resolveManually": "Lo risolverò manualmente",
"askRooResolve": "Chiedi a Roo di risolvere",
"close": "Chiudi"
}

View file

@ -20,7 +20,6 @@
"openInCurrentWindow": "現在のウィンドウで開く",
"openInNewWindow": "新しいウィンドウで開く",
"merge": "マージ",
"delete": "削除",
"newWorktree": "新しい Worktree",
@ -55,15 +54,5 @@
"worktreeIsLocked": "worktree がロックされています",
"deleting": "削除中...",
"mergeBranch": "ブランチをマージ",
"mergeDescription": "'{{source}}' を '{{target}}' にマージ",
"deleteAfterMerge": "マージが成功したら worktree を削除",
"merging": "マージ中...",
"mergeSuccess": "マージに成功しました",
"mergeConflicts": "マージの競合",
"conflictsDescription": "次のファイルに解決が必要な競合があります:",
"mergeFailed": "マージに失敗しました",
"resolveManually": "手動で解決する",
"askRooResolve": "Roo に解決を依頼",
"close": "閉じる"
}

View file

@ -20,7 +20,6 @@
"openInCurrentWindow": "현재 창에서 열기",
"openInNewWindow": "새 창에서 열기",
"merge": "병합",
"delete": "삭제",
"newWorktree": "새 Worktree",
@ -55,15 +54,5 @@
"worktreeIsLocked": "worktree가 잠겨 있습니다",
"deleting": "삭제 중...",
"mergeBranch": "브랜치 병합",
"mergeDescription": "'{{source}}'을(를) '{{target}}'에 병합",
"deleteAfterMerge": "병합 성공 후 worktree 삭제",
"merging": "병합 중...",
"mergeSuccess": "병합 성공",
"mergeConflicts": "병합 충돌",
"conflictsDescription": "다음 파일에 해결이 필요한 충돌이 있습니다:",
"mergeFailed": "병합 실패",
"resolveManually": "수동으로 해결할게요",
"askRooResolve": "Roo에게 해결 요청",
"close": "닫기"
}

View file

@ -20,7 +20,6 @@
"openInCurrentWindow": "Openen in huidig venster",
"openInNewWindow": "Openen in nieuw venster",
"merge": "Samenvoegen",
"delete": "Verwijderen",
"newWorktree": "Nieuwe Worktree",
@ -55,15 +54,5 @@
"worktreeIsLocked": "worktree is vergrendeld",
"deleting": "Bezig met verwijderen...",
"mergeBranch": "Branch samenvoegen",
"mergeDescription": "'{{source}}' samenvoegen in '{{target}}'",
"deleteAfterMerge": "Worktree verwijderen na succesvolle merge",
"merging": "Bezig met samenvoegen...",
"mergeSuccess": "Samenvoegen geslaagd",
"mergeConflicts": "Samenvoegconflicten",
"conflictsDescription": "De volgende bestanden hebben conflicten die moeten worden opgelost:",
"mergeFailed": "Samenvoegen mislukt",
"resolveManually": "Ik los het handmatig op",
"askRooResolve": "Roo vragen om op te lossen",
"close": "Sluiten"
}

View file

@ -20,7 +20,6 @@
"openInCurrentWindow": "Otwórz w bieżącym oknie",
"openInNewWindow": "Otwórz w nowym oknie",
"merge": "Scal",
"delete": "Usuń",
"newWorktree": "Nowy Worktree",
@ -55,15 +54,5 @@
"worktreeIsLocked": "worktree jest zablokowany",
"deleting": "Usuwanie...",
"mergeBranch": "Scal Branch",
"mergeDescription": "Scal '{{source}}' do '{{target}}'",
"deleteAfterMerge": "Usuń worktree po udanym scaleniu",
"merging": "Scalanie...",
"mergeSuccess": "Scalanie zakończone sukcesem",
"mergeConflicts": "Konflikty scalania",
"conflictsDescription": "Następujące pliki mają konflikty, które trzeba rozwiązać:",
"mergeFailed": "Scalanie nie powiodło się",
"resolveManually": "Rozwiążę ręcznie",
"askRooResolve": "Poproś Roo o rozwiązanie",
"close": "Zamknij"
}

View file

@ -20,7 +20,6 @@
"openInCurrentWindow": "Abrir na janela atual",
"openInNewWindow": "Abrir em uma nova janela",
"merge": "Mesclar",
"delete": "Excluir",
"newWorktree": "Novo Worktree",
@ -55,15 +54,5 @@
"worktreeIsLocked": "worktree está bloqueado",
"deleting": "Excluindo...",
"mergeBranch": "Mesclar Branch",
"mergeDescription": "Mesclar '{{source}}' em '{{target}}'",
"deleteAfterMerge": "Excluir worktree após mesclagem bem-sucedida",
"merging": "Mesclando...",
"mergeSuccess": "Mesclagem bem-sucedida",
"mergeConflicts": "Conflitos de mesclagem",
"conflictsDescription": "Os seguintes arquivos têm conflitos que precisam ser resolvidos:",
"mergeFailed": "Falha na mesclagem",
"resolveManually": "Vou resolver manualmente",
"askRooResolve": "Pedir ao Roo para resolver",
"close": "Fechar"
}

View file

@ -20,7 +20,6 @@
"openInCurrentWindow": "Открыть в текущем окне",
"openInNewWindow": "Открыть в новом окне",
"merge": "Слить",
"delete": "Удалить",
"newWorktree": "Новый Worktree",
@ -55,15 +54,5 @@
"worktreeIsLocked": "worktree заблокирован",
"deleting": "Удаление...",
"mergeBranch": "Слить ветку",
"mergeDescription": "Слить '{{source}}' в '{{target}}'",
"deleteAfterMerge": "Удалить worktree после успешного слияния",
"merging": "Слияние...",
"mergeSuccess": "Слияние выполнено",
"mergeConflicts": "Конфликты слияния",
"conflictsDescription": "Следующие файлы имеют конфликты, которые нужно разрешить:",
"mergeFailed": "Слияние не удалось",
"resolveManually": "Разрешу вручную",
"askRooResolve": "Попросить Roo разрешить",
"close": "Закрыть"
}

View file

@ -20,7 +20,6 @@
"openInCurrentWindow": "Mevcut pencerede aç",
"openInNewWindow": "Yeni pencerede aç",
"merge": "Birleştir",
"delete": "Sil",
"newWorktree": "Yeni Worktree",
@ -55,15 +54,5 @@
"worktreeIsLocked": "worktree kilitli",
"deleting": "Siliniyor...",
"mergeBranch": "Branch birleştir",
"mergeDescription": "'{{source}}' branch'ini '{{target}}' içine birleştir",
"deleteAfterMerge": "Birleştirme başarılı olursa worktree'yi sil",
"merging": "Birleştiriliyor...",
"mergeSuccess": "Birleştirme başarılı",
"mergeConflicts": "Birleştirme çakışmaları",
"conflictsDescription": "Aşağıdaki dosyalarda çözülmesi gereken çakışmalar var:",
"mergeFailed": "Birleştirme başarısız",
"resolveManually": "Kendim çözeceğim",
"askRooResolve": "Roo'dan çözmesini iste",
"close": "Kapat"
}

View file

@ -20,7 +20,6 @@
"openInCurrentWindow": "Mở trong cửa sổ hiện tại",
"openInNewWindow": "Mở trong cửa sổ mới",
"merge": "Gộp",
"delete": "Xóa",
"newWorktree": "Worktree Mới",
@ -55,15 +54,5 @@
"worktreeIsLocked": "worktree đang bị khóa",
"deleting": "Đang xóa...",
"mergeBranch": "Gộp Nhánh",
"mergeDescription": "Gộp '{{source}}' vào '{{target}}'",
"deleteAfterMerge": "Xóa worktree sau khi gộp thành công",
"merging": "Đang gộp...",
"mergeSuccess": "Gộp thành công",
"mergeConflicts": "Xung đột khi gộp",
"conflictsDescription": "Các tệp sau có xung đột cần được giải quyết:",
"mergeFailed": "Gộp thất bại",
"resolveManually": "Tôi sẽ tự xử lý",
"askRooResolve": "Nhờ Roo xử lý",
"close": "Đóng"
}

View file

@ -20,7 +20,6 @@
"openInCurrentWindow": "在当前窗口打开",
"openInNewWindow": "在新窗口打开",
"merge": "合并",
"delete": "删除",
"newWorktree": "新建 Worktree",
@ -55,15 +54,5 @@
"worktreeIsLocked": "worktree 已锁定",
"deleting": "正在删除...",
"mergeBranch": "合并分支",
"mergeDescription": "将 '{{source}}' 合并到 '{{target}}'",
"deleteAfterMerge": "合并成功后删除 worktree",
"merging": "正在合并...",
"mergeSuccess": "合并成功",
"mergeConflicts": "合并冲突",
"conflictsDescription": "以下文件存在冲突,需要解决:",
"mergeFailed": "合并失败",
"resolveManually": "我来手动解决",
"askRooResolve": "让 Roo 来解决",
"close": "关闭"
}

View file

@ -20,7 +20,6 @@
"openInCurrentWindow": "在目前視窗開啟",
"openInNewWindow": "在新視窗開啟",
"merge": "合併",
"delete": "刪除",
"newWorktree": "新增 Worktree",
@ -55,15 +54,5 @@
"worktreeIsLocked": "worktree 已鎖定",
"deleting": "正在刪除...",
"mergeBranch": "合併分支",
"mergeDescription": "將 '{{source}}' 合併到 '{{target}}'",
"deleteAfterMerge": "合併成功後刪除 worktree",
"merging": "正在合併...",
"mergeSuccess": "合併成功",
"mergeConflicts": "合併衝突",
"conflictsDescription": "以下檔案有衝突需要解決:",
"mergeFailed": "合併失敗",
"resolveManually": "我會手動解決",
"askRooResolve": "請 Roo 協助解決",
"close": "關閉"
}