社区所有版块导航
Python
python开源   Django   Python   DjangoApp   pycharm  
DATA
docker   Elasticsearch  
aigc
aigc   chatgpt  
WEB开发
linux   MongoDB   Redis   DATABASE   NGINX   其他Web框架   web工具   zookeeper   tornado   NoSql   Bootstrap   js   peewee   Git   bottle   IE   MQ   Jquery  
机器学习
机器学习算法  
Python88.com
反馈   公告   社区推广  
产品
短视频  
印度
印度  
Py学习  »  Git

用工具思路来规范化 git commit message

pigcan • 8 年前 • 551 次点击  

在团队协作中我们经常碰到的问题是每个人都有自己的开发习惯,这个习惯包含但不限于编码风格,工具使用等,所以往往协作中就会出现各种各样的问题。这篇文章将会从很小的切入点开始讲,即如标题所诉 Git Commit Message

但在讲之前大家最好对如下的分支管理有一定的了解,原因在于,好的分支管理模型和好的 Git Commit Message 是规范化开发必不可少的内容。

衍生阅读 Git 分支管理模型gitflow

为什么要规范 Git Commit Message

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

  • 说不出所以然的一连串的 commit 提交日志
  • commit 信息写的很简单,根本没有办法从 commit 信息中获知该 commit 用意的
  • commit 信息写的很随意,commit 信息和变更代码之间不能建立联系的
  • commit 信息写的过于冗余的

相信或多或少大家都曾碰到过。一旦涉及代码回滚,issue 回溯,changelog,语义化版本发布等操作时,作为 PM 肯定一脸懵逼 即使 PM 参与了全程的 CR 环节。

那理想中的 Git Commit Message 应该是要能较好的解决如上问题

  • 发生问题时快速让 PM 识别问题代码并回滚
  • commit 和 代码之间能建立起联系,并和相关的 issue 予以关联,做到任何代码都能区域性的解决问题(当然这也需要好的分支模型来支撑)

而 changelog,语义化版本发布这更像是合理化 commit 后水到渠成之事。

如何算比较好的 Git Commit Message

以个人来看,好的 commit 需要有以下特征

  • 有节制性的
  • 简明扼要的
  • 和代码,issue 强关联,利于 CR 的

如何写出规范化的 Git Commit Message

当前业界应用的比较广泛的是 Angular Git Commit Guidelines

具体格式为:

<type>(<scope>): <subject>
<BLANK LINE>
<body>
<BLANK LINE>
<footer>

type: 本次 commit 的类型,诸如 bugfix docs style 等
scope: 本次 commit 波及的范围
subject: 简明扼要的阐述下本次 commit 的主旨,在原文中特意强调了几点 1. 使用祈使句,是不是很熟悉又陌生的一个词,来传送门在此 祈使句 2. 首字母不要大写 3. 结尾无需添加标点
body: 同样使用祈使句,在主体内容中我们需要把本次 commit 详细的描述一下,比如此次变更的动机,如需换行,则使用 |
footer: 描述下与之关联的 issue 或 break change,详见案例

一方面我们可以通过 commit 模板,但是这对于整体管控而言比较难以把握。所以如标题所诉,我采取了工具化的方式。

问题将会被拆分成

如何利用工具协助 生成 commit

commitizen 来格式化 git commit message 的工具,它提供了一种问询式的方式去获取所需信息,而在一个大框架下,我们肯定有自己想要遵循的范式(即个性化内容,比如 types 的类型),此时就由 commitizen 中的 adapter 来承载,例如如上提到的 angular 规范则是由 cz-conventional-changelog 来实现。

如何利用工具协助 校验 commit

commitlint 来校验 git commit message 的工具,而所需要校验的内容是否符合规范则和 commitizen 一样需要一个 adapter,例如校验 angular 规范的则由 @commitlint/config-conventional 来呈现。

何时校验才算合理

这就需要 husky 了。附所有可用的 hooks

在老版本中在 package.json

"scripts": {
  "commitmsg": "commitlint -e $GIT_PARAMS"
}

在新版本中

  "husky": {
    "hooks": {
      "commit-msg": "commitlint -e $GIT_PARAMS"
    }
  }

水到渠成的 changelog

依托于 commitizen 对 Git Commit Message 的规范化,我们非常容易依托 commit 信息来自动化生成 changelog。

正常情况下,我们可以使用 standard-versionsemantic-release 来生成 changelog。

standard-version 与 semantic-release 的区别,总结来说就是 standard-version 只针对 local git repo 而 semantic-release 则会牵扯到代码 push 亦或 npm publish。

另外如果你的项目是 mono repo 的,即通过 lerna 来管理的,然后代码又托管在 github 上,那么 lerna 也给了一套自己的解决方案,一种基于 github tag 给 pr 和 issue 打标的方式。这一块可以见我之前的文章 monorepo 新浪潮 | introduce lerna

项目实战

在实际我们的业务项目中当前有两种场景,一种是普通的 repo,还有一种是 mono repo,如果还不知道 mono repo 是什么的,可以参考下我之前写的这篇文章 monorepo 新浪潮 | introduce lerna,这篇文章也在文章上面有所提到。

普通 repo

为了让读者可以快速上手,我已经把相关内容整理到一个示例 repo - normal repo,对它的解释是 Starter kit with zero-config for building a library in ES6, featuring Prettier, Semantic Release, and more! 这是一个还在进行中的 repo,当前还确少 babel 那个部分,如果是 ts 用户的话 还需要 ts 那个部分,这些都是需要后续补上的部分。

接下来说下关键部分,先上 package.json

 "scripts": {
  "ct": "git-cz",
  "precommit": "lint-staged",
  "commitmsg": "commitlint -e $GIT_PARAMS",
  "release": "standard-version"
},
"config": {
  "commitizen": {
    "path": "./node_modules/cz-conventional-changelog"
  }
},
"standard-version": {
  "skip": {
    "commit": true,
    "tag": true
  }
},
"lint-staged": {
  "*.js": [
    "prettier --trailing-comma es5 --single-quote --write",
    "git add"
  ]
},

在常规开发中,我们的操作方式会变更为如下:

第一步:使用 commitizen 替代 git commit

使用

$ npm run ct

来替代原有的 git commit

如果你是 sourceTree 用户,其实也不用担心,你完全可以可视化操作完后,再在命令行里面执行 ct 命令,这一部分确实破坏了整体的体验,当前并没有找到更好的方式来解决。

第二步:格式化代码

这一步,并不需要人为干预,因为 precommit 中的 lint-staged 会自动化格式,以保证代码风格尽量一致

第三步:commit message 校验

这一步,同样也不需要人为介入,因为 commitmsg 中的 commitlint 会自动校验 msg 的规范

第四步:当有发布需求时

使用

$ npm run release

在这一步中,我们依托 standard-version 的能力,输出 changelog,细心的同学可以看到在配置 standard-version 时,我们忽略了相关的打标操作。 原因在于,我们会介入修改 changelog,因为依托 commit msg 的 changelog 对用户而言或许并不直观。 如果没有这种特殊需求的,可以选择打标。

"standard-version": {
  "skip": {
    "commit": true,
    "tag": true
  }
},

第五步:发布

$ npm publish

mono repo

同上,这是一个使用 mono repo 的快速上手示例。 对它的解释是 Starter kit with lerna and zero-config for building a library in ES6, featuring Prettier, Semantic Release, and more!

mono repo 最大的差异是,需要用不同的 commiizen adapter 来适配 mono repo 这种特殊的项目结构,所以在这边我们也选用了 cz-lerna-changelog,最大原因在于我们想要根据 commit 生成 changelog 时 commit 能落实到对应的 package,以及有一份归总的 changelog,这份 changelog 能说明所有的子 packages 的 changelog。

同样说下关键部分,先上 package.json

"scripts": {
  "ct": "git-cz",
  "precommit": "lint-staged",
  "commitmsg": "commitlint -e $GIT_PARAMS",
  "release": "lerna publish --conventional-commits --skip-git --skip-npm",
  "publish": "./tasks/publish.js"
},
"config": {
  "commitizen": {
    "path": "./node_modules/cz-lerna-changelog"
  }
},
"lint-staged": {
  "*.js": [
    "prettier --trailing-comma es5 --single-quote --write",
    "git add"
  ]
},

这边我只说下差异部分

第四步:当有发布需求时

使用

$ npm run release

在这一步中我们借助了 lerna 自身的能力来根据 commit msg 来生成了 changelog,同样我们忽略了打标,以及发布流程,原因依旧是我们需要修改自动化生成的 changelog。但这个操作带来的问题是后续需要手动进行 publish 的操作。在实际业务项目里面,我们的选择是在项目根目录中新建一个 tasks 目录,该目录内放一些自动化脚本,比如这里有 publish.js

所以这边变成利用 release 来生成 changelog,继而我们修改,然后再到根目录中执行 npm run publish 来执行 tasks/publish.js。这部分当前我还没有同步到示例中,后续会添加。

第五步:发布

$ npm run publish

缘由如上诉。

总结

前几天听 UCAN 分享,温伯华提到一点特别印象深刻,大意就是成长必定是上坡路,必定是艰辛的,其实没有如上工具照样可以开发,然而它的存在是让人养成良好的协作习惯,而好的习惯是可以让人受益终身的,所以希望作为读者的你,能踏上这个上坡路。

Ref: github.com/angular/ang…


今天看啥 - 高品质阅读平台
本文地址:http://www.jintiankansha.me/t/piU1nGMrLr
Python社区是高质量的Python/Django开发社区
本文地址:http://www.python88.com/topic/10999