Files
novalon-website/git-clean-local-gone.sh
T

90 lines
2.6 KiB
Bash

#!/bin/bash
# ============================================================
# 脚本:git-clean-local-branches.sh
# 功能:删除所有远程不存在的本地分支(只保留当前分支及与远程同名的分支)
# 用法:./git-clean-local-branches.sh [-n|--dry-run] [-f|--force]
# -n, --dry-run 预览要删除的分支,不实际执行
# -f, --force 跳过确认提示,直接删除
# ============================================================
set -e
dry_run=false
force=false
while [[ $# -gt 0 ]]; do
case "$1" in
-n|--dry-run) dry_run=true; shift ;;
-f|--force) force=true; shift ;;
-h|--help)
cat <<EOF
用法: $0 [选项]
-n, --dry-run 预览要删除的分支,不实际删除
-f, --force 跳过删除确认,直接执行
-h, --help 显示此帮助
EOF
exit 0
;;
*) echo "未知选项: $1"; exit 1 ;;
esac
done
# ---------- 刷新远程缓存 ----------
echo "==> 刷新所有远程缓存..."
git fetch --all --prune --prune-tags 2>/dev/null || git fetch --all --prune
for remote in $(git remote); do
git remote prune "$remote" 2>/dev/null || true
done
echo
# ---------- 获取远程分支完整路径(去掉远程前缀) ----------
# 例如 origin/feat/xxx -> feat/xxx
remote_branches=$(git branch -r | grep -v '\->' | sed 's/^[^/]*\///' | sort -u)
# ---------- 收集本地分支(排除当前分支) ----------
current_branch=$(git rev-parse --abbrev-ref HEAD)
to_delete=()
for branch in $(git for-each-ref refs/heads/ --format='%(refname:short)'); do
if [[ "$branch" == "$current_branch" ]]; then
echo " 保留当前分支: $branch"
continue
fi
if ! echo "$remote_branches" | grep -qxF "$branch"; then
to_delete+=("$branch")
fi
done
# ---------- 执行删除 ----------
if [[ ${#to_delete[@]} -eq 0 ]]; then
echo "没有需要删除的分支。"
exit 0
fi
echo "以下本地分支在远程不存在,将被删除:"
printf " %s\n" "${to_delete[@]}"
echo
if $dry_run; then
echo "(试运行,未实际删除)"
exit 0
fi
if ! $force; then
read -p "确认删除以上分支?(y/N) " -n 1 -r
echo
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
echo "操作取消。"
exit 0
fi
fi
echo "==> 开始删除..."
for branch in "${to_delete[@]}"; do
echo "删除: $branch"
if ! git branch -d "$branch" 2>/dev/null; then
echo " 普通删除失败,尝试强制删除..."
git branch -D "$branch" 2>/dev/null || echo " 警告:删除失败,跳过"
fi
done
echo "完成。"