前言
开发人员在使用git提交(commit)代码的时候,需要添加备注信息,但是很多人偷懒不愿意写或者写的很短。为了限制开发人员写过短的备注信息,需要在gitlab服务器端进行配置(客户端也可以,但这里配置的是服务端)
配置
服务端有两种配置方式,一种是全局的配置,一种是各个项目独立的配置。这里讲各个项目独立的配置:
- 选择一个项目,比如叫testGit
- 在git所在服务器后台,切换到git项目源代码存储的目录:如果使用的是docker镜像启动的gitlab, 源代码库目录一般位于/var/opt/gitlab/git-data/repositories/
/ .git,假设group叫test, 则路径就是/var/opt/gitlab/git-data/repositories/test/testGit.git目录。 - 在testGit.git目录创建一个新目录custom_hooks
- 在custom_hooks目录创建一个文件命名为pre-receive,并且可执行权限设置为777(或者设置其所在用户组和拥有者为gitlab)
- 添加脚本内容到pre-receive, 保存脚本内容,不用重启gitlab会立刻生效
脚本
下面是pre-receive文件的脚本内容,设置提交代码时的备注长度至少为5个英文字符(如果是中文字符,一个中文字符相当于3个英文字符)
#!/bin/bash
#pre-receive script
#set -x #for debugging
validate_ref()
{
# --- Arguments
oldrev=$(git rev-parse $1)
newrev=$(git rev-parse $2)
refname="$3"
commitList=`git rev-list $oldrev..$newrev`
#echo $commitList
split=($commitList)
for s in ${split[@]}
do
echo "@@@@@@@"
echo "$s"
msg=`git cat-file commit $s | sed '1,/^$/d'`
echo $msg
if [ ${#msg} -lt 5 ];then
echo "!!! Commit message length less than 5"
exit 1
else
echo "bigger than 5"
fi
done
}
fail=""
# Allow dual mode: run from the command line just like the update hook, or
# if no arguments are given then run as a hook script
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
PAGER= validate_ref $2 $3 $1
else
while read oldrev newrev refname
do
validate_ref $oldrev $newrev $refname
done
fi
if [ -n "$fail" ]; then
exit $fail
fi
开发人员在push代码(pull, commit的时候不会报错)的时候如果备注长度小于5个英文字符,就会提示报错:
改进
限制提交的comments备注必须为三行,第一行至少18个英文字符,第二行为空,第三行为30个英文字符
root@bob-k8s3:/srv/gitlab/data/git-data/repositories/root/pets.git/custom_hooks# cat pre-receive
#!/bin/bash
#pre-receive script
#set -x #for debugging
RED='\033[0;31m'
NC='\033[0m' # No Color
reverse() {
# first argument is the array to reverse
# second is the output array
declare -n arr="$1" rev="$2"
for i in "${arr[@]}"
do
rev=("$i" "${rev[@]}")
done
}
regex_list=(
'^test'
'^fix '
'^docs'
'^task'
'^refactor'
'^revert'
'^style'
'^chore'
'^Merge'
'^merge'
'^[ci skip]'
)
# Concatenate regex_list
separator="|"
regex="$( printf "${separator}%s" "${regex_list[@]}" )"
# remove leading separator
regex="${regex:${#separator}}"
validate_ref()
{
# --- Arguments
oldrev=$(git rev-parse $1)
newrev=$(git rev-parse $2)
refname="$3"
#echo $oldrev
#echo $newrev
GITCMD="git"
commitList=`git rev-list $oldrev..$newrev`
split=($commitList)
reverse split split2
for s in ${split2[@]}
do
#echo "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++"
echo "$s"
currentrev=$s
msg=`git cat-file commit $s | sed '1,/^$/d'`
#echo $msg
match=`echo $msg | grep -nE "(${regex})"`
if [ "${match}" != "" ]; then
#show all the changed files, between this push and last push, maybe one or more commits
changedFiles=$($GITCMD diff --stat --name-only --diff-filter=ACMRT ${oldrev}..${currentrev})
#echo $changedFiles
#if it is bug fixing
if [[ "${match}" =~ "fix" ]]; then
#check if there is unit testing commiting
if ! [[ $changedFiles =~ "src/test/" ]]; then
echo -e "${RED}Error: Need unit testing cases ${NC}"
#exit 1
fi
fi
# if pom.xml changed, make sure it can not chang the code coverage threshold
if [[ $changedFiles =~ "pom.xml" ]]; then
#check file contents, make sure no body change code coverage threshold
#codeCoverageKeyword=`git diff-tree -r -p --no-color --no-commit-id --diff-filter=d $s | grep -n ""`
codeCoverageKeyword=`git diff --unified=0 ${oldrev}..${currentrev} | grep -n ""`
if [ "${codeCoverageKeyword}" != "" ]; then
echo -e "${RED}Error: you can not change code coverage rate ${NC}"
#exit 1
fi
fi
else
echo -e "Error:${RED} comments should be started wih test or fix or task... ${NC}"
fi
# validate the git comments
if [[ $msg == *"Merge branch"* ]];
then
echo "Merge branch...skip the checking"
else
n=0
while read -r line; do
((n++))
# 1st line at least 18 english characters
if [ $n -eq 1 ] && [ ${#line} -lt 3 ];then
echo -e "Error:${RED} 1st line length should be bigger than 18${NC}: ${#line}"
#exit 1
fi
# 2nd line must be empty
if [ $n -eq 2 ] && [ ${#line} -gt 0 ];then
echo -e "Error:${RED} 2nd line length should be 0${NC}: ${#line}"
#exit 1
fi
# 3rd line at least 30 english characters
if [ $n -eq 3 ] && [ ${#line} -lt 30 ];then
echo -e "Error:${RED} 3rd line length should be bigger than 30${NC}: ${#line}"
#exit 1
fi
done <<< "$msg"
if [ $n -lt 3 ];then
echo -e "Error:${RED} You should commit with 3 lines comments${NC}: $n"
# exit 1
fi
fi
#change the oldrev to show file list and file contents between 2 commits
oldrev=$currentrev
done
}
fail=""
# Allow dual mode: run from the command line just like the update hook, or
# if no arguments are given then run as a hook script
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
PAGER= validate_ref $2 $3 $1
else
while read oldrev newrev refname
do
validate_ref $oldrev $newrev $refname
done
fi
if [ -n "$fail" ]; then
exit $fail
fi
第二行的空行是必须, 否则使用如下两个命令时就会格式错乱
$git log --oneline
$git shortlog
下图中第一个是第二行添加了空行右边会有三个点意思是可以点击这三个点查看更多信息,第二个是只有一行时的效果:
备注
- pre-receive会响应以任何形式的代码提交,比如命令行,比如通过gitlab网页
- 如果在pre-receive里`touch testme.txt", 默认会在pre-receive脚本所在目录的上一级目录里生成。
- 也可以在pre-receive里使用curl调用REST接口,比如gitlab的各种restful api
- 在linux下面提交多行备注的方法很简单,在备注内容中敲回车即可,但在windows中如果使用的是https://git-scm.com/, 方法就相对繁琐一点,要使用多个 -m