46db3f73e8
Finishes the isolated-worktree standard begun in #38 (which merged the branches/ gitignore, runbook, and scripts/worktree-start). Adds the two remaining helpers and their tests. - scripts/worktree-review: isolated DETACHED review worktree under branches/review-<branch> (fetch/prune first, refuse to overwrite, print path, --dry-run). Detached so a reviewer cannot accidentally commit and review work never blocks the author's implementation folder. - scripts/worktree-clean: the only deleting helper — removes a branches/ worktree after merge/close, refuses a dirty worktree (no --force), optionally safe-deletes a merged branch (git branch -d), fetch/prune first, --dry-run. Deletes nothing unless explicitly invoked. - tests/test_worktrees.py: path generation + refuse-to-overwrite for all three helpers via --dry-run (no real worktrees/branches/network/deletions). - runbook: reference worktree-review / worktree-clean and the --dry-run flag. Checks: bash -n clean on all three scripts; git diff --check clean; full suite 286 passed, 0 failures. Closes #39. Follow-up to #38. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
75 lines
2.2 KiB
Bash
Executable File
75 lines
2.2 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
|
|
usage() {
|
|
cat <<'EOF'
|
|
usage: scripts/worktree-clean [--dry-run] [--delete-branch] <branch-name|folder-name>
|
|
|
|
Remove a branch worktree under branches/ AFTER its PR is merged or closed. This
|
|
is the ONLY helper that deletes anything, and it deletes nothing unless you
|
|
invoke it explicitly. It refuses to remove a worktree with uncommitted changes
|
|
(no --force is offered). With --delete-branch it also deletes the local branch,
|
|
but only with a safe `git branch -d` (fails unless the branch is merged).
|
|
|
|
Pass the branch name (with slashes) so --delete-branch can resolve it; the
|
|
folder is branches/<branch-with-slashes-replaced-by-dashes>.
|
|
|
|
Examples:
|
|
scripts/worktree-clean --dry-run fix/issue-123-example
|
|
scripts/worktree-clean --delete-branch fix/issue-123-example
|
|
EOF
|
|
}
|
|
|
|
dry_run=0
|
|
del_branch=0
|
|
while [[ "${1:-}" == --* ]]; do
|
|
case "$1" in
|
|
--dry-run) dry_run=1 ;;
|
|
--delete-branch) del_branch=1 ;;
|
|
--help) usage; exit 0 ;;
|
|
*) usage >&2; exit 2 ;;
|
|
esac
|
|
shift
|
|
done
|
|
|
|
if [[ $# -ne 1 ]]; then
|
|
usage >&2
|
|
exit 2
|
|
fi
|
|
|
|
branch="$1"
|
|
worktree_name="${branch//\//-}"
|
|
|
|
script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
repo_root="$(cd "$script_dir/.." && pwd)"
|
|
worktree_path="$repo_root/branches/$worktree_name"
|
|
|
|
if [[ ! -d "$worktree_path" ]]; then
|
|
printf 'No such worktree: %s\n' "$worktree_path" >&2
|
|
exit 1
|
|
fi
|
|
|
|
if [[ "$dry_run" -eq 1 ]]; then
|
|
printf 'repo: %s\n' "$repo_root"
|
|
printf 'worktree: %s\n' "$worktree_path"
|
|
printf 'delete-branch: %s\n' "$del_branch"
|
|
printf 'commands:\n'
|
|
printf ' git -C %q fetch prgs --prune\n' "$repo_root"
|
|
printf ' git -C %q worktree remove %q\n' "$repo_root" "$worktree_path"
|
|
if [[ "$del_branch" -eq 1 ]]; then
|
|
printf ' git -C %q branch -d %q\n' "$repo_root" "$branch"
|
|
fi
|
|
exit 0
|
|
fi
|
|
|
|
git -C "$repo_root" fetch prgs --prune
|
|
# No --force: `git worktree remove` fails on uncommitted changes, on purpose.
|
|
git -C "$repo_root" worktree remove "$worktree_path"
|
|
printf 'removed worktree: %s\n' "$worktree_path"
|
|
|
|
if [[ "$del_branch" -eq 1 ]]; then
|
|
# Safe delete only: refuses to drop an unmerged branch.
|
|
git -C "$repo_root" branch -d "$branch"
|
|
printf 'deleted branch: %s\n' "$branch"
|
|
fi
|