还在手动删GitLab分支?教你如何自动清理过期合并分支
一、背景:分支管理的烦恼
在项目开发过程中,随着越来越多开发人员参与进来,各种分支不断涌现。很多时候,大家在将代码合并到release分支后,不会顺手删除源分支,可能想着以后要是有问题还能拿这些历史分支来修复。而且在创建合并请求(MR)时,也常常忘记勾选“Delete source branch when merge request is accepted.”这个选项。时间一长,仓库里就堆积了大量已经合并但没啥用的分支。这些“僵尸分支”不仅看着杂乱,还会给后续项目维护带来麻烦。要是专门花时间一个个去删,效率又太低。所以,我就琢磨着能不能借助GitLab的定时流水线任务,实现自动删除过期分支的功能,让繁琐的工作变得轻松一些。
二、配置步骤详解
(一)流水线任务配置
要实现自动删除过期合并分支,第一步就是在仓库里配置一个流水线任务。
- 先在流水线里新增一个阶段,比如取名为
branh-auto-delete
,这个名字可以根据自己的喜好来取,方便识别就行。 - 接着添加任务逻辑,具体代码如下:
Custom-Auto-Delete-Branch: stage: branh-auto-delete image: 你能获取到的一个docker镜像,需要包含shell, git, curl, jq等命令 variables: <<: *gitlab-variables tags: - official script: - echo Job:Custom - echo "will try to delete" - echo $PATH - export PATH=$PATH:$MAVEN_HOMEN_HOME/bin - | # 使用预定义的环境变量 GITLAB_URL="$GITLAB_HOST" PRIVATE_TOKEN="$GITLAB_TOKEN" PROJECT_ID="$CI_PROJECT_ID" MONTHS_AGO="${MONTHS_AGO:-3}" # 默认值为3个月 deleted_branch="" # 获取当前时间的三个月前的日期 three_months_ago=$(date -d "-${MONTHS_AGO} months" +%s) echo "$three_months_ago" # 项目的tag tags=$(curl --silent --header "PRIVATE-TOKEN: $PRIVATE_TOKEN" "$GITLAB_URL/api/v4/projects/$PROJECT_ID/repository/tags") # 循环获取所有页面的分支 # 初始化分页参数 page=1 per_page=100 branches="" echo "get all branch" while true; do response=$(curl --silent --header "PRIVATE-TOKEN: $PRIVATE_TOKEN" "$GITLAB_URL/api/v4/projects/$PROJECT_ID/repository/branches?per_page=$per_page&page=$page") branch_count=$(echo "$response" | jq '. | length') # 如果当前页面没有分支,退出循环 if [ "$branch_count" -eq 0 ]; then break fi # 累积所有分支(jq可以处理) branches="$branches$response" page=$((page + 1)) done echo "$branches" # 解析分支信息 echo "$branches" | jq -c '.[] | select(.protected == false)' | while read -r branch; do branch_name=$(echo "$branch" | jq -r '.name') echo -e "rn" echo " " echo "-------- [$branch_name] --------" echo "check branch: [$branch_name]" # 跳过 'release' 和 'master' 分支 if [ "$branch_name" == "release" ] || [ "$branch_name" == "master" ]; then echo "Skipping branch: [$branch_name]" continue fi # 获取分支的最后一次提交时间 last_commit_date=$(echo "$branch" | jq -r '.commit.committed_date') last_commit_timestamp=$(date -d "$last_commit_date" +%s) echo "[$branch_name] last_commit_date: $last_commit_date" echo "[$branch_name] last_commit_timestamp: $last_commit_timestamp, $three_months_ago" # 检查最后一次提交时间是否早于三个月前 if [ "$last_commit_timestamp" -ge "$three_months_ago" ]; then echo "Branch $branch_name has recent activity. Skipping..." continue fi # 检查分支是否合并到 release merge_requests=$(curl --silent --header "PRIVATE-TOKEN: $PRIVATE_TOKEN" "$GITLAB_URL/api/v4/projects/$PROJECT_ID/merge_requests?state=merged&source_branch=$branch_name") has_merged_to_release=$(echo "$merge_requests" | jq -e '.[] | select(.target_branch == "release")' > /dev/null; echo $?) echo "[$branch_name] merge status: $has_merged_to_release" # 如果没有合并到 release,则跳过 if [ "$has_merged_to_release" -ne 0 ]; then echo "Branch [$branch_name] has not been merged to release. Skipping..." continue fi # 检查分支是否有标签 has_tag=$(echo "$tags" | jq -e --arg branch "$branch_name" '.[] | select(.commit.id == $branch)' > /dev/null; echo $?) # 如果没有标签,则删除分支 if [ "$has_tag" -ne 0 ]; then echo "Deleting branch: [$branch_name]" curl --request DELETE --header "PRIVATE-TOKEN: $PRIVATE_TOKEN" "$GITLAB_URL/api/v4/projects/$PROJECT_ID/repository/branches/$branch_name" deleted_branch="$deleted_branch$branch_name"$'n' fi echo "delete: $deleted_branch" done only: - schedules
这段代码的作用是,通过一系列的操作,筛选出那些已经合并到release分支、没有标签,并且最后提交时间早于三个月前的分支,然后将它们删除。
(二)添加定时任务
配置好流水线任务后,这个任务默认不会在每次常规的流水线任务中执行,只有被定时任务调度时才会运行。接下来我们就需要添加定时任务。
- 进入仓库的
build→pipeline_schedules
。 - 开始添加定时流水线的配置:
- “desc”这个字段可以随便填写,主要用于给自己做个备注,方便识别这个定时任务是干什么的。
- “Interval Pattern”用来设置定时的频率。比如
15 14 * * 5
,它表示每周五的14:15:00执行一次。这里的设置可以根据自己的需求调整,比如你想每天凌晨2点执行,就可以设置成0 2 * * *
。 - 时区默认选择北京就行,如果你的项目有特殊要求,也可以根据实际情况调整。
- “MONTHS_AGO”变量用来设置多久前未合并的分支才会被删除,不填的话默认是3个月。你可以根据项目的实际情况,把这个时间改长或者改短。
- 保存好配置后,可以手动执行一次,看看实际效果如何。要是有问题,也能及时调整。
(三)完成配置
按照上面的步骤一步步操作,配置完成后,GitLab就会按照我们设定的规则,自动删除那些过期的合并分支啦!以后再也不用手动一个个去删了,是不是很方便?
三、逻辑实现原理
其实这个自动删除过期合并分支的功能,本质上就是一个shell脚本。它的核心逻辑主要有以下几步:
- 获取所有分支:通过
$GITLAB_URL/api/v4/projects/$PROJECT_ID/repository/branches?per_page=$per_page&page=$page
这个接口,就可以把项目里的所有分支都获取到。因为分支数量可能比较多,所以这里使用了分页的方式,一页一页地把所有分支数据都收集起来。 - 筛选分支名并跳过特定分支:利用
jq
命令把获取到的分支数据进行拆解,得到每个分支的名字。同时,跳过那些名字是release
和master
的分支,这两个分支一般比较重要,不能随便删。 - 获取分支最后提交时间:通过
jq -r '.commit.committed_date'
这个命令,能获取到每个分支对应的最后提交时间。然后把这个时间转换成时间戳的形式,方便后续比较。 - 过滤近期有活动的分支:根据设定的时间(默认三个月前),过滤掉那些最后提交时间晚于这个时间的分支,因为这些分支近期还有人在使用,不能删除。
- 检查分支是否合并到release:使用
$GITLAB_URL/api/v4/projects/$PROJECT_ID/merge_requests?state=merged&source_branch=$branch_name
这个接口,查看每个分支是否存在合并请求,并且检查是否已经合并到release
分支。如果没有合并到release
,那就跳过这个分支,不进行删除操作。 - 检查分支是否有标签:查看分支是否被人为标注了tag,如果有标签,说明这个分支可能还有用,也不删除。
- 删除符合条件的分支:对于那些已经合并到
release
、没有标签,而且最后提交时间早于三个月前的分支,使用$GITLAB_URL/api/v4/projects/$PROJECT_ID/repository/branches/$branch_name
这个接口,把它们删除掉。
四、后续改进方向
目前这个方案虽然能实现自动删除过期合并分支的功能,但还有可以优化的地方。比如,现在的配置还不够灵活,后续可以考虑增加一些自动配置的方式,让大家能更方便地根据不同项目的需求,调整删除分支的规则。这样一来,无论是大项目还是小项目,都能更轻松地管理自己的分支啦!
希望今天分享的这个GitLab自动删除过期合并分支的方法,能帮助到正在为分支管理发愁的小伙伴们。要是在操作过程中有什么问题,或者有更好的建议,欢迎在评论区留言交流哦!