批量删除久未使用的git分支
该脚本实现批量删除指定日期内久未删除的分支:
快捷使用
./git-cleanup.sh -d 90(天数)
自定义保护分支列表
创建保护分支列表文件:
echo -e "production\nlegacy-system" > ~/.git_cleanup_protected
指定自定义配置文件:
./git-cleanup.sh -c ./project_protected_branches.cfg -d 60
配置文件格式说明:
- 每行一个分支名称
- 支持行末注释(以 # 开头的内容)
- 自动忽略空行和空格
查看当前保护分支列表
# 使用示例 $ ./git-cleanup.sh -l 当前受保护分支列表: ---------------------------------------- 分支名称 来源 ---------------------------------------- production [配置文件] /home/user/.git_cleanup_protected main [系统默认] master [系统默认] develop [系统默认] ---------------------------------------- (配置文件路径: /home/user/.git_cleanup_protected)
脚本内容
git-cleanup.sh:
#!/bin/bash
# 默认配置
DEFAULT_PROTECTED=("master" "main" "develop") # 默认受保护分支
CONFIG_FILE="${HOME}/.git_cleanup_protected" # 默认配置文件路径
remote="origin" # 远程仓库名称
delete_local=true # 是否删除本地分支
days_threshold=30 # 默认过期天数阈值
# 加载配置文件
declare -a protected_branches=()
load_protected_branches() {
# 清空数组重新加载
protected_branches=()
# 读取配置文件
if [ -f "$CONFIG_FILE" ]; then
while IFS= read -r line; do
line=${line%%#*} # 去除行末注释
line=${line//$'\r'/} # 处理Windows换行符
line=${line// /} # 去除空格
[[ -n "$line" ]] && protected_branches+=("$line")
done < "$CONFIG_FILE"
fi
# 合并默认保护分支(去重)
for branch in "${DEFAULT_PROTECTED[@]}"; do
if [[ ! " ${protected_branches[@]} " =~ " $branch " ]]; then
protected_branches+=("$branch")
fi
done
}
# 列出保护分支
list_protected_branches() {
# 读取配置文件内容(不合并默认值)
declare -a config_branches=()
if [ -f "$CONFIG_FILE" ]; then
while IFS= read -r line; do
line=${line%%#*}
line=${line// /}
[[ -n "$line" ]] && config_branches+=("$line")
done < "$CONFIG_FILE"
fi
echo "当前受保护分支列表:"
echo "----------------------------------------"
printf "%-25s %s\n" "分支名称" "来源"
echo "----------------------------------------"
# 显示配置文件中的分支
for branch in "${config_branches[@]}"; do
printf "%-25s %s\n" "$branch" "[配置文件] $CONFIG_FILE"
done
# 显示未在配置文件中出现的默认分支
for default_branch in "${DEFAULT_PROTECTED[@]}"; do
if [[ ! " ${config_branches[@]} " =~ " $default_branch " ]]; then
printf "%-25s %s\n" "$default_branch" "[系统默认]"
fi
done
echo "----------------------------------------"
echo "(配置文件路径: $CONFIG_FILE)"
exit 0
}
# 解析命令行参数
while [[ $# -gt 0 ]]; do
case $1 in
-d|--days)
days_threshold="$2"
shift; shift ;;
-c|--config)
CONFIG_FILE="$2"
shift; shift ;;
-l|--list)
list_protected_branches ;;
-h|--help)
echo "用法: $0 [选项]"
echo "选项:"
echo " -d, --days N 设置过期天数阈值(默认:30)"
echo " -c, --config FILE指定配置文件路径(默认:${CONFIG_FILE})"
echo " -l, --list 列出所有受保护分支"
echo " -h, --help 显示帮助信息"
exit 0 ;;
*)
echo "未知选项: $1"; exit 1 ;;
esac
done
# 验证天数参数
[[ "$days_threshold" =~ ^[0-9]+$ ]] || { echo "错误:天数参数必须为整数"; exit 1; }
# 加载保护分支列表
load_protected_branches
# 计算截止时间戳
cutoff=$(date -d "$days_threshold days ago" +%s)
# 获取分支信息(含创建者)
declare -a branches_info
while read ts branch; do
branch_name=${branch#$remote/}
# 跳过受保护分支
[[ " ${protected_branches[@]} " =~ " $branch_name " ]] && continue
# 获取分支创建者信息
creator=$(git log --reverse --format="%an <%ae>" "$branch" -1 2>/dev/null || echo "未知")
creator=${creator//|/-} # 处理特殊字符
# 存储分支信息:时间戳|分支名|创建者
branches_info+=("$ts|$branch_name|${creator//$'\n'/}")
done < <(git fetch -pq && git for-each-ref --sort=committerdate \
--format='%(committerdate:unix) %(refname:short)' \
"refs/remotes/$remote")
# 筛选待删除分支
branches_to_delete=()
for entry in "${branches_info[@]}"; do
IFS='|' read ts branch_name creator <<< "$entry"
[ $ts -lt $cutoff ] && branches_to_delete+=("$branch_name|$creator")
done
# 显示结果
if [ ${#branches_to_delete[@]} -eq 0 ]; then
echo "没有需要清理的分支(阈值:${days_threshold}天)"
exit 0
fi
echo "以下分支超过 ${days_threshold} 天未更新(共 ${#branches_to_delete[@]} 个):"
printf "%-30s %s\n" "分支名称" "创建者"
echo "------------------------------------------------"
for entry in "${branches_to_delete[@]}"; do
IFS='|' read branch creator <<< "$entry"
printf "%-30s %s\n" "$branch" "$creator"
done
# 用户确认
read -p "是否确认删除这些分支?[y/N] " -n 1 -r
echo
[[ ! $REPLY =~ ^[Yy]$ ]] && { echo "操作已取消"; exit 1; }
# 执行删除
deleted_count=0
for entry in "${branches_to_delete[@]}"; do
IFS='|' read branch_name creator <<< "$entry"
# 删除远程分支
if git push -q "$remote" --delete "$branch_name"; then
echo "已删除远程分支: $branch_name (创建者: $creator)"
((deleted_count++))
else
echo "删除远程分支失败: $branch_name" >&2
continue
fi
# 删除本地分支
if [ "$delete_local" = true ]; then
git branch -D "$branch_name" >/dev/null 2>&1 && \
echo "已删除本地分支: $branch_name" || \
echo "本地分支不存在: $branch_name"
fi
done
echo "操作完成,共删除 $deleted_count 个远程分支"