]> git.ekhem.eu.org Git - guix.git/commitdiff
[ai] Add merge-worktree workflow: branch-summary, merge script, and skill doc.
authorJakub Czajka <jakub@ekhem.eu.org>
Mon, 6 Jul 2026 09:24:17 +0000 (11:24 +0200)
committerJakub Czajka <jakub@ekhem.eu.org>
Tue, 7 Jul 2026 21:36:27 +0000 (23:36 +0200)
Introduces a workflow for merging feature branches into main via
rebase + fast-forward merge. The skill document teaches Claude
the merge-worktree procedure so it can be invoked as a slash command.

.claude/scripts/branch-summary [new file with mode: 0755]
.claude/scripts/merge-worktree [new file with mode: 0755]
.claude/skills/merge-worktree.md [new file with mode: 0644]

diff --git a/.claude/scripts/branch-summary b/.claude/scripts/branch-summary
new file mode 100755 (executable)
index 0000000..0623773
--- /dev/null
@@ -0,0 +1,46 @@
+#!/bin/sh
+# Copyright (c) 2026 Jakub Czajka <jakub@ekhem.eu.org>
+# License: GPL-3.0 or later.
+#
+# branch-summary — Summarize non-main branches as a markdown table.
+
+# List all local branches except main.
+branches=$($HOME/.guix-home/profile/bin/git \
+    -C "$CLAUDE_PROJECT_DIR" for-each-ref \
+    --format='%(refname:short)' refs/heads/ \
+    | $GUIX_BIN/grep -v '^main$')
+
+if [ -z "$branches" ]; then
+    $GUIX_BIN/echo "No other branches."
+    exit 0
+fi
+
+# Print up to 3 commit subjects from branch $1 as a comma-separated
+# list, escaped for markdown table use.
+format_commits() {
+    $HOME/.guix-home/profile/bin/git -C "$CLAUDE_PROJECT_DIR" log --oneline \
+        --format='%s' main.."$1" 2>/dev/null \
+        | head -3 \
+        | $GUIX_BIN/sed 's/|/\\|/g' \
+        | $GUIX_BIN/tr '\n' ',' \
+        | $GUIX_BIN/sed 's/,$//;s/,/, /g'
+}
+
+# Table header.
+$GUIX_BIN/echo '| Branch | Commits | Summary |'
+$GUIX_BIN/echo '|--------|---------|---------|'
+
+# One row per branch.
+echo "$branches" | while read -r b; do
+    count=$($HOME/.guix-home/profile/bin/git \
+        -C "$CLAUDE_PROJECT_DIR" rev-list --count \
+        main.."$b" 2>/dev/null)
+    if [ -z "$count" ] || [ "$count" -eq 0 ]; then
+        summary="(even with main)"
+    else
+        summary=$(format_commits "$b")
+    fi
+    $GUIX_BIN/echo "| \`$b\` | $count | $summary |"
+done
+
+exit 0
diff --git a/.claude/scripts/merge-worktree b/.claude/scripts/merge-worktree
new file mode 100755 (executable)
index 0000000..492e45a
--- /dev/null
@@ -0,0 +1,82 @@
+#!/bin/sh
+# Copyright (c) 2026 Jakub Czajka <jakub@ekhem.eu.org>
+# License: GPL-3.0 or later.
+#
+# merge-worktree — Merge a worktree branch into main.
+#
+# This script operates on the main worktree (CLAUDE_PROJECT_DIR) as a
+# subprocess, independent of the session's current directory. It rebases
+# the branch for linear history then fast-forwards main.
+#
+# Usage: merge-worktree <branch-name>
+
+set -eu
+
+branch="${1:-}"
+if [ -z "$branch" ]; then
+    echo "Usage: merge-worktree <branch-name>" >&2
+    exit 1
+fi
+
+PROJECT_DIR="${CLAUDE_PROJECT_DIR:-$(pwd)}"
+
+# Validate branch.
+if ! $HOME/.guix-home/profile/bin/git -C "$PROJECT_DIR" rev-parse \
+    --verify "$branch" >/dev/null 2>&1; then
+    echo "Error: Branch '$branch' does not exist." >&2
+    exit 1
+fi
+
+if [ "$branch" = "main" ]; then
+    echo "Error: Cannot merge main into itself." >&2
+    exit 1
+fi
+
+# Check main worktree is clean.
+if [ -n "$($HOME/.guix-home/profile/bin/git -C "$PROJECT_DIR" \
+    status --porcelain --untracked-files=no)" ]; then
+    echo "Error: Main worktree has uncommitted changes." >&2
+    echo "  Commit or stash them first." >&2
+    exit 1
+fi
+
+# Ensure main is restored on any exit (rebase failure, interruption).
+trap '$HOME/.guix-home/profile/bin/git -C "$PROJECT_DIR" checkout main \
+    2>/dev/null || true' EXIT
+
+# Fetch from origin.
+echo "=== Fetching from origin ==="
+$HOME/.guix-home/profile/bin/git -C "$PROJECT_DIR" fetch origin
+
+# Rebase branch onto main.
+echo "=== Rebasing $branch onto main ==="
+if ! $HOME/.guix-home/profile/bin/git -C "$PROJECT_DIR" \
+    rebase main "$branch"; then
+    rc=$?
+    echo "Error: Rebase failed (conflicts)." >&2
+    echo "  Resolve them in the main worktree:" >&2
+    echo "    cd $PROJECT_DIR" >&2
+    echo "    git status  # see conflicted files" >&2
+    echo "    # fix conflicts, then:" >&2
+    echo "    git rebase --continue" >&2
+    echo "    git checkout main" >&2
+    echo "    git merge --ff-only $branch" >&2
+    exit $rc
+fi
+
+# Switch back to main.
+echo "=== Switching to main ==="
+$HOME/.guix-home/profile/bin/git -C "$PROJECT_DIR" checkout main
+
+# Fast-forward merge.
+echo "=== Merging $branch into main (fast-forward) ==="
+if ! $HOME/.guix-home/profile/bin/git -C "$PROJECT_DIR" \
+    merge --ff-only "$branch"; then
+    rc=$?
+    echo "Error: Fast-forward merge failed." >&2
+    echo "  This should not happen after a successful rebase." >&2
+    echo "  Try: git -C $PROJECT_DIR merge $branch" >&2
+    exit $rc
+fi
+
+echo "=== Branch '$branch' successfully merged into main ==="
diff --git a/.claude/skills/merge-worktree.md b/.claude/skills/merge-worktree.md
new file mode 100644 (file)
index 0000000..1a1f6af
--- /dev/null
@@ -0,0 +1,48 @@
+---
+name: merge-worktree
+description: Merge a workspace branch into main and optionally reconfigure.
+---
+
+# merge-worktree
+
+Merge a worktree branch into main, rebasing for linear history, then
+optionally run guix reconfigure.
+
+## Instructions
+
+When the user asks to merge a workspace, integrate branch changes, or
+"commit to main":
+
+1. **Show available workspaces**:
+   Run `.claude/scripts/branch-summary` to display a markdown table of
+   all non-main branches (workspaces) and their commits.
+
+2. **Ask which workspace to merge**:
+   Use AskUserQuestion (single-select). Present the workspace branch
+   names from step 1 as options. If only one non-main branch exists,
+   ask to confirm merging that one.
+
+3. **Execute the merge**:
+   Run `.claude/scripts/merge-worktree <selected-branch>`.
+   If the merge fails (rebase conflict), instruct the user to resolve
+   conflicts in the main worktree at `$CLAUDE_PROJECT_DIR`, then retry.
+
+4. **Ask about guix reconfigure**:
+   Use AskUserQuestion (single-select) with these options:
+   - "guix home reconfigure"
+   - "guix system reconfigure"
+   - "Skip reconfigure"
+
+5. **Run reconfigure if selected**:
+   Run the chosen command using Bash against the main worktree.
+
+6. **Offer branch cleanup**:
+   Use AskUserQuestion (single-select) asking whether to delete the
+   merged branch. Options: "Delete branch and worktree", "Keep branch".
+
+## Notes
+
+- The merge script `cd`s to `$CLAUDE_PROJECT_DIR` (main worktree) as a
+  subprocess, independent of the session's worktree directory.
+- After the merge, `ExitWorktree` becomes available since the branch is
+  now an ancestor of main.