git提交规范
一个好的COMMIT MESSAGE非常重要:
- 可以让其它开发人员清楚知道每个commit的变更内容。
- 可以基于COMMIT MESSAGE进行过滤查找。
- 基于规范的COMMIT MESSAGE可以生成Change Log。
- 可以依据某些类型的Commit Message触发构建或者发布流程。
- 根据提交的类型来确定语义化版本号。
业界使用最多的就是Angular规范。其每个提交都是有意义的,并且提交的格式都是规范的,同样可以识别规范,从而帮助我们自动化完成某些工作。就如前面所说的生成Change log等等。
在Angular规范中,COMMIT MESSAGE包含三部分:Header,Body,Footer。格式如下:
<type>[optional scope]: <description>
// 空行
[optional body]
// 空行
[optional footer(s)]Header是必须的,body和footer可以省略。==两个空行不可以省略,scope必须用()括起来,冒号紧接着前面的内容,冒号后面必须有一个空格==。
一个符合规范的提交如下:
fix($compile): couple of unit tests for IE9
# Please enter the Commit Message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
# On branch master
# Changes to be committed:
# ...
Older IEs serialize html uppercased, but IE9 does not...
Would be better to expect case insensitive, unfortunately jasmine does
not allow to user regexps for throw expectations.
Closes #392
Breaks foo.bar api, foo.baz should be used insteadHeader
包括type,subject和可选的scope。
对于type类型,看下图:
对于代码的变更,如果不符合feat、fix、perf、style四种,那么就作为refactor。对于非代码类的变更,如果不符合test、ci、docs,就归于chore。
scope用来说明commit的影响范围,必须是名词,范围不能太小,否则难以维护。
subject是对commit的简短描述,必须以动词开头,使用现在时,第一个字母必须小写,句子的末尾不能够加英文句号。
Body
对本次提交的更详细的描述。格式比较自由,但是也要以动词开头,使用现在时。需要包括修改的动机,与上一次提交的改动点。
Footer
用来说明本次提交造成的后果。 在实际应用中,Footer通常用来说明不兼容的改动和关闭的issue列表。
BREAKING CHANGE: <breaking change summary>
// 空行
<breaking change description + migration instructions>
// 空行
// 空行
Fixes #<issue number>- 不兼容的改动:以BREAKING CHANGE开头,跟上不兼容的摘要。其它部分需要说明变动的描述,理由和迁移方法。
- 关闭issue列表:新建一行,以
Closes开头列出,例如Closes #123和Closes #123, #456, #789。
Revert Commit
这是一种特殊的情况,即当前的commit还原了先前的commit,那么以revert:开头,后面跟着还原的commit的Header。Body必须写为This reverts commit <HASH>,其中HASH就是还原的提交的SHA标志。
例如:
revert: feat(iam-apiserver): add 'Host' option
This reverts commit 079360c7cfc830ea8a6e13f4c8b8114febc9b48a.重要内容
提交频率
不要随意提交commit。随意提交会让COMMIT MESSAGE变得难懂。 提交有两种方式:
- 完成一个Buf的修复、开发完一个小功能、开发完一个完整的功能。
- 规定一个时间定期提交。例如下班前。
按照上面的工作方式,本地的COMMIT比较多,比较杂乱。因此在把代码远程合并和进行Pull Request之前,执行git rebase -i合并之前的所有commit。
合并提交
将多个commit合并成一个commit。可以让commit记录变得简介有意义 。
完成这个功能使用的就是git rebase命令。用来重写commit历史。
通常使用git rebase -i <commit ID>命令,其中-i参数表示交互的意思,即进入到交互页面,对commit进行一些操作。
会列出给出commit ID之后(不包括,越下面越新)的所有提交,每个commit前有一个操作命令,默认是pick,通过修改其命令,来对此commit执行不同的变更操作。
git rebase支持的变更操作如下:
| 命令 | 目的 |
|---|---|
| p,pick | 不对该commit做任何处理 |
| r,reword | 保留此commit, 但是修改提交信息 |
| e, edit | 保留此commit,但是rebase时会暂停,允许修改这个commit |
| s,squash | 保留此commit,但是会将此commit与上一个commit合并。 |
| f,fixup | 与squash相同,但是不会保存当前commit的提交信息。 |
| x,exec | 执行其它shell命令 |
| d,drop | 删除此commit |
通常使用squash和fixup来合并提交。
例如使用squash合并
pick 07c5abd Introduce OpenPGP and teach basic usage
s de9b1eb Fix PostChecker::Post#urls
s 3e7ee36 Hey kids, stop all the highlighting
pick fa20af3 git interactive rebase, squash, amend会将第二个和第三个提交合并到第一个提交,最终生成两个提交,第一个提交包含三个提交的提交信息。
如果使用fixup来合并:
pick 07c5abd Introduce OpenPGP and teach basic usage
s de9b1eb Fix PostChecker::Post#urls
f 3e7ee36 Hey kids, stop all the highlighting
pick fa20af3 git interactive rebase, squash, amend同样会将第二个和第三个提交合并到第一个提交,也会最终产生两个提交,但是第一个提交中的提交信息里,第三行提交会被注释掉。
一个合并提交的完整示例
每次开发一个新功能,通常就新建一个分支,开发完成之后再合并到主分支。
- 新建一个分支。
git checkout -b feature/user此时的提交记录如下:
$ git log --oneline
7157e9e docs(docs): append test line 'update3' to README.md
5a26aa2 docs(docs): append test line 'update2' to README.md
55892fa docs(docs): append test line 'update1' to README.md
89651d4 docs(doc): add README.md- 然后在这个分支下完成功能 在完成功能的期间可能会产生多次提交。例如下列记录
$ git log --oneline
4ee51d6 docs(user): update user/README.md
176ba5d docs(user): update user/README.md
5e829f8 docs(user): add README.md for user
f40929f feat(user): add delete user function
fc70a21 feat(user): add create user function
7157e9e docs(docs): append test line 'update3' to README.md
5a26aa2 docs(docs): append test line 'update2' to README.md
55892fa docs(docs): append test line 'update1' to README.md
89651d4 docs(doc): add README.md在feature/user分支上产生了5个提交。现在开发完毕,想要将此分支合并到主分支,但是提交记录太多,于是先进行合并。
3. 合并commit
要合并feature/user上的5个提交,就要将commit id设置为要合并的提交的父commit ID,例如合并fc70a21~4ee51d6,git rebase -i的commit id就是7157e9e。
git rebase -i 7157e9e对需要合并的commit执行squash操作,然后wq保存后,就可以编辑合并后的提交的COMMIT MESSAGE。在wq保存退出后,commit合并结束。 4. 将开发完成的分支合并到主分支上
git checkout master
git merge feature/user修改Commit Message
对于某次不符合要求的提交,可能需要对其Commit信息进行修改。
可以使用git commit --amend修改最近一次的commit的message。输入此命令,进入交互页面,直接提交即可。
如果要修改某次的提交信息,同样可以git rebase -i命令来修改,不同的是,只需要对需要更改的提交执行r命令,wq后进入交互页面修改提交信息,再次wq操作完成。
修改commit message后,commit id也会发生变化。
如果执行分支操作的时候,当前分支有未提交的代码,那么可以执行git stash暂存工作状态,修改完成后再执行git stash pop恢复工作状态。
Commit Message规范化
既然要求规范化,那么人工都难以避免出错,因此使用工作自动化进行生成和检查Commit Message就是可以预见的。
- Commit message生成和检查:生成符合Angular规范的Commit message。提交前检查,历史commit message检查。
- 基于commit message自动生成CHANGELOG 和 语义化版本号。
有下列5中工具来完成这些:
- commitizen-go:进入交互模式,并根据提示生成Commit Message,然后提交。
- commit-msg:githooks,指定检查的规则
- go-gitlint:检查历史提交的Commit Message是否符合Angular规范,可以将此工具添加到CI流程中,确保生成的Commit Message都是符合规范的。
- gsemver:语义化版本自动生成工具。
- git-chglog:根据Commit Message生成CHANGELOG。