章
目
录
一、背景:分支管理的烦恼
在项目开发过程中,随着越来越多开发人员参与进来,各种分支不断涌现。很多时候,大家在将代码合并到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 "\r\n"
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自动删除过期合并分支的方法,能帮助到正在为分支管理发愁的小伙伴们。要是在操作过程中有什么问题,或者有更好的建议,欢迎在评论区留言交流哦!