本文由风萧萧梦潇投稿,转载请注明出处。若有错误,请不吝指正。html
在工做中,咱们一般使用git来管理代码,当咱们对代码进行某项改动后,均可以经过git commit对代码进行提交。git规定提交时必需要写提交信息,做为改动说明,保存在commit历史中,方便回溯。但你仔细研究过git commit吗?或者换句话说你注意过应该怎样写commit信息和优化commit信息吗?本文将回答这些问题,但愿对你们有所帮助。node
为了对每次提交进行提交说明,方便以后回溯和团队协做,Git 每次提交代码,都要写 Commit message(提交说明),不然就不容许提交。当参与团队协做时,咱们共同维护一个maste或dev的代码,若是其余人改动了仓库代码,咱们确定想知道他到底改动了什么,此次改动会对咱们有什么影响。怎么看呢,直接看代码确定没错,但不是最好的方式。其实最方便的方式就是查看提交历史了。若是提交信息写的足够好的话,不须要看代码咱们也清楚改动了什么,这样就能够提升协做效率和沟通成本了。git
试想谁不想看到下面这样优雅清晰明了提交历史呢,若是再能自动生成ChangeLog文档天然是极好的。我想没有哪一个程序员能抵挡得住这种诱惑吧。程序员
整体来讲,规范 commit信息的意义以下:github
鉴于此,咱们须要写出清晰规范的git commit。那么什么的规范的commit信息呢,请继续看下去。shell
为引导用户为开源社区作贡献,angular较早提出了进行pr时的commit说明规范(详见Git Commit Guidelines),后被不少开源项目所接受,造成了一套约定式提交规范。首先让咱们从一条提交记录出发看一下angular是如何写提交信息的。 npm
如上所示,angular提交信息遵循以下格式:json
<type>(<scope>): <subject> # header信息头必须
<BLANK LINE>
<body> # 信息体
<BLANK LINE>
<footer> # 结束部分
复制代码
header 信息头(必须)<type>(<scope>): <subject>
vim
信息头必需要有type,它严格限定为以下值:windows
feat: A new feature
fix: A bug fix
docs: Documentation only changes
style: Changes that do not affect the meaning of the code (white-space, formatting, missing semi-colons, etc)
refactor: A code change that neither fixes a bug nor adds a feature
perf: A code change that improves performance
test: Adding missing or correcting existing tests
chore: Changes to the build process or auxiliary tools and libraries such as documentation generation
复制代码
另外若是本次提交是回退以前的提交,应该以revert:开头,跟着要回退提交的header信息,在body中写:This reverts commit <hash>
其余开源项目的type类型也相似,像electron的type类型以下所示,详见Commit message guidelines:
fix: A bug fix
feat: A new feature
docs: Documentation changes
test: Adding missing tests or correcting existing tests
build: Changes that affect the build system
ci: Changes to our CI configuration files and scripts
perf: A code change that improves performance
refactor: A code change that neither fixes a bug nor adds a feature
style: Changes that do not affect the meaning of the code (linting)
vendor: Bumping a dependency like libchromiumcontent or node
复制代码
接下来是scope。它指定了本次提交的影响范围,好比数据层、控制层、视图层等等,视项目不一样而定。若是影响范围较大,可使用通配符*。scope能够忽略。
最后是subject,指出本次提交的主题,是对本次提交的简短描述,不超过50个字符。注意它和前面的冒号之间要有空格,和type同样,必需要有。subject内容有如下规定:
type和subject决定了本次提交信息的质量,是灵魂所在。
body 信息体(可忽略)
是对header中subject的补充,能够写一些本次提交改动了哪里和有什么影响等内容。注意时态一样要使用通常如今时,好比改动要写change,不能用changed或changes。
footer 信息尾部(可忽略)
尾部能够包含一些相似作出了哪些重大改变这样的内容,也能够写关闭了那些issue。另外Breaking Changes要以BREAKING CHANGE:
打头,后面跟空格或两个新行和具体内容。关闭了那些bug要使用Closes
打头,哪怕只关闭了一个,例如Closes #234
angular关于commit message的详细规范请参见Git Commit Message Conventions文档。
看来要写出符合git commit规范的信息也是不容易的,不过社区也为咱们提供了一些辅助工具来帮助进行提交,下面根据使用目的来简单介绍一下这些工具。
cz-cli 是一款能够交互式创建提交信息的工具。它帮助咱们从type开始一步步创建提交信息,具体效果如图所示,经过上下键控制指向你想要的type类型。
注意:
- windows下使用git bash 运行该工具不能上下选择,可使用powershell代替。
- 此工具要配合adapter(相似模板)使用,来提供交互提交的样式包括type类型和提交的结构,可自定义。
全局环境下安装使用方法以下:
# 须要同时安装commitizen和cz-conventional-changelog,后者是adapter
$ npm install -g commitizen cz-conventional-changelog
# 配置安装的adapter
$ echo '{ "path": "cz-conventional-changelog" }' > ~/.czrc
# 使用
$ git cz
复制代码
本地环境下(非全局安装)使用方法以下:
# 安装commitizen
$ npm install --save-dev commitizen
# 接下来安装适配器
# for npm >= 5.2
$ npx commitizen init cz-conventional-changelog --save-dev --save-exact
# for npm < 5.2
$ ./node_modules/.bin/commitizen init cz-conventional-changelog --save-dev --save-exact
// package.json script字段中添加commit命令
"scripts": {
"commit": "git-cz"
}
// use
$ npm run commit
// 若是不但愿每次使用npm run commit写提交信息的话,可使用git hook,把git commit命令替换成交互式提交,注意windows下不生效
"husky": {
"hooks": {
"prepare-commit-msg": "exec < /dev/tty && git cz --hook",
}
}
复制代码
commitlint是一款提交信息校验工具,原理是可用git hooks在真正进行git commit入库操做前对信息进行验证,不符合规则的commit信息将会被阻止提交入库,以下所示。
使用方式也很简单:
# 安装 commitlint cli and conventional config
$ npm install --save-dev @commitlint/{config-conventional,cli}
# Windows下自带命令行工具不会识别/{x,x},因此使用如下语句安装
$ npm install --save-dev @commitlint/config-conventional @commitlint/cli
# 生成commitlint配置文件,这步是必须的,否则提交会报错,达不到效果
$ echo "module.exports = {extends: ['@commitlint/config-conventional']}" > commitlint.config.js
复制代码
注意:使用commitlint时须要创建校验文件commitlint.config.js,否则会校验失败
若是你们本身写过git hooks,那么能够把commitlint添加到git commit前的校验中,若是不是很熟的话能够借助一些工具,好比husky。
# 安装husky
$ npm i -D husky
# package.json文件添加以下字段
"husky": {
"hooks": {
"commit-msg": "commitlint -E HUSKY_GIT_PARAMS"
}
}
复制代码
固然若是认为遵照规则很累,能够在git commit时使用 --no-verify参数跳过验证,直接提交。不过这样使用该插件就没意义了。因此尽可能保证本身写的commit信息符合规范。
changelog是改动日志,包含咱们发布的版本信息,以及每次版本更新的东西。
conventional-changelog-cli是一款changelog生成工具,经过提取commit信息(默认提取类型为feat、fix和包含breaking change的提交信息)为咱们自动化生成changelog文档。
全局使用方法以下:
# 安装conventional-changelog-cli
$ npm install -g conventional-changelog-cli
$ cd my-project
# 保留原changelog文档,生成本次改变
$ conventional-changelog -p angular -i CHANGELOG.md -s
# 彻底从新生成changelog文档
$ conventional-changelog -p angular -i CHANGELOG.md -s -r 0
复制代码
若是不想全局安装的话,可使用npm run script方式运行,以下所示
$ npm i -D conventional-changelog-cli
// package.json script字段中添加version命令
"script": {
"version": "conventional-changelog -p angular -i CHANGELOG.md -s && git add CHANGELOG.md"
}
// use
$ npm run version
复制代码
conventional-changelog-cli生成changelog是根据到目前为止的全部提交信息同最新一次tag做比较获得的全部feature、bug、breaking change信息进行文档的生成,因此要在每次版本更新并生成changelog文档后对分支打tag,再push到远程分支。
这里摘取conventional-changelog-cli推荐的总体流程:
社区一样提供了一些高级工具来自动化进行上述的某些流程,能够说提供了一条龙服务。具体工具以下:
standard-version: 更新版本、生成changelog、打tag
semantic-release: 更新版本、生成changelog、打tag、推送代码发布
具体使用方法请自行查看文档,这里再也不赘述。
前面讲了这么多git commit规范,可能你们要问了,我也准备从如今开始写符合规范的提交信息,那以前项目中的不符合规范的信息怎么办呢?其实以前的提交信息也是有办法修改的,关键就是使用git rebase
命令。此外还有一个问题就是我写了不少条提交信息,但其实都是干的同一件事(这很常见,好比说要修复某个bug,改好以后发现这个bug在其余设备上并无改好,因而又改好以后提交了一次,但都是改的同一个问题),有办法将他们合并成一条吗?其实有的,关键也在于git rebase
。是否是瞬间感受这个命令很强大,想要火烧眉毛的试一下呢。
好吧,不卖关子了,直接来到正题,如何使用git rebase
进行变基操做。先说一下若是直接使用git rebase [target-branch]
,虽然能够帮咱们在本分支基于目标分支进行变基操做,但它只会让两个分支的全部提交连成一条线,不能修改具体提交信息,因此须要使用git rebase -i
进行交互式操做。首先了解一下git rebase -i
的几个操做。
另外还要知道git rebase --continue
命令用来告诉git继续进行合并,通常在解决冲突后使用(通常来说若是全部的提交没有冲突的话,能够一直走下去,直到出现成功的提示。但若是两次提交合并涉及到冲突,就须要解决冲突并在git add后使用该命令继续走下去);git rebase --abort
命令用来终止变基操做,通常在不想进行rebase时使用(大部分时间是由于玩脱了,rebase到了一种不可预知的地步,不知道干啥了,就只能终止了)。直到出现相似“Successfully rebased and updated refs/heads/dev.”的消息就说明本次变基成功了。下面具体讲一下如何修改和美化提交信息。
修改提交信息能够分为如下几个步骤,固然具体步骤还要具体状况具体分析,有些能够忽略。
暂存工做状态:使用git stash
将当前工做状态进行暂存,若是没有须要暂存的工做状态请忽略
转到须要修改的提交上:使用git rebase -i [commit-id]^
将 HEAD 移动到须要修改的 commit-id 上,由于该[commit-id]也在修改之列,因此要基于它的上一个提交变基,或者直接使用[commit-id]^
将pick修改成想要进行的操做命令:进行编辑时通常要把全部须要修改的commit的pick改成r或e,提示:若是多的话可使用vim的全局替换
从新编辑commit信息
附加修改:若是须要在该分支上修改其余内容,能够在改动文件后直接使用git add
将其添加到暂存区,并使用 git commit –amend
追加改动到提交。若是不须要请忽略
继续进行变基操做:使用git rebase –continue
继续,通常若是提交没有冲突或者附加修改的话,不须要手动输入,git会自动进行下一次操做。
变基完成:重复以上步骤,直到出现变基成功文字。若是暂存过工做状态,须要使用git stash pop
恢复以前的工做状态,结束。
咱们大多数时候只会使用git merge
来将开发代码合并到主分支。不过这样会致使主分支包含咱们合并分支的全部提交信息。久而久之,会让commit history愈来愈繁杂,但其实合并的代码彻底能够用一条提交信息好比feat: 添加某项新特性
来代替。固然还有其余缘由会致使commit信息重复且没必要要。好比当咱们在拿不许bug到底有没有修复成果时可能会屡次改动代码进行测试,若是每次改动测试都进行了提交,就会产生屡次commit信息,若是不对这些commit作合并的话,在咱们将代码合并到开发主分支时就会产生不少繁杂的commit信息,不过因为这些commit信息都是为解决一样的事情服务的,彻底能够合到一块儿。因此若是你嫌弃commit信息太啰嗦冗余,那么就须要对其进行美化了。美化主要有两种方式:git rebase
和 git merge --squash
,这里将介绍它们的使用,并进行对比。
rebase merge
注意:若是要合并的commit历史过多而且对git rebase命令使用不熟练,请慎用,否则可能会被各类冲突逼疯的!
若是咱们想将dev的提交信息进行美化并合并到master分支,能够进行以下操做:
git checkout dev
git rebase -i master
,其中具体的操做请参见上一小节,不一样的不过是把一些提交的pick改成s而已,即提交信息合并到上一次提交。git checkout master
git merge dev
squash merge
一样以dev分支合并到master为例:
git checkout master
git merge --squash dev
两种方式都能实现提交信息的合并,保持 master 分支干净整洁。不过它们也有很大不一样。
squash merge会把分支的全部提交一股脑应用在目标分支上,而后你要修改冲突后再提交,生成一次commit,而此次commit包含dev的全部改动。产生的此次新的commit的做者天然也就是作了本次将dev分支合并到master分支操做的人,他可能并非原dev分支的做者,也就掩盖了真实的做者。此外不管改动有多少,只会产生一次提交记录。
rebase merge拥有更高的可操做性,它容许咱们能够选择保留几条有意义的提交,而不像squash merge只有一条。固然有更高的操做自由度也意味着步骤比较繁琐,不像squash merge简单方便。固然变基操做完成后在主分支上使用git merge
进行合并,原做者信息会获得保留。
总之,若是你想要更快进行提交合并,能容忍原做者信息丢失的话,能够选择squash merge;若是你想要保留多条有意义的提交信息和须要保留原做者信息的话,rebase merge可能要更适合你。
话说回来,其实git rebase
命令很是强大,不只能作本分支commit信息的修改、合并,还能使用git rebase [startpoint] [endpoint] --onto [branchName]
将本分支的某一段commit集合合并到另外一分支。嗯,git非常博大精深呢,要想达到精通,我还有很长一段路要走!