如何使用bash脚本删除无打开Pull Request的旧Git分支
Bash脚本实现自动清理无关联打开PR的旧分支
下面提供两种可直接使用的实现方案,优先推荐使用GitHub CLI的方案,逻辑更简单不易出错。
方案1:基于GitHub CLI实现(推荐)
前置依赖
- 已安装GitHub CLI,可通过包管理器直接安装,例如
brew install gh/apt install gh - 已执行
gh auth login完成目标仓库的权限认证
完整脚本
#!/bin/bash # 配置项 REMOTE_NAME="origin" # 保护分支,不会被删除 PROTECTED_BRANCHES=("main" "master" "develop" "release/*") # 分支闲置时间阈值,单位:天,超过该时间无更新才会被清理 INACTIVE_DAYS=30 # dry_run模式:设为true只会打印要删除的分支,设为false会真实执行删除 DRY_RUN=true # 1. 拉取最新远程信息 git fetch $REMOTE_NAME --prune # 2. 获取所有打开的PR的源分支列表,去重 OPEN_PR_BRANCHES=($(gh pr list --state open --json headRefName --jq '.[].headRefName' | sort -u)) # 3. 遍历所有远程分支过滤待清理项 for branch in $(git branch -r | grep "$REMOTE_NAME/" | sed "s/$REMOTE_NAME\///"); do # 跳过保护分支 skip=0 for protected in "${PROTECTED_BRANCHES[@]}"; do if [[ $branch == $protected ]]; then skip=1 break fi done if [[ $skip == 1 ]]; then continue; fi # 跳过有打开PR关联的分支 if [[ " ${OPEN_PR_BRANCHES[*]} " =~ " $branch " ]]; then continue fi # 检查分支最后提交时间是否超过闲置阈值 last_commit_timestamp=$(git log -1 --format=%ct "$REMOTE_NAME/$branch") current_timestamp=$(date +%s) days_since_last_commit=$(( (current_timestamp - last_commit_timestamp) / 86400 )) if [[ $days_since_last_commit -ge $INACTIVE_DAYS ]]; then echo "待删除分支:$branch,最后更新于 $days_since_last_commit 天前" if [[ $DRY_RUN == false ]]; then git push $REMOTE_NAME --delete "$branch" fi fi done
使用说明
- 先调整脚本开头的配置项,确认保护分支、闲置时间符合你的需求
- 第一次执行保持
DRY_RUN=true,确认输出的待删除分支列表无误后,再改成false执行真实删除
方案2:原生Git实现(无需额外工具)
如果你无法安装GitHub CLI,可以用原生Git命令实现,逻辑如下:
#!/bin/bash REMOTE_NAME="origin" PROTECTED_BRANCHES=("main" "master" "develop") INACTIVE_DAYS=30 DRY_RUN=true git fetch $REMOTE_NAME --prune # 获取所有PR的头哈希列表 ALL_PR_HASHES=($(git ls-remote $REMOTE_NAME 'refs/pull/*/head' | awk '{print $1}')) # 遍历所有远程分支 for branch in $(git branch -r | grep "$REMOTE_NAME/" | sed "s/$REMOTE_NAME\///"); do # 跳过保护分支 skip=0 for protected in "${PROTECTED_BRANCHES[@]}"; do [[ $branch == $protected ]] && { skip=1; break; } done [[ $skip == 1 ]] && continue # 获取当前分支的头哈希 branch_hash=$(git rev-parse "$REMOTE_NAME/$branch") # 检查该哈希是否属于未合并的PR头 if [[ " ${ALL_PR_HASHES[*]} " =~ " $branch_hash " ]]; then # 额外校验该PR是否已合并到主分支 if git merge-base --is-ancestor "$branch_hash" "$REMOTE_NAME/main"; then echo "分支$branch关联的PR已合并,可清理" else continue fi fi # 校验闲置时间 last_commit_ts=$(git log -1 --format=%ct "$REMOTE_NAME/$branch") days_since=$(( ($(date +%s) - last_commit_ts) / 86400 )) if [[ $days_since -ge $INACTIVE_DAYS ]]; then echo "待删除分支:$branch,最后更新于$days_since天前" [[ $DRY_RUN == false ]] && git push $REMOTE_NAME --delete "$branch" fi done
注意事项
- 所有脚本执行前请先运行dry run模式确认删除列表,避免误操作
- 建议在仓库配置保护分支规则,锁定核心分支,即使脚本逻辑出错也无法删除核心分支
- 可将脚本配置为仓库的CI定时任务,每周自动执行一次清理
内容的提问来源于stack exchange,提问作者alextdaada
相关产品推荐
相关产品推荐

