feat(branches): add Merge Branch dialog and confirm flow
publish / Build and publish Ubuntu AppImage (release) Successful in 9m52s
publish / Build and publish Windows installer (release) Successful in 11m10s
publish / Build and publish AUR packages (release) Successful in 19m3s

Introduce a modal dialog to configure and confirm branch merges. It
replaces the old prompt-based workflow and lets users choose a merge
strategy with localized labels. Confirming the dialog runs the merge,
refreshes views, and clears the pending merge target.

- Add a merge dialog UI with strategy options and keyboard support.
- Replace prompt-based merge flow with a state-driven confirm dialog.
- Include CSS for dialog layout, responsive sizing, and styling.
This commit is contained in:
2026-09-01 22:27:59 +02:00
parent add98f962e
commit 106cc98afb
3 changed files with 183 additions and 4 deletions
+22 -4
View File
@@ -27,6 +27,7 @@
import ExplorerPanel from "./lib/components/ExplorerPanel.svelte";
import HistoryPanel from "./lib/components/HistoryPanel.svelte";
import InitRepositoryDialog from "./lib/components/InitRepositoryDialog.svelte";
import MergeBranchDialog from "./lib/components/MergeBranchDialog.svelte";
import NewBranchDialog from "./lib/components/NewBranchDialog.svelte";
import RenameBranchDialog from "./lib/components/RenameBranchDialog.svelte";
import ReflogDialog from "./lib/components/ReflogDialog.svelte";
@@ -169,6 +170,7 @@
GitFileStatus,
GitIgnoreKind,
GitLfsStatus,
MergeStrategy,
GitRepositoryFile,
GitRemote,
PullStrategy,
@@ -391,6 +393,7 @@
let comparisonFromLabel = "";
let comparisonToLabel = "";
let newBranchCommit: GitCommit | null = null;
let mergeBranchTarget: GitBranchInfo | null = null;
let renameBranchTarget: GitBranchInfo | null = null;
let deleteBranchTarget: GitBranchInfo | null = null;
let deleteBranchForce = false;
@@ -3207,11 +3210,15 @@
async function merge(branch: GitBranchInfo) {
if (!activeRepoPath || branch.current) return;
const strategy = (window.prompt("Merge strategy: default, squash, ff-only, or no-ff", "default") ?? "").trim();
if (!strategy) return;
if (!["default", "squash", "ff-only", "no-ff"].includes(strategy)) { errorMessage = "Unknown merge strategy."; return; }
mergeBranchTarget = branch;
}
async function confirmMerge(strategy: MergeStrategy) {
const branch = mergeBranchTarget;
if (!activeRepoPath || !branch || branch.current) return;
await runOperation(`Merging ${branch.name}`, async () => {
applyStatus(await mergeBranch(activeRepoPath, branch.name, strategy as import("./lib/types").MergeStrategy));
applyStatus(await mergeBranch(activeRepoPath, branch.name, strategy));
mergeBranchTarget = null;
await refreshRepositoryViews(activeRepoPath);
trackEvent("branch_merged", {
remote: branch.remote ? 1 : 0,
@@ -5926,6 +5933,17 @@
/>
{/if}
{#if mergeBranchTarget}
<MergeBranchDialog
branch={mergeBranchTarget}
currentBranch={status?.current_branch ?? ""}
{isBusy}
language={appLanguage}
onMerge={confirmMerge}
onClose={() => { if (!isBusy) mergeBranchTarget = null; }}
/>
{/if}
{#if commitNoteTarget}
<CommitNoteDialog
commit={commitNoteTarget}