feat(git): rename remote branches atomically via push

Adds a new command to rename remote branches and update tracking refs.
Renaming remote refs is performed atomically using a single push.
The push creates the new remote ref and deletes the old if it succeeds.
The frontend now invokes remote-rename when needed and shows labels.

- Atomic remote rename via push with create/ref and delete
- Frontend supports remote branch renames from the branch panel
- Compare UI now shows labels for remote refs in results
This commit is contained in:
Christoph Brandau
2026-08-13 18:32:16 +02:00
parent ca14fac90c
commit f43fe00873
11 changed files with 447 additions and 71 deletions
+17 -4
View File
@@ -1,5 +1,5 @@
<script lang="ts">
import { Check, ChevronDown, ChevronRight, Folder, FolderOpen, GitBranch, GitMerge, HardDrive, Pencil, Plus, Tag as TagIcon, Trash2, Upload, X } from "@lucide/svelte";
import { Check, ChevronDown, ChevronRight, Folder, FolderOpen, GitBranch, GitCompare, GitMerge, HardDrive, Pencil, Plus, Tag as TagIcon, Trash2, Upload, X } from "@lucide/svelte";
import type { GitBranch as GitBranchInfo, GitTag } from "../types";
type BranchTreeNode = BranchFolderNode | BranchLeafNode;
@@ -49,6 +49,7 @@
hasRepository: boolean;
isBusy: boolean;
onCheckout: (branch: GitBranchInfo) => void;
onCompareBranch: (branch: GitBranchInfo) => void;
onMerge: (branch: GitBranchInfo) => void;
onRebase: (branch: GitBranchInfo) => void;
onCreateBranch: (branchName: string) => void | Promise<void>;
@@ -72,6 +73,7 @@
hasRepository = false,
isBusy = false,
onCheckout = () => {},
onCompareBranch = () => {},
onMerge = () => {},
onRebase = () => {},
onCreateBranch = () => {},
@@ -250,7 +252,7 @@
const rawX = rect ? event.clientX - rect.left : event.offsetX;
const rawY = rect ? event.clientY - rect.top : event.offsetY;
const maxX = Math.max(8, (rect?.width ?? window.innerWidth) - 192);
const maxY = Math.max(8, (rect?.height ?? window.innerHeight) - 190);
const maxY = Math.max(8, (rect?.height ?? window.innerHeight) - 226);
contextBranch = branch;
contextMenuX = Math.max(8, Math.min(rawX, maxX));
@@ -268,6 +270,13 @@
await onRenameBranch(branch);
}
function compareContextBranch() {
const branch = contextBranch;
if (!branch || isBusy) return;
closeBranchContextMenu();
onCompareBranch(branch);
}
async function deleteContextBranch() {
const branch = contextBranch;
if (!branch || branch.current || isBusy) return;
@@ -677,6 +686,10 @@
<GitBranch size={14} aria-hidden="true" />
Checkout
</button>
<button type="button" role="menuitem" onclick={compareContextBranch} disabled={isBusy}>
<GitCompare size={14} aria-hidden="true" />
Compare with...
</button>
<button type="button" role="menuitem" onclick={mergeContextBranch} disabled={isBusy || contextBranch.current}>
<GitMerge size={14} aria-hidden="true" />
Merge into current
@@ -690,9 +703,9 @@
Open in new worktree
</button>
<div class="menu-separator" role="separator"></div>
<button type="button" role="menuitem" onclick={renameContextBranch} disabled={isBusy || contextBranch.remote}>
<button type="button" role="menuitem" onclick={renameContextBranch} disabled={isBusy}>
<Pencil size={14} aria-hidden="true" />
Rename
{contextBranch.remote ? "Rename remote..." : "Rename"}
</button>
<button
class="danger"