内容简介:本文由风萧萧梦潇投稿,转载请注明出处。如有错误,请不吝指正。在工作中,我们通常使用git来管理代码,当我们对代码进行某项改动后,都可以通过git commit对代码进行提交。git规定提交时必须要写提交信息,作为改动说明,保存在commit历史中,方便回溯。但你仔细研究过git commit吗?或者换句话说你注意过应该怎样写commit信息和优化commit信息吗?本文将回答这些问题,希望对大家有所帮助。为了对每次提交进行提交说明,方便之后回溯和团队协作,Git 每次提交代码,都要写 Commit mess
本文由风萧萧梦潇投稿,转载请注明出处。如有错误,请不吝指正。
在工作中,我们通常使用git来管理代码,当我们对代码进行某项改动后,都可以通过git commit对代码进行提交。git规定提交时必须要写提交信息,作为改动说明,保存在commit历史中,方便回溯。但你仔细研究过git commit吗?或者换句话说你注意过应该怎样写commit信息和优化commit信息吗?本文将回答这些问题,希望对大家有所帮助。
一、git commit的意义
为了对每次提交进行提交说明,方便之后回溯和团队协作,Git 每次提交代码,都要写 Commit message(提交说明),否则就不允许提交。当参与团队协作时,我们共同维护一个maste或dev的代码,如果其他人改动了仓库代码,我们肯定想知道他到底改动了什么,这次改动会对我们有什么影响。怎么看呢,直接看代码肯定没错,但不是最好的方式。其实最方便的方式就是查看提交历史了。如果提交信息写的足够好的话,不需要看代码我们也清楚改动了什么,这样就可以提高协作效率和沟通成本了。
试想谁不想看到下面这样优雅清晰明了提交历史呢,如果再能自动生成ChangeLog文档自然是极好的。我想没有哪个 程序员 能抵挡得住这种诱惑吧。
总体来说,规范 commit信息的意义如下:
- 可读性即提供本次代码改动的信息,方便其他人浏览和理解
- 可回溯性即方便查找特定提交说明,回溯某些commit(比如新增特性、修复bug等)
- 自动化性即可根据commit信息自动生成ChangeLog(改动说明)
鉴于此,我们需要写出清晰规范的git commit。那么什么的规范的commit信息呢,请继续看下去。
二、git commit 规范
为引导用户为开源社区做贡献,angular较早提出了进行pr时的commit说明规范(详见 Git Commit Guidelines ),后被很多开源项目所接受,形成了一套约定式提交规范。首先让我们从一条提交记录出发看一下angular是如何写提交信息的。
如上所示,angular提交信息遵循如下格式:
<type>(<scope>): <subject> # header信息头必须 <BLANK LINE> <body> # 信息体 <BLANK LINE> <footer> # 结束部分 复制代码
-
header 信息头(必须)
<type>(<scope>): <subject>
信息头必须要有type,它严格限定为如下值:
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内容有以下规定:
- 以动词开头,使用第一人称现在时,比如change,而不是changed或changes
- 首字母小写
- 结尾不加句号(.)
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的优秀辅助工具
看来要写出符合git commit规范的信息也是不容易的,不过社区也为我们提供了一些辅助 工具 来帮助进行提交,下面根据使用目的来简单介绍一下这些工具。
1、生成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", } } 复制代码
2、校验commit信息
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信息符合规范。
3、生成changelog文档
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推荐的整体流程:
- Make changes 改动代码
- Commit those changes 使用git commit提交改动信息
- Make sure Travis turns green 确保提交信息都符合规则
- Bump version in package.json 更改package.json中的版本
- conventionalChangelog 使用该工具生成changelog
- Commit package.json and CHANGELOG.md files 提交package.json和changelog文档
- Tag 给分支打标签
- Push 推送到远程分支
4、高级工具
社区同样提供了一些高级工具来自动化进行上述的某些流程,可以说提供了一条龙服务。具体工具如下:
standard-version : 更新版本、生成changelog、打tag
semantic-release : 更新版本、生成changelog、打tag、推送代码发布
具体使用方法请自行查看文档,这里不再赘述。
四、修改及美化commit信息
前面讲了这么多git commit规范,可能大家要问了,我也准备从现在开始写符合规范的提交信息,那之前项目中的不符合规范的信息怎么办呢?其实之前的提交信息也是有办法修改的,关键就是使用 git rebase
命令。此外还有一个问题就是我写了很多条提交信息,但其实都是干的同一件事(这很常见,比如说要修复某个bug,改好之后发现这个bug在其他设备上并没有改好,于是又改好之后提交了一次,但都是改的同一个问题),有办法将他们合并成一条吗?其实有的,关键也在于 git rebase
。是不是瞬间感觉这个命令很强大,想要迫不及待的试一下呢。
好吧,不卖关子了,直接来到正题,如何使用 git rebase
进行变基操作。先说一下如果直接使用 git rebase [target-branch]
,虽然可以帮我们在本分支基于目标分支进行变基操作,但它只会让两个分支的所有提交连成一条线,不能修改具体提交信息,所以需要使用 git rebase -i
进行交互式操作。首先了解一下 git rebase -i
的几个操作。
如上图所示,git rebase提供了几个操作来对提交信息进行处理,这里挑几个常用的介绍一下。
- pick 缩写为p,保留本次提交包括文件改动和提交信息
- reword 缩写为r,保留本次改动,但重写提交信息
- edit 缩写为e,保留本次改动,而且可以附加改动、编辑提交信息
- squash 缩写为s,保留改动,但本次提交会附加到上次提交中,也就是和上次提交合并(提交信息也会合并)
- fixup 缩写为f,同squash,不同的是会丢弃掉本次提交的说明信息
- drop 缩写为d,丢掉本次提交(包括文件改动和提交信息)
另外还要知道 git rebase --continue
命令用来告诉git继续进行合并,一般在解决冲突后使用(一般来讲如果所有的提交没有冲突的话,可以一直走下去,直到出现成功的提示。但如果两次提交合并涉及到冲突,就需要解决冲突并在git add后使用该命令继续走下去); git rebase --abort
命令用来终止变基操作,一般在不想进行rebase时使用(大部分时间是因为玩脱了,rebase到了一种不可预知的地步,不知道干啥了,就只能终止了)。直到出现类似“Successfully rebased and updated refs/heads/dev.”的消息就说明本次变基成功了。下面具体讲一下如何修改和美化提交信息。
1、修改commit信息
修改提交信息可以分为以下几个步骤,当然具体步骤还要具体情况具体分析,有些可以忽略。
-
暂存工作状态:使用
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
恢复之前的工作状态,结束。
2、commit信息的美化
我们大多数时候只会使用 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 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很是博大精深呢,要想达到精通,我还有很长一段路要走!
以上所述就是小编给大家介绍的《给你的git commit加点料》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Twenty Lectures on Algorithmic Game Theory
Tim Roughgarden / Cambridge University Press / 2016-8-31 / USD 34.99
Computer science and economics have engaged in a lively interaction over the past fifteen years, resulting in the new field of algorithmic game theory. Many problems that are central to modern compute......一起来看看 《Twenty Lectures on Algorithmic Game Theory》 这本书的介绍吧!