From df54597cc3789336359bf4d878c49dfafac9a894 Mon Sep 17 00:00:00 2001 From: Jinjing <6427696+AmethystLiang@users.noreply.github.com> Date: Thu, 9 Apr 2026 13:37:20 -0700 Subject: [PATCH] fix: address review findings (#422) --- .../sidebar/DeleteWorktreeDialog.tsx | 51 +++++++++++++----- .../src/components/sidebar/WorktreeCard.tsx | 52 ++++++++++++++++--- .../sidebar/WorktreeContextMenu.tsx | 15 +++++- 3 files changed, 98 insertions(+), 20 deletions(-) diff --git a/src/renderer/src/components/sidebar/DeleteWorktreeDialog.tsx b/src/renderer/src/components/sidebar/DeleteWorktreeDialog.tsx index 1e84f7532d9..872c1dae81a 100644 --- a/src/renderer/src/components/sidebar/DeleteWorktreeDialog.tsx +++ b/src/renderer/src/components/sidebar/DeleteWorktreeDialog.tsx @@ -34,6 +34,10 @@ const DeleteWorktreeDialog = React.memo(function DeleteWorktreeDialog() { const deleteError = deleteState?.error ?? null const canForceDelete = deleteState?.canForceDelete ?? false const worktreeName = worktree?.displayName ?? 'unknown' + // Why: the main worktree is the repo's original clone directory — `git worktree remove` + // always rejects it. We block the delete button upfront so the user doesn't have to + // discover this limitation via a confusing force-delete dead-end. + const isMainWorktree = worktree?.isMainWorktree ?? false useEffect(() => { if (isOpen && worktreeId && !worktree && !isDeleting) { @@ -127,7 +131,19 @@ const DeleteWorktreeDialog = React.memo(function DeleteWorktreeDialog() { )} - {deleteError && ( + {isMainWorktree && ( +
+
+ +
+ This is the main worktree (the original clone + directory). Git does not allow removing the main worktree. +
+
+
+ )} + + {deleteError && !isMainWorktree && (
@@ -138,19 +154,28 @@ const DeleteWorktreeDialog = React.memo(function DeleteWorktreeDialog() { - {canForceDelete ? ( - - ) : ( - - )} + {!isMainWorktree && + (canForceDelete ? ( + + ) : ( + + ))} diff --git a/src/renderer/src/components/sidebar/WorktreeCard.tsx b/src/renderer/src/components/sidebar/WorktreeCard.tsx index ce389d5a4d7..278bc3cb2f3 100644 --- a/src/renderer/src/components/sidebar/WorktreeCard.tsx +++ b/src/renderer/src/components/sidebar/WorktreeCard.tsx @@ -351,6 +351,9 @@ const WorktreeCard = React.memo(function WorktreeCard({
)} + {/* Branch / folder badge — unchanged from the original logic so we + never lose the branch name, even when the main worktree is checked + out on a non-primary branch like "feature-x". */} {isFolder ? ( ) : isPrimaryBranch(worktree.branch) ? ( - - main - + worktree.isMainWorktree ? ( + + + + main + + + + Main worktree + + + ) : ( + + main + + ) ) : ( {branch} )} + {/* Why: the main worktree (the original clone directory) cannot be + deleted via `git worktree remove`. Surfacing this in the card lets + users identify it at a glance. When the branch is already primary, + the blue "main" badge above does double duty; otherwise we add a + separate blue badge so both the branch and worktree type are visible. */} + {worktree.isMainWorktree && !isFolder && !isPrimaryBranch(worktree.branch) && ( + + + + main + + + + Main worktree + + + )} + {/* Why: the conflict operation (merge/rebase/cherry-pick) is the only signal that the worktree is in an incomplete operation state. Showing it on the card lets the user spot worktrees that need diff --git a/src/renderer/src/components/sidebar/WorktreeContextMenu.tsx b/src/renderer/src/components/sidebar/WorktreeContextMenu.tsx index 2a9ddee0382..c1b8869890b 100644 --- a/src/renderer/src/components/sidebar/WorktreeContextMenu.tsx +++ b/src/renderer/src/components/sidebar/WorktreeContextMenu.tsx @@ -176,7 +176,20 @@ const WorktreeContextMenu = React.memo(function WorktreeContextMenu({ worktree, Shutdown - + {/* Why: `git worktree remove` always rejects the main worktree, so we + disable the item upfront. Radix forwards unknown props to the DOM + element, so `title` works directly without a wrapper span — this + preserves Radix's flat roving-tabindex keyboard navigation. */} + {isDeleting ? 'Deleting…' : isFolder ? 'Remove Folder from Orca' : 'Delete'}