缘起

公司的 git 提交比较乱,很多对应的 issue 没有链起来,不知道哪个是哪个,在这里尝试整理 git commit 的提交规范和应对措施。
规范是人定的,有一个人不遵守,到最后所有人都随便,破窗效应怎么办?自动化来做这件事。

什么是好的规范?

看看 angular 和 Vue 的 github 仓库提交。
image.png
image.png
Angular 还总结出一套规范,得到了社区的广泛认同:

  1. <type>(<scope>): <subject>
  2. <BLANK LINE>
  3. <body>
  4. <BLANK LINE>
  5. <footer>

type 的值很多,比如 feat, build, docs, fix 等。

描述
feat 新增一个功能
fix 修复一个 Bug
docs 文档变更
style 代码格式(不影响功能,例如空格、分号等格式修正)
refactor 代码重构
perf 改善性能
test 测试
build 变更项目构建或外部依赖(例如 scopes: webpack、gulp、npm 等)
ci 更改持续集成软件的配置文件和 package 中的 scripts 命令,例如 scopes: Travis, Circle 等
chore 变更构建流程或辅助工具
revert 代码回退

你现在再回头看看 ng 和 Vue 的提交记录应该就有感觉了。

项目里怎么用?

先了解规范,再使用规范,最终使用工具来辅助完成。
需要用到这几个npm插件:

  • commitizen commit 格式化
  • cz-conventional-changelog 社区流行的规范
  • cz-customizable 自定义规范
  • @commitlint/cli 校验规范
  • husky git 钩子
  • conventional-changelog 根据提交自动生成版本日志

版本日志都是自动生成的,是不是恍然大悟。
使用这些插件,可以一步一步来。

渐进使用

先自己用,先约束自己,同时不污染已有项目。

  1. # 全局安装
  2. npm i -g commitizen cz-conventional-changelog
  3. # 用户目录写入配置
  4. echo '{ "path": "cz-conventional-changelog" }' > ~/.czrc
  5. # git add file 然后执行提交
  6. git-cz

有的喜欢在 feat 前面加个 emoji表情,或者想汉化怎么办,这就是自定义部分了

  1. # 接上面
  2. npm i -g cz-customizable
  3. # 修改 ~/.czrc
  4. { "path": "cz-customizable" }
  5. # 创建配置文件,后来发现windows放到用户目录不好使
  6. # touch ~/.cz-config.js
  7. # 放到项目目录就好了
  8. touch ./.cz-config.js
  9. # 修改自定义的配置
  10. # https://github.com/leonardoanalista/cz-customizable/blob/master/cz-config-EXAMPLE.js

代码还是贴一下吧。
emoji 在这里找 https://gitmoji.carloscuesta.me/
file: .cz-config.js:

  1. module.exports = {
  2. types: [
  3. { value: "🎉feat", name: "feat: A new feature" },
  4. { value: "fix", name: "fix: A bug fix" },
  5. { value: "docs", name: "docs: Documentation only changes" },
  6. {
  7. value: "style",
  8. name:
  9. "style: Changes that do not affect the meaning of the code\n (white-space, formatting, missing semi-colons, etc)"
  10. },
  11. {
  12. value: "refactor",
  13. name:
  14. "refactor: A code change that neither fixes a bug nor adds a feature"
  15. },
  16. {
  17. value: "perf",
  18. name: "perf: A code change that improves performance"
  19. },
  20. { value: "test", name: "test: Adding missing tests" },
  21. {
  22. value: "chore",
  23. name:
  24. "chore: Changes to the build process or auxiliary tools\n and libraries such as documentation generation"
  25. },
  26. { value: "revert", name: "revert: Revert to a commit" },
  27. { value: "WIP", name: "WIP: Work in progress" }
  28. ],
  29. scopes: [
  30. { name: "accounts" },
  31. { name: "admin" },
  32. { name: "exampleScope" },
  33. { name: "changeMe" }
  34. ],
  35. allowTicketNumber: false,
  36. isTicketNumberRequired: false,
  37. ticketNumberPrefix: "TICKET-",
  38. ticketNumberRegExp: "\\d{1,5}",
  39. // it needs to match the value for field type. Eg.: 'fix'
  40. /*
  41. scopeOverrides: {
  42. fix: [
  43. {name: 'merge'},
  44. {name: 'style'},
  45. {name: 'e2eTest'},
  46. {name: 'unitTest'}
  47. ]
  48. },
  49. */
  50. // override the messages, defaults are as follows
  51. messages: {
  52. type: "Select the type of change that you're committing:",
  53. scope: "\nDenote the SCOPE of this change (optional):",
  54. // used if allowCustomScopes is true
  55. customScope: "Denote the SCOPE of this change:",
  56. subject: "Write a SHORT, IMPERATIVE tense description of the change:\n",
  57. body:
  58. 'Provide a LONGER description of the change (optional). Use "|" to break new line:\n',
  59. breaking: "List any BREAKING CHANGES (optional):\n",
  60. footer:
  61. "List any ISSUES CLOSED by this change (optional). E.g.: #31, #34:\n",
  62. confirmCommit: "Are you sure you want to proceed with the commit above?"
  63. },
  64. allowCustomScopes: true,
  65. allowBreakingChanges: ["feat", "fix"],
  66. // skip any questions you want
  67. skipQuestions: ["body"],
  68. // limit subject length
  69. subjectLimit: 100
  70. // breaklineChar: '|', // It is supported for fields body and footer.
  71. // footerPrefix : 'ISSUES CLOSED:'
  72. // askForBreakingChangeFirst : true, // default is false
  73. }

这时候再执行 get-cz 就有自定义的内容了。
必要的话,可以把 .cz-config.js 放到 .gitignore 里面,这样就完成了在不污染项目的情况下,对自己进行了约束。
接下来,可以说:

  • 项目集成
  • commit校验
  • 自动生成版本日志

    husky 一本通

    ```bash yarn add husky@next -D
  1. .huskyrc
  2. ```json
  3. {
  4. "husky": {
  5. "hooks": {
  6. "pre-commit": "npm test",
  7. "commit-msg": "commitlint -E HUSKY_GIT_PARAMS",
  8. "pre-push": "npm test",
  9. "...": "..."
  10. }
  11. }
  12. }

1 简单用法

  1. {
  2. "scripts":{
  3. "precommit": "eslint src/**/*.js"
  4. }
  5. }

会检测所有的文件。不是渐进式修改。

2 只检测本次修改的文件

git 路径:add — staged — commit
安装这个插件,在commit之前会检测 staged 的文件

  1. yarn add lint-staged -D
  1. {
  2. "scripts":{"precommit":"lint-staged"},
  3. "lint-staged":{"scr/**/*.js":"eslint"}
  4. }

或者,lint完了再 add

  1. {
  2. "scripts": {
  3. "precommit": "lint-staged"
  4. },
  5. "lint-staged": {
  6. "src/**/*.js": ["eslint --fix", "git add"]
  7. }
  8. }

或者,使用 prettier

  1. {
  2. "scripts": {
  3. "precommit": "lint-staged"
  4. },
  5. "lint-staged": {
  6. "src/**/*.js": ["prettier --write", "git add"]
  7. }
  8. }

3 结合 commitlint

  1. yarn add -D @commitlint/cli

ng风格和自定义风格

  1. # ng
  2. yarn add -D @commitlint/config-conventional
  3. # custome
  4. yarn add -D commitlint-config-cz
  5. # 配置文件
  6. touch commitlint.config.js
  7. # ng校验
  8. module.exports = { extends: ['@commitlint/config-conventional'] };
  9. # custom 校验
  10. module.exports = { extends: [ 'cz' ] };
  11. # git hooks 提交时候校验规则
  12. "husky": { "hooks": { "commit-msg": "commitlint -E HUSKY_GIT_PARAMS" } }

开发日志,先放着

  1. yarn add -D conventional-changelog
  1. {
  2. "version": "conventional-changelog -p angular -i CHANGELOG.md -s -r 0 && git add CHANGELOG.md"
  3. }