背景:
由于公司项目管理需要,对开发人员的提交日志进行规范性约束。作为兼职的devops工程师,责无旁贷的去吭哧吭哧的研究了。公司主要使用git管理代码,gogs托管。作为领导眼中分分钟解决的问题,在真实上手研究还是需要一些时间成本的(鄙人主职还是研发)。
思路:
1、利用度娘和biying搜索了大量解决方案,发现都是指向git hook这个钩子来实现具体的业务场景。
比如 [1] 通过修改客户端的prepare-commit-msg.sample和commit-msg.sample,实现客户端的commit校验,但必须开发人员自己在库中的git/hook目录下修改相应文件,很难控制约束不太自觉的人员;又如 [2] 以Android项目为例子,使用Gradle脚本,当用户执行构建操作的时候,我们执行配置提交模板的脚本,通过脚本将配置的模板拷贝到用户的".git/hooks"目录下。再如 [3] 提出了一种解决.git文件夹不会被git跟踪,所以.git/hooks目录下的hooks钩子无法提交,就不能和他人共享钩子脚本。通过第三方的插件如:husky和yorkie解决上述问题。但上述三种方案都是在客户端侧对git提交的注释进行约束,不太能满足我们的诉求。
2、[3] 和 [4] 中还描述了hook是分客户端hook和服务器hook的,pre-receive、update和post-receive是服务器hook,只需要修改对应代码库的服务器hook文件,就可以对所有开发人员的push 提交注释进行校验。于是思考服务器hook也许可以解决我们的问题。
3、思考如何在执行pre-receive时获取注销,并对注释格式进行校验。[5] 和[6] 给了我启发。
解决方案
1、修改代码库中git/hook目录下的pre-receive
regex="^修改类型:(新功能|缺陷) TB编号\+主题:.{1,100} 是否自测:(是|否)" echo "regex: "$regex ## 定义注释出错提示信息 tips_msg="修改类型:新功能/缺陷 TB编号+主题: 是否自测:是/否" validate_commit_message() { oldrev=$(git rev-parse $1) newrev=$(git rev-parse $2) refname="$3" #echo 'Old version: '$oldrev #echo 'New version: '$newrev #echo 'Branch: '$refname ## git 命令 #GITCMD="git" ## 按时间倒序列出 commit 找出两个版本之间差异的版本号集合 oldrev~newrev commitList=`git rev-list $oldrev..$newrev` #echo 'commitList: '$commitList split=($commitList) #echo 'split: '$split # 遍历数组 for s in ${split[@]} do #echo “$s” #通过版本号获取仓库中对象实体的类型、大小和内容的信息 #比如提交人、作者、邮件、提交时间、提交内容等 currentContent=`git cat-file commit $s` #echo 'Commit obj: '$currentContent #获取提交内容 msg=`git cat-file commit $s | sed '1,/^$/d'` #echo 'msg: '$msg ## merge合并分之直接放行 if [[ $msg == *"Merge branch"* ]]; then echo "Merge branch...skip the checking" else ## 做内容校验 match=`echo $msg | grep -nE "(${regex})"` echo 'Match result: '$match ## 找到匹配说明是符合规范的 if [ "${match}" != "" ]; then ## 校验注释长度 msg_length=${#msg} #echo "Msg length: ${msg_length}" if [[ ${msg_length} -lt ${COMMIT_MESSAGE_MIN_LENGTH} ]]; then echo -e "Error: Commit message should be bigger than ${COMMIT_MESSAGE_MIN_LENGTH} and current commit message length: ${msg_length}" exit 1 fi ### 找到匹配内容做相应处理,如fix ,校验pom文件等 #if [[ "${match}" =~ "fix:" ]]; then ## 如果是修补bug,规范有点获取到fix中的ID,然后调用禅道对外的API关闭,其他场景类似 #fi # 是否开启校验和master分之 isMaster=$(echo $refname | grep "master$") if [ -n "$isMaster" ]; then # 如果是master分之,并且pom文件发生了变更,判断pom文件是否含有sonapshot的引用 pomfile=`git diff --name-only ${oldrev} ${newrev} | grep -e "pom\.xml"` if [[ "${pomfile}" != "" ]]; then #echo $pomfile ## 获取pom文件更新的内容 pomcontent=`git show $newrev:$pomfile` #echo $pomcontent ## 校验pom文件是否包含snapshot版本 if [[ $pomcontent =~ 'SNAPSHOT' ]]; then echo -e "Error: Snapshot version cannot exist in master branch!" exit 1 fi fi fi ## 其他操作 echo "Commit Success!" else echo -e "Error: Commit comments message should be started with [${tips_msg}]..." exit 1 fi fi done } ####### 执行入口########### pre_receive() { validate_commit_message $1 $2 $3 } if [ -n "$1" -a -n "$2" -a -n "$3" ]; then # Output to the terminal in command line mode - if someone wanted to # resend an email; they could redirect the output to sendmail # themselves #pre_receive $2 $3 $1 echo $1'+'$2'+'$3 else while read oldrev newrev refname do #pre_receive $oldrev $newrev $refname echo "1" echo $oldrev' '$newrev' '$refname echo "2" pre_receive $oldrev $newrev $refname done fi "/home/git/gogs/gogs" hook --config='/home/git/gogs/custom/conf/app.ini' pre-receive
2、commit后 push到远端服务器 若注释不符合规范
3、git commit --amend 修改注释 [7]
4、修改注释成满足要求格式后push成功
参考:
[1] https://zhuanlan.zhihu.com/p/456519458
[2] https://juejin.cn/post/7208111879151009848
[3] https://juejin.cn/post/6974301879731748900
[4] https://git-scm.com/book/en/v2/Customizing-Git-Git-Hooks
[5] https://blog.csdn.net/xiaoll880214/article/details/105916898
[6] https://www.zhihu.com/question/65604891
[7] https://blog.csdn.net/c46550/article/details/116574128
标签:git,##,echo,newrev,提交,msg,commit,日志 From: https://www.cnblogs.com/cosmocosmo/p/17525208.html