fix(scripts/pr): make cleanup worktree-safe

This commit is contained in:
Gustavo Madeira Santana
2026-03-31 09:06:24 -04:00
parent 27b9665871
commit 8dbba7d17c
3 changed files with 186 additions and 9 deletions

View File

@@ -185,3 +185,151 @@ merge_author_email_candidates() {
"${reviewer_id}+${reviewer}@users.noreply.github.com" \
"${reviewer}@users.noreply.github.com" | awk 'NF && !seen[$0]++'
}
common_repo_root() {
if command -v repo_root >/dev/null 2>&1; then
repo_root
return
fi
local base_dir
base_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
git -C "$base_dir" rev-parse --show-toplevel
}
worktree_path_for_branch() {
local branch="$1"
local ref="refs/heads/$branch"
git worktree list --porcelain | awk -v ref="$ref" '
/^worktree / {
worktree=$2
next
}
/^branch / {
if ($2 == ref) {
print worktree
found=1
}
}
END {
if (!found) {
exit 1
}
}
'
}
worktree_is_registered() {
local path="$1"
git worktree list --porcelain | awk -v target="$path" '
/^worktree / {
if ($2 == target) {
found=1
}
}
END {
exit found ? 0 : 1
}
'
}
resolve_existing_dir_path() {
local path="$1"
if [ ! -d "$path" ]; then
return 1
fi
(
cd "$path" >/dev/null 2>&1 &&
pwd -P
)
}
is_repo_pr_worktree_dir() {
local path="$1"
local root
root=$(common_repo_root)
local worktrees_dir="$root/.worktrees"
local resolved_path
resolved_path=$(resolve_existing_dir_path "$path" 2>/dev/null || true)
if [ -z "$resolved_path" ]; then
return 1
fi
local resolved_worktrees_dir
resolved_worktrees_dir=$(resolve_existing_dir_path "$worktrees_dir" 2>/dev/null || true)
if [ -z "$resolved_worktrees_dir" ]; then
return 1
fi
case "$resolved_path" in
"$resolved_worktrees_dir"/pr-*)
return 0
;;
esac
return 1
}
remove_worktree_if_present() {
local path="$1"
if [ ! -e "$path" ]; then
return 0
fi
if worktree_is_registered "$path"; then
git worktree remove "$path" --force >/dev/null 2>&1 || true
fi
if [ ! -e "$path" ]; then
return 0
fi
if worktree_is_registered "$path"; then
echo "Warning: failed to remove registered worktree $path"
return 0
fi
if ! is_repo_pr_worktree_dir "$path"; then
echo "Warning: refusing to trash non-PR-worktree path $path"
return 0
fi
if command -v trash >/dev/null 2>&1; then
trash "$path" >/dev/null 2>&1 || {
echo "Warning: failed to trash orphaned worktree dir $path"
return 0
}
return 0
fi
echo "Warning: orphaned worktree dir remains and trash is unavailable: $path"
return 0
}
delete_local_branch_if_safe() {
local branch="$1"
local ref="refs/heads/$branch"
if ! git show-ref --verify --quiet "$ref"; then
return 0
fi
local branch_worktree=""
branch_worktree=$(worktree_path_for_branch "$branch" 2>/dev/null || true)
if [ -n "$branch_worktree" ]; then
echo "Skipping local branch delete for $branch; checked out in worktree $branch_worktree"
return 0
fi
if git branch -D "$branch" >/dev/null 2>&1; then
return 0
fi
if git update-ref -d "$ref" >/dev/null 2>&1; then
return 0
fi
echo "Warning: failed to delete local branch $branch"
return 0
}