Git使用规范

520 阅读5分钟

优秀创作者-孟忠明.png


Git使用规范

前言

在项目开发开发中或许我们能经常看到

1、git操作很随意,临上线了,发现多出了很多非上线内容的代码

2、commit 信息写的很随意,commit 信息和变更代码之间不能建立联系的

3、提交的commit与任务详情无法关联

为了解决以上问题,我们制定了本规范

规范目的

1、规范操作流程,防止出现意料之外的情况

2、与Jira联动,回溯任务详情

3、规范提交记录,方便追溯定位问题

规范内容

常用分支

1、develop:开发环境正在运行的代码分支,用于前后端开发联调

2、release:测试环境正在运行的代码分支,用于测试同事进行测试

3、gray:灰度环境正在运行的代码分支,用于上线前的灰度测试

4、master:生产环境正在运行的代码分支

开发流程

  1. 开发前:每次开发新功能,必须从最新的 master 分支 checkout 出一个新的开发分支
  2. 开发中:如果涉及到前后端开发联调,请将开发分支提交 merge request 到 develop 分支进行联调,由开发人员自己操作合并
  3. 开发完成:将开发分支提交 merge request到 master 分支,并指给负责人 Code Review
  4. 测试:将开发分支提交 merge request 到 release 分支进行测试,由开发人员自己操作合并
  5. 灰度测试:将开发分支提交merge request 到 gray分支进行测试,由负责人操作合并
  6. 测试完成后:将开发分支代码提交 merge request到 master 分支,并指给负责人 Code Review,之后由负责人操作合并
  7. 合并代码后:从合并后的 Master 分支打一个新 Tag 版本号,然后使用部署系统发布上线

img

规范要求

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