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
102 lines
3.1 KiB
Svelte
102 lines
3.1 KiB
Svelte
<script lang="ts">
|
|
import { GitBranch, LoaderCircle, X } from "@lucide/svelte";
|
|
import type { GitBranch as GitBranchInfo } from "../types";
|
|
|
|
interface Props {
|
|
branch: GitBranchInfo;
|
|
isBusy: boolean;
|
|
onRename: (name: string) => void;
|
|
onClose: () => void;
|
|
}
|
|
|
|
let {
|
|
branch,
|
|
isBusy = false,
|
|
onRename = () => {},
|
|
onClose = () => {},
|
|
}: Props = $props();
|
|
|
|
let name = $state("");
|
|
|
|
function remoteName(branch: GitBranchInfo): string {
|
|
if (!branch.remote) return "";
|
|
const slash = branch.name.indexOf("/");
|
|
return slash > 0 ? branch.name.slice(0, slash) : branch.name;
|
|
}
|
|
|
|
function editableName(branch: GitBranchInfo): string {
|
|
if (!branch.remote) return branch.name;
|
|
const slash = branch.name.indexOf("/");
|
|
return slash >= 0 ? branch.name.slice(slash + 1) : branch.name;
|
|
}
|
|
|
|
let originalName = $derived(editableName(branch));
|
|
let remote = $derived(remoteName(branch));
|
|
|
|
$effect(() => {
|
|
name = originalName;
|
|
});
|
|
|
|
function submit(event: SubmitEvent) {
|
|
event.preventDefault();
|
|
const value = name.trim();
|
|
if (!value || value === originalName) return;
|
|
onRename(value);
|
|
}
|
|
</script>
|
|
|
|
<div
|
|
class="dialog-backdrop"
|
|
role="presentation"
|
|
>
|
|
<div class="dialog rename-branch-dialog" role="dialog" aria-modal="true" aria-label={branch.remote ? "Rename remote branch" : "Rename branch"} tabindex="-1">
|
|
<header class="dialog-header">
|
|
<div>
|
|
<span class="eyebrow">{branch.remote ? "Rename remote branch" : "Rename branch"}</span>
|
|
<h2 class="mt-0.5 text-ink text-base font-bold leading-tight">{branch.name}</h2>
|
|
</div>
|
|
<button class="dialog-close" type="button" onclick={onClose} title="Close">
|
|
<X size={18} aria-hidden="true" />
|
|
</button>
|
|
</header>
|
|
|
|
<form class="rename-branch-form" onsubmit={submit}>
|
|
<label class="new-branch-field">
|
|
<span>Branch name</span>
|
|
<div class:remote-branch-name-field={branch.remote}>
|
|
{#if branch.remote}<strong>{remote}/</strong>{/if}
|
|
<!-- svelte-ignore a11y_autofocus -->
|
|
<input
|
|
bind:value={name}
|
|
autocomplete="off"
|
|
spellcheck="false"
|
|
disabled={isBusy}
|
|
autofocus
|
|
/>
|
|
</div>
|
|
</label>
|
|
|
|
{#if branch.remote}
|
|
<p class="rename-remote-note">
|
|
Gitty creates <strong>{remote}/{name.trim() || "new-name"}</strong> and removes
|
|
<strong>{branch.name}</strong> in one atomic push. The operation stops if the remote changed in the meantime.
|
|
</p>
|
|
{/if}
|
|
|
|
<div class="new-branch-actions">
|
|
<button class="btn-secondary" type="button" onclick={onClose} disabled={isBusy}>
|
|
Cancel
|
|
</button>
|
|
<button class="btn-primary" type="submit" disabled={isBusy || name.trim().length === 0 || name.trim() === originalName}>
|
|
{#if isBusy}
|
|
<LoaderCircle class="spin" size={16} aria-hidden="true" />
|
|
{:else}
|
|
<GitBranch size={16} aria-hidden="true" />
|
|
{/if}
|
|
{branch.remote ? "Rename on remote" : "Rename"}
|
|
</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|