chore(workflow): branch-and-PR working method + ADR-number reservation (ADR-0059)
ci / gate (push) Successful in 2m5s
ci / manifests (push) Successful in 4s
ci / gate (pull_request) Successful in 2m5s
ci / manifests (pull_request) Successful in 4s

Adopt a trackable working method now the repo is public:
- PRs onto a protected main; --no-ff merge commits; one worktree per branch.
- Reserve-first ADR numbering: scripts/adr-reserve.sh claims the next number
  atomically against main (push = compare-and-swap; ledger
  docs/adr/RESERVATIONS.log), so a number is stable from creation.
- Worktree helpers scripts/wt-new.sh + wt-clean.sh.
- Local-origin test harnesses (reserve 10/10, worktrees 7/7, shellcheck clean).

Record the decision in ADR-0059, supersede ADR-0000's placeholder-until-merge
numbering default, and add the lean CONTRIBUTING.md sections + CLAUDE.md
operational rules.
This commit is contained in:
claude@clouddev1
2026-06-23 20:41:42 +00:00
parent e845a6ee72
commit b5c848efcb
10 changed files with 694 additions and 11 deletions
+72
View File
@@ -0,0 +1,72 @@
#!/usr/bin/env bash
#
# wt-clean.sh — tidy up worktrees whose branch has merged.
#
# WHAT it does (safe by default):
# 1. `git worktree prune` — drop admin entries for worktrees whose
# directory is already gone.
# 2. For every *other* worktree (never the primary checkout, never the one
# you're standing in) whose branch is fully merged into origin/main:
# remove the worktree and delete the local branch.
#
# SAFETY: it refuses to remove a worktree with uncommitted changes (no
# --force) and only ever touches branches git confirms are merged into
# origin/main, so unmerged work is never lost. Run it whenever; it's not
# tied to any moment.
#
# USAGE
# scripts/wt-clean.sh # do it
# scripts/wt-clean.sh --dry-run # show what it would remove
set -euo pipefail
log() { printf ' wt-clean: %s\n' "$*" >&2; }
dry=0
[ "${1:-}" = "--dry-run" ] && dry=1
git rev-parse --git-dir >/dev/null 2>&1 || { echo "wt-clean: not in a git repo" >&2; exit 1; }
log "fetching origin/main"
git fetch --quiet --prune origin main || true
log "pruning stale worktree entries"
if (( dry )); then
git worktree prune --dry-run -v
else
git worktree prune -v
fi
# The primary checkout and the current worktree are off-limits.
main_wt="$(git worktree list --porcelain | awk '/^worktree /{print $2; exit}')"
here="$(git rev-parse --show-toplevel)"
# Branches fully merged into origin/main (whitespace-trimmed, sans markers).
merged="$(git branch --format='%(refname:short)' --merged origin/main)"
is_merged() { grep -qxF "$1" <<<"$merged"; }
removed=0
# Iterate worktrees: paired "worktree <path>" / "branch refs/heads/<name>".
path=""; while read -r key val; do
case "$key" in
worktree) path="$val" ;;
branch)
br="${val#refs/heads/}"
if [ "$path" != "$main_wt" ] && [ "$path" != "$here" ] && is_merged "$br"; then
if (( dry )); then
log "would remove worktree $path (branch $br, merged)"
else
if git worktree remove "$path" 2>/dev/null; then
git branch -d "$br" >/dev/null 2>&1 || true
log "removed worktree $path + branch $br"
removed=$((removed+1))
else
log "skipped $path — has uncommitted changes (remove it by hand)"
fi
fi
fi
;;
esac
done < <(git worktree list --porcelain)
(( dry )) || log "done — removed $removed merged worktree(s)"