Git使用规范
前言
在项目开发开发中或许我们能经常看到
1、git操作很随意,临上线了,发现多出了很多非上线内容的代码
2、commit 信息写的很随意,commit 信息和变更代码之间不能建立联系的
3、提交的commit与任务详情无法关联
为了解决以上问题,我们制定了本规范
规范目的
1、规范操作流程,防止出现意料之外的情况
2、与Jira联动,回溯任务详情
3、规范提交记录,方便追溯定位问题
规范内容
常用分支
1、develop:开发环境正在运行的代码分支,用于前后端开发联调
2、release:测试环境正在运行的代码分支,用于测试同事进行测试
3、gray:灰度环境正在运行的代码分支,用于上线前的灰度测试
4、master:生产环境正在运行的代码分支
开发流程
- 开发前:每次开发新功能,必须从最新的 master 分支 checkout 出一个新的开发分支
- 开发中:如果涉及到前后端开发联调,请将开发分支提交 merge request 到 develop 分支进行联调,由开发人员自己操作合并
- 开发完成:将开发分支提交 merge request到 master 分支,并指给负责人 Code Review
- 测试:将开发分支提交 merge request 到 release 分支进行测试,由开发人员自己操作合并
- 灰度测试:将开发分支提交merge request 到 gray分支进行测试,由负责人操作合并
- 测试完成后:将开发分支代码提交 merge request到 master 分支,并指给负责人 Code Review,之后由负责人操作合并
- 合并代码后:从合并后的 Master 分支打一个新 Tag 版本号,然后使用部署系统发布上线
规范要求
1、每次开发新功能,都应该新建一个单独的分支
2、新的开发分支必须是基于最新的master
3、分支命名必须按照格式:{分支创建时间}-{LDAP开发者账号}-{业务or开发版本} ,比如20210712-zmmeng-clue,20210712-zmmeng-clue0200,第三部分能明确开发内容即可
4、每次提交代码,commit message必须符合规范
5、如果发生冲突,必须在本地解决
commit message规范
<type>(<scope>): <subject>
<空行>
<body>
<空行>
<footer>
其中,Header 是必需的,Body 和 Footer 可以省略。
1.1 Header
Header部分只有一行,包括三个字段:type
(必需)、scope
(必需)、subject
(必需)
type
用于说明commit的类别,可以使用以下标识。
feat:新功能(feature)
fix:修补bug
docs:文档(documentation)
build: 影响构建系统或外部依赖项的更改(示例范围:compsoer更新版本号)
revert: 撤销上一次的 commit
merge: 代码合并
style: 格式
refactor: 重构
perf: 性能优化
test: 增加测试
init: 初次提交
add: 添加依赖
chore: 更改配置文件
ci: CI部署
del: 删除代码/文件
scope
用于说明需求的Jira编号,必须填写,比如:PER-123。
subject
是 commit 目的的简短描述,不超过50个字符。
1.2 Body
Body 部分是对本次 commit 的详细描述,可以分成多行。(换行用\n)
1.3 Footer
Footer 部分只用于两种情况。
- 不兼容变动
如果当前代码与上一个版本不兼容,则 Footer 部分以BREAKING CHANGE
开头,后面是对变动的描述、以及变动理由和迁移方法。
- 关闭Issue
如果当前 commit 针对某个issue,那么可以在 Footer 部分关闭这个 issue。也可以一次关闭多个 issue 。
fix #234
fix #123, #245, #992
关联工具
GitLab与Jira联动
可以每个项目单独配置,也可以一个Group整体配置
配置页路径:Setting(设置) -> Integrations(集成) -> Jira)
配置页面
- Web URL:Jira地址
- Jira API URL:通常和WebUrl相同
- 用户名或电子邮件:这里填写Jira中配置的账号
- 输入新的密码或 API 令牌: 根据上述账号填写
填写完成即可
Commit规范校验工具
利用Git的本地钩子&GitLab服务器钩子来实现自动校验
本地校验
添加本地commit-msg钩子实现自动校验
为了方便开发者安装自己本地的校验工具,编写了如下的脚本,执行之后自动安装 多次安装,后安装的会覆盖之前的
#!/bin/bash
#
# create hooks file
createFile()
{
target="$1"
cat > "$target" << 'END_TEXT'
#!/bin/sh
#
# An example hook script to check the commit log message.
# Called by "git commit" with one argument, the name of the file
# that has the commit message. The hook should exit with non-zero
# status after issuing an appropriate message if it wants to stop the
# commit. The hook is allowed to edit the commit message file.
#
# To enable this hook, rename this file to "commit-msg".
# Uncomment the below to add a Signed-off-by line to the message.
# Doing this in a hook is a bad idea in general, but the prepare-commit-msg
# hook is more suited to it.
#
# SOB=$(git var GIT_AUTHOR_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p')
# grep -qs "^$SOB" "$1" || echo "$SOB" >> "$1"
current_path="$PWD" # 同 "`pwd`"
angular_regex="^(feat|fix|docs|build|revert|merge|style|refactor|perf|test|init|add|chore|ci|del)+\(([A-Za-z]+-[0-9]+)\): (.+){1,50}"
merge_regex="^(Merge branch|Merge remote-tracking branch)(.+)+"
file="$current_path/$1"
commit_msg=`head -n 1 $file`
if egrep -iq "$merge_regex" "$file"; then
exit 0
fi
if ! egrep -iq "$angular_regex" "$file"; then
echo "ERROR:"
echo "ERROR: Your commit was rejected because the commit"
echo "ERROR: commit: $commit_msg"
echo "ERROR: is illegal. Example: 'feat(PER-123): This is a commit example.'"
echo "ERROR:"
echo "ERROR: Please fix the commit message and commit again."
echo "ERROR"
exit 1
fi
match=": "
msg=${commit_msg#*$match}
length=${#msg}
if [ $length -gt 50 ] ; then
echo "ERROR:"
echo "ERROR: Your commit was rejected because the commit"
echo "ERROR: commit: $msg"
echo "ERROR: is longer than 50. Example: 'feat(PER-123): This is a commit example.'"
echo "ERROR:"
echo "ERROR: Please fix the commit message and commit again."
echo "ERROR"
exit 1
fi
END_TEXT
`chmod +x $target`
}
# 项目同级目录执行生效
for file in ./*
do
# echo "$file"
if [ -d "$file/.git/hooks/" ];then
createFile "$file/.git/hooks/commit-msg"
echo "$file 项目安装成功"
fi
done
本地安装步骤
mac系统
# 进入代码项目同级目录,比如:code/
cd code/
vim createCommitMsgShell
# 写入上面的脚本内容,保存
chmod +x createCommitMsgShell
./createCommitMsgShell
windows系统
打开git bash操作窗口
# 进入代码项目同级目录,比如:code/
cd code/
vim createCommitMsgShell
# 写入上面的脚本内容,保存
chmod +x createCommitMsgShell
./createCommitMsgShell
建议:所有git项目放到同一个目录文件夹下,方便统一管理
远程校验
添加服务器pre-receive钩子实现自动校验
#!/bin/bash
#
# Reject pushes that contain commits with messages that do not adhere
# to the defined regex.
# This can be a useful pre-receive hook [1] if you want to ensure every
# commit is associated with a ticket ID.
#
# As an example this hook ensures that the commit message contains a
# JIRA issue formatted as [JIRA-<issue number>].
#
# [1] https://help.github.com/en/enterprise/user/articles/working-with-pre-receive-hooks
#
zero_commit='0000000000000000000000000000000000000000'
angular_regex='^(feat|fix|docs|build|revert|merge|style|refactor|perf|test|init|add|chore|ci|del)+\(([A-Za-z]+-[0-9]+)\): (.+){1,50}'
merge_regex='^(Merge branch|Merge remote-tracking branch)(.+)+'
match=": "
while read -r oldrev newrev refname; do
# Branch or tag got deleted, ignore the push
[ "$newrev" = "$zero_commit" ] && continue
# Calculate range for new branch/updated branch
[ "$oldrev" = "$zero_commit" ] && range="HEAD..$newrev" || range="$oldrev..$newrev"
for commit in $(git rev-list "$range" --not --all --after=1632650364); do
if git log --max-count=1 --format=%B $commit | egrep -iq "$merge_regex"; then
continue
fi
if ! git log --max-count=1 --format=%B $commit | egrep -iq "$angular_regex"; then
echo "ERROR:"
echo "ERROR: Your push was rejected because the commit"
echo "ERROR: $commit in ${refname#refs/heads/}"
commit_msg=`git log --max-count=1 --format=%B $commit`
echo "ERROR: commit: $commit_msg"
echo "ERROR: is illegal. Example: 'feat(PER-123): This is a commit example.'"
echo "ERROR:"
echo "ERROR: Please fix the commit message and push again."
echo "ERROR: https://help.github.com/en/articles/changing-a-commit-message"
echo "ERROR"
exit 1
fi
commit_msg=`git log --max-count=1 --format=%B $commit |head -1`
msg=${commit_msg#*$match}
length=${#msg}
if [ $length -gt 50 ] ; then
echo "ERROR:"
echo "ERROR: Your commit was rejected because the commit"
echo "ERROR: commit: $msg"
echo "ERROR: is longer than 50. Example: 'feat(PER-123): This is a commit example.'"
echo "ERROR:"
echo "ERROR: Please fix the commit message and commit again."
echo "ERROR"
exit 1
fi
done
done
单项目钩子
先找到项目的对应hash 路径
# 进入项目路径文件夹
cd \@hashed/d4/73/d4735e3a265e16eee03f59718b9b5d03019c07d8b6c51f90da3a666eec13ab35.git
mkdir -p custom_hooks/pre-receive.d/
vim custom_hooks/pre-receive.d/commit-msg
# 写入上面的脚本内容,保存
chmod +x -R ./custom_hooks
全局钩子
修改GitLab配置,gitlab_shell['custom_hooks_dir'],配置hooks路径
# 进入配置的hooks路径文件夹
cd hooks/
mkdir -p pre-receive.d/
vim pre-receive.d/commit-msg
# 写入上面的脚本内容,保存
chmod +x -R ./pre-receive.d
修改commit信息方式
- git commit --amend
- git rebase
- git rebase -i HEAD~5
- git switch -c 20210712-zmmeng-clue-rebase
- 具体参考git-rebase