给你的git commit加点料

本文由风萧萧梦潇投稿,转载请注明出处。若有错误,请不吝指正。html

在工做中,咱们一般使用git来管理代码,当咱们对代码进行某项改动后,均可以经过git commit对代码进行提交。git规定提交时必需要写提交信息,做为改动说明,保存在commit历史中,方便回溯。但你仔细研究过git commit吗?或者换句话说你注意过应该怎样写commit信息和优化commit信息吗?本文将回答这些问题,但愿对你们有所帮助。node

1、git commit的意义

为了对每次提交进行提交说明,方便以后回溯和团队协做,Git 每次提交代码,都要写 Commit message(提交说明),不然就不容许提交。当参与团队协做时,咱们共同维护一个maste或dev的代码,若是其余人改动了仓库代码,咱们确定想知道他到底改动了什么,此次改动会对咱们有什么影响。怎么看呢,直接看代码确定没错,但不是最好的方式。其实最方便的方式就是查看提交历史了。若是提交信息写的足够好的话,不须要看代码咱们也清楚改动了什么,这样就能够提升协做效率和沟通成本了。git

试想谁不想看到下面这样优雅清晰明了提交历史呢,若是再能自动生成ChangeLog文档天然是极好的。我想没有哪一个程序员能抵挡得住这种诱惑吧。程序员

在这里插入图片描述
在这里插入图片描述

整体来讲,规范 commit信息的意义以下:github

  • 可读性即提供本次代码改动的信息,方便其余人浏览和理解
  • 可回溯性即方便查找特定提交说明,回溯某些commit(好比新增特性、修复bug等)
  • 自动化性便可根据commit信息自动生成ChangeLog(改动说明)

鉴于此,咱们须要写出清晰规范的git commit。那么什么的规范的commit信息呢,请继续看下去。shell

2、git commit 规范

为引导用户为开源社区作贡献,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内容有如下规定:

    1. 以动词开头,使用第一人称如今时,好比change,而不是changed或changes
    2. 首字母小写
    3. 结尾不加句号(.)

    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文档

3、git commit的优秀辅助工具

看来要写出符合git commit规范的信息也是不容易的,不过社区也为咱们提供了一些辅助工具来帮助进行提交,下面根据使用目的来简单介绍一下这些工具。

一、生成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",
  }
}
复制代码

二、校验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信息符合规范。

三、生成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 推送到远程分支

四、高级工具

社区一样提供了一些高级工具来自动化进行上述的某些流程,能够说提供了一条龙服务。具体工具以下:

standard-version: 更新版本、生成changelog、打tag

semantic-release: 更新版本、生成changelog、打tag、推送代码发布

具体使用方法请自行查看文档,这里再也不赘述。

4、修改及美化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.”的消息就说明本次变基成功了。下面具体讲一下如何修改和美化提交信息。

一、修改commit信息

修改提交信息能够分为如下几个步骤,固然具体步骤还要具体状况具体分析,有些能够忽略。

  1. 暂存工做状态:使用git stash将当前工做状态进行暂存,若是没有须要暂存的工做状态请忽略

  2. 转到须要修改的提交上:使用git rebase -i [commit-id]^将 HEAD 移动到须要修改的 commit-id 上,由于该[commit-id]也在修改之列,因此要基于它的上一个提交变基,或者直接使用[commit-id]^

  3. 将pick修改成想要进行的操做命令:进行编辑时通常要把全部须要修改的commit的pick改成r或e,提示:若是多的话可使用vim的全局替换

  4. 从新编辑commit信息

  5. 附加修改:若是须要在该分支上修改其余内容,能够在改动文件后直接使用git add 将其添加到暂存区,并使用 git commit –amend 追加改动到提交。若是不须要请忽略

  6. 继续进行变基操做:使用git rebase –continue继续,通常若是提交没有冲突或者附加修改的话,不须要手动输入,git会自动进行下一次操做。

  7. 变基完成:重复以上步骤,直到出现变基成功文字。若是暂存过工做状态,须要使用git stash pop恢复以前的工做状态,结束。

二、commit信息的美化

咱们大多数时候只会使用git merge来将开发代码合并到主分支。不过这样会致使主分支包含咱们合并分支的全部提交信息。久而久之,会让commit history愈来愈繁杂,但其实合并的代码彻底能够用一条提交信息好比feat: 添加某项新特性来代替。固然还有其余缘由会致使commit信息重复且没必要要。好比当咱们在拿不许bug到底有没有修复成果时可能会屡次改动代码进行测试,若是每次改动测试都进行了提交,就会产生屡次commit信息,若是不对这些commit作合并的话,在咱们将代码合并到开发主分支时就会产生不少繁杂的commit信息,不过因为这些commit信息都是为解决一样的事情服务的,彻底能够合到一块儿。因此若是你嫌弃commit信息太啰嗦冗余,那么就须要对其进行美化了。美化主要有两种方式:git rebasegit merge --squash,这里将介绍它们的使用,并进行对比。

  1. rebase merge

    注意:若是要合并的commit历史过多而且对git rebase命令使用不熟练,请慎用,否则可能会被各类冲突逼疯的!

    若是咱们想将dev的提交信息进行美化并合并到master分支,能够进行以下操做:

    • 先切换到 dev 分支:git checkout dev
    • 基于master进行变基操做:git rebase -i master,其中具体的操做请参见上一小节,不一样的不过是把一些提交的pick改成s而已,即提交信息合并到上一次提交。
    • 切换回目标分支:git checkout master
    • 合并: git merge dev
  2. squash merge

    一样以dev分支合并到master为例:

    • 切换到目标分支:git checkout master
    • 以 squash 的形式 merge: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非常博大精深呢,要想达到精通,我还有很长一段路要走!

参考资料:

  1. 你可能会忽略的 Git 提交规范
  2. Commit message 和 Change log 编写指南
  3. Git Commit Message Conventions
  4. 【Git】rebase 用法小结
  5. merge squash 和 merge rebase 区别
  6. git笔记-进阶
相关文章
相关标签/搜索