feat(branches): add force delete flow for local branches
publish / publish-tauri (, windows-latest) (release) Successful in 22m57s

Branch deletion now supports an optional force mode in the Tauri
command, enabling deletion of branches that are not fully merged.
The UI replaces the simple confirm prompt with a dedicated dialog and
auto-escalates to force delete when Git rejects a normal delete.

- Add force flag to delete_branch command and tests
- Implement BranchDeleteConfirmDialog and wire it into App.svelte
- Update branch context menu actions and styling
This commit is contained in:
Christoph Brandau
2026-07-04 00:52:40 +02:00
parent c2d7fefb47
commit 9a4c6e5b9b
6 changed files with 239 additions and 46 deletions
@@ -0,0 +1,80 @@
<script lang="ts">
import { AlertTriangle, GitBranch, LoaderCircle, Trash2, X } from "@lucide/svelte";
import type { GitBranch as GitBranchInfo } from "../types";
interface Props {
branch: GitBranchInfo;
force: boolean;
isBusy: boolean;
onConfirm: () => void | Promise<void>;
onClose: () => void;
}
let {
branch,
force = false,
isBusy = false,
onConfirm = () => {},
onClose = () => {},
}: Props = $props();
let title = $derived(force ? "Force delete branch?" : "Delete branch?");
function closeFromBackdrop(event: MouseEvent) {
if (isBusy || event.target !== event.currentTarget) return;
onClose();
}
</script>
<div class="dialog-backdrop" role="presentation" onclick={closeFromBackdrop}>
<div class="dialog branch-delete-dialog" role="dialog" aria-modal="true" aria-label={title}>
<header class="dialog-header">
<div>
<span class="eyebrow">{force ? "Force delete" : "Delete branch"}</span>
<p class="dialog-title">{title}</p>
</div>
<button class="btn-sm dialog-close" type="button" onclick={onClose} disabled={isBusy} aria-label="Close">
<X size={16} aria-hidden="true" />
</button>
</header>
<div class="branch-delete-body">
<div class="discard-warning-icon" aria-hidden="true">
<AlertTriangle size={22} />
</div>
<div class="discard-confirm-copy">
<p>
{#if force}
This branch is not fully merged. Force deleting removes the branch pointer even if some commits are only reachable from this branch.
{:else}
Delete this local branch from the repository?
{/if}
</p>
<code class="discard-target" title={branch.name}>
<GitBranch size={13} aria-hidden="true" />
{branch.name}
</code>
<p class="discard-warning-text">
{#if force}
Make sure you no longer need the unique commits on this branch.
{:else}
Git will refuse if the branch is not fully merged.
{/if}
</p>
</div>
</div>
<footer class="discard-confirm-actions">
<button class="btn-secondary" type="button" onclick={onClose} disabled={isBusy}>Cancel</button>
<button class="btn-danger" type="button" onclick={onConfirm} disabled={isBusy}>
{#if isBusy}
<LoaderCircle class="spin" size={15} aria-hidden="true" />
{:else}
<Trash2 size={15} aria-hidden="true" />
{/if}
{force ? "Force delete" : "Delete"}
</button>
</footer>
</div>
</div>