本文目录导读:

清理开源项目的版本分支是维护项目健康度的关键工作,混乱的分支会导致开发效率下降、CI/CD成本上升,并增加合并冲突的风险。
以下是系统性地清理版本分支的标准化流程和最佳实践,分为策略制定、执行清理和自动化维护三个部分。
第一阶段:制定分支清理策略
在动手删除之前,必须先定义“哪些分支可以删”,建议遵循以下原则:
- 已合并的分支可以删除:那些已经合并到主分支(
main/master)、稳定分支(stable)或开发分支(develop)的特性分支或修复分支。 - 未合并但已废弃的分支可以删除:即那些长时间(如30天、60天)没有活动,且没有在开发中的分支(Stale Branches)。
- 长期存在的分支需要保留:
- 主分支:
main/master(必须保留)。 - 开发分支:
develop(如果使用Git Flow)。 - 稳定/发布分支:
release-*或stable-*(用于维护已发布的版本,如release-2.1.x,特别是LTS版本)。 - 维护中的旧版分支:
x,如果项目还在对该旧版本进行安全修复。
- 主分支:
核心策略:只保留“活”的分支和“版本发布历史记录”所需的分支,推荐使用 GitHub Flow 或 Trunk-Based Development 这类精简的分支模型,避免 Git Flow 产生过多长期未合并的“死亡分支”。
第二阶段:执行清理(分步操作)
第一步:备份与确认(非常重要)
在删除前,确保你或你的团队有方式找回代码,虽然Git恢复理论上可能,但成本很高。
# 1. 获取所有远程分支的本地副本,作为备份参考(可选) git fetch --all
第二步:识别可删除的分支
使用 git branch 命令配合条件查找。
-
查看本地已合并到当前分支的分支:
# 合并到 main 的分支 git checkout main git branch --merged main | grep -v '\* main' | grep -v '\* master' | grep -v '\* develop'
输出结果中的那些分支,如果没有标记为 `` 且不是主要分支,通常可以删除。*
-
查看本地未合并但长时间未更新的分支(危险操作):
# 查看尚未合并到 main 的分支及其最后提交时间 for branch in $(git branch --no-merged main | cut -c 3-); do echo "$branch - $(git log -1 --format=%ci $branch)" done如果其中的分支超过60天未commit,且不是
develop或release分支,可以考虑删除。
第三步:清理本地仓库
-
删除本地已合并的分支:
git branch --merged main | grep -v '^* main\|master\|develop' | xargs git branch -d
-
删除本地未合并但确定废弃的分支(慎用,会永久丢失未合并的更改):
git branch -D stale-branch-name
-
清理本地远程追踪分支的“僵尸引用”(即远程已删除,但本地还保留的引用):
git remote prune origin
这会在删除前提示你哪些远程分支已被删除。
第四步:清理远程仓库(核心步骤,需谨慎)
推荐使用 GitHub / GitLab 的 Web UI 操作,因为:
- 可以批量选择。
- 有“恢复/撤销”的选项(通常在30天内可以恢复已删除的分支)。
- 有权限控制。
如果你必须使用命令行操作:
-
强制删除远程分支:
# 删除单个 git push origin --delete feature-old-logic # 批量删除(危险!先测试好条件) git branch -r --merged origin/main | grep -v 'origin/main\|origin/develop\|origin/release' | sed 's/origin\///' | xargs -I {} git push origin --delete {} -
彻底清理远程分支的缓存:
git fetch --prune origin
第三阶段:自动化与持续维护
手动清理一次后,更需要建立一套持续维护的机制,防止“技术债”积累。
-
使用 CI/CD 自动清理合并后的分支:
- GitHub:在 Settings -> Actions -> General -> 勾选 "Automatically delete head branches",这样每个PR合并后,源分支自动从远程删除。
- GitLab:在 Settings -> General -> Merge requests -> 勾选 "Delete source branch when merge request is accepted"。
-
使用
stale策略(推荐):- GitHub Actions:使用 actions/stale 或 peter-evans/close-stale-issues(主要用于Issues/PR)。
- GitLab CI/CD:可以通过
rules或定时 job 执行git branch -d脚本。 - 或使用专业的自动化工具:GitHub官方支持的减少仓库活动 或托管平台的Bot。
-
实施分支命名规范:
feature/xxx、fix/xxx、release/xxx、hotfix/xxx。- 配合自动化脚本,可以安全地批量清理
feature/或fix/前缀下长时间未更新的分支。
-
定期回顾:
- 每月或每季度执行一次全面的分支清理(特别是对旧的发布分支)。
- 维护一个
RELEASE_NOTES.md或CHANGELOG.md,明确指出哪些旧版本还受支持,哪些旧分支可以安全删除(v1.x 分支在 2024-12-31 后不再维护,将于 2025-01-15 删除)。
特殊情况处理
-
分支上还有未合并的更改,但确实要废弃:
- 你可以选择将其 移至存档(例如创建一个名为
archive/的子目录,推送到archive/stale-feature分支),而不是直接删除,这样确保代码不会丢失,但也不会污染主分支列表。 - 或者,使用
git tag为最后一次提交打上一个特殊标签(如delete-me/feature-old),然后删除分支。
- 你可以选择将其 移至存档(例如创建一个名为
-
发布分支(Release/Stable):
- 它们通常不删除,除非确定了那个版本已经完全不再维护(例如所有用户都已升级到v4,且v3不再有任何安全更新)。
- 发布分支的理想数量通常控制在 2-3 个(最近的一个主版本 + 1-2个长期支持版本)。
一个建议的脚本流程
你可以在项目仓库根目录添加一个 scripts/cleanup-branches.sh 脚本,让维护者执行或CI自动调用(需谨慎):
#!/bin/bash
# 谨慎使用!仅在确认无误后执行。
echo "=== 清理本地已合并分支 ==="
git checkout main
git fetch --prune origin
# 1. 删除本地已合并到main且非主分支的分支
git branch --merged main | grep -v '^* main\|master\|develop' | xargs git branch -d 2>/dev/null
# 2. 删除远程未合并但确实已废弃的分支(这里假设标准是超过90天无提交)
echo "=== 检查远程废弃分支 (90天无活动) ==="
# 获取所有远程分支的最后更新时间
for branch in $(git branch -r --format='%(refname:short)' | grep -v 'origin/main\|origin/develop'); do
last_commit_date=$(git log -1 --format=%ct "$branch" 2>/dev/null)
current_time=$(date +%s)
# 计算天数差 (90天 = 7776000秒)
if [ $((current_time - last_commit_date)) -gt 7776000 ]; then
echo "[潜在删除] $branch 最后更新于 $(git log -1 --format=%ci $branch)"
# 可以在这里添加 git push origin --delete 的步骤,但建议先手动确认
fi
done
echo "=== 自动删除远程已合并分支 === "
# 注意:此操作需谨慎,确保 list 中不包含 main/develop/release 等
git branch -r --merged origin/main | grep -v 'origin/main\|origin/develop\|origin/release' | sed 's/origin\///' | while read branch; do
echo "删除远程分支: $branch"
git push origin --delete "$branch" 2>/dev/null || echo "[跳过] 可能已不存在"
done
echo "清理完成。"
最后的核心建议是:永远不要手动删除你不确定的分支。 先在 Issue 中发起讨论,标记为 status: stale,等待团队确认或30天无人反对后,再进行删除,删除后,使用 git push origin --delete 确保远程也同步清理。