git commit 工具链

111 阅读11分钟

git commit 工具链

前言

如果你待过 大厂 或者看过一些 社区规范,会发现前端在 commit 时有对应的规范。

规范 一方面方便管理项目,一方面能让评审人员或者自己在看对应 commit 时,能快速定位到做的事情。

像一些社区的cli内置了 Eslint ,例如Vue cli、Vite、create react app等,可以根据你的需求选配。但是这里,我们自己来搭配 Eslint 。

代码规范

Eslint

用过的同学对它都不陌生,Eslint可以在你开发期间检测的你代码的是否按照规范写,如果不是,就会有报错提醒。

安装

npm i eslint -D

生成配置文件

npx eslint --init

eslint 检测风格

image-20220512102928193.png

  • To check syntax only - 只检查语法
  • To check syntax and find problems - 检查语法和查找错误
  • To check syntax, find problems, and enforce code style - 检查语法,查找错误并加强代码风格

项目使用的模块规范

image.png

项目使用的框架

image.png

是否使用 TypeScript

image-20220512105506880.png

代码运行环境

image-20220512105549979.png 配置文件类型

image-20220512105625957.png 是否用 npm 安装规范

image-20220512105707222.png

选择你的 npm 镜像容器

image-20220512105801463.png

选配完成后,会在根目录会自动生成 .eslintrc.js

module.exports = {
  env: {
    browser: true,
    node: true,
    es2021: true
  },
  extends: [
    "eslint:recommended",
    "plugin:react/recommended",
    "plugin:react/jsx-runtime",
    "plugin:@typescript-eslint/recommended"
  ],
  parser: "@typescript-eslint/parser",
  parserOptions: {
    ecmaFeatures: {
      jsx: true
    },
    ecmaVersion: "latest",
    sourceType: "module"
  },
  plugins: ["react", "@typescript-eslint"],
  // 配置规则
  rules: {}
};

Vscode eslint自动格式化

保存代码的时候,自动运行 eslint 格式化

旧版本

{
    //配置eslint
    "eslint.autoFixOnSave": true,  //  启用保存时自动修复,默认只支持.js文件
    "eslint.validate": [
       "javascript",  //  用eslint的规则检测js文件
       {
         "language": "vue",   // 检测vue文件
         "autoFix": true   //  为vue文件开启保存自动修复的功能
       },
       {
         "language": "html",
         "autoFix": true
       }
     ]
}

新版(>1.41.0)配置

{
    //autoFixedOnSave 设置已废弃,采用如下新的设置
    "editor.codeActionsOnSave": {
      "source.fixAll.eslint": true
    },
    "eslint.format.enable": true,
    //autoFix默认开启,只需输入字符串数组即可
    "eslint.validate": ["javascript", "vue", "html"]
}

prettier

使用 prettier 插件, 通过配置 prettier 的配置文件,统一项目的格式化风格

安装

没有 eslint

npm i prettier -D

有 eslint

npm i prettier eslint-config-prettier eslint-plugin-prettier -D

测试是否安装成功

prettier -v

文件格式

自定义文件的格式可以有多种

  • prettierrc 文件,支持yaml和json格式;或者加上扩展名也可以,可选的扩展名有 .yaml/.yml/.json
  • prettierrc.toml 文件
  • prettier.config.js or .prettierrc.js 返回一个对象
  • package.json文件中加上prettier对象

json 配置文件写法

{
    "semi": false,
    "singleQuote": true
}

toml 文件写法

#  .prettierrc.toml
semi = false
singleQuote = true

yaml 文件写法

# .prettierrc
semi: false
singleQuote: true

js 写法

// prettier.config.js or .prettierrc.js 返回对象
module.exports = {
  semi: false,
  singleQuote: true
};

配置文件

在根目录创建 .prettierrc, 配置格式化

// .prettierrc
{
  "semi": false,
  "tabWidth": 2,
  "trailingComma": "none",
  "singleQuote": true,
  "arrowParens": "avoid"
}

prettier 配置大全

// 常用配置相关解释
printWidth: 100, // 超过最大值换行
tabWidth: 4, // 缩进字节数
useTabs: false, // 缩进不使用tab,使用空格
semi: true, // 句尾添加分号
singleQuote: true, // 使用单引号代替双引号
proseWrap: "preserve", // 默认值。因为使用了一些折行敏感型的渲染器(如GitHub comment)而按照markdown文本样式进行折行
arrowParens: "avoid", //  (x) => {} 箭头函数参数只有一个时是否要有小括号。avoid:省略括号
bracketSpacing: true, // 在对象,数组括号与文字之间加空格 "{ foo: bar }"
disableLanguages: ["vue"], // 不格式化vue文件,vue文件的格式化单独设置
endOfLine: "auto", // 结尾是 \n \r \n\r auto
eslintIntegration: false, //不让prettier使用eslint的代码格式进行校验
htmlWhitespaceSensitivity: "ignore",
ignorePath: ".prettierignore", // 不使用prettier格式化的文件填写在项目的.prettierignore文件中
jsxBracketSameLine: false, // 在jsx中把'>' 是否单独放一行
jsxSingleQuote: false, // 在jsx中使用单引号代替双引号
parser: "babylon", // 格式化的解析器,默认是babylon
requireConfig: false, // Require a 'prettierconfig' to format prettier
stylelintIntegration: false, //不让prettier使用stylelint的代码格式进行校验
trailingComma: "es5", // 在对象或数组最后一个元素后面是否加逗号(在ES5中加尾逗号)
tslintIntegration: false // 不让prettier使用tslint的代码格式进行校验

有时候,某些文件/文件夹的文件并不需要格式化,我们可以通过配置 .prettierignore 来忽略不需要格式化的文件,常见配置如下:

// .prettierignore

/dist/*
.local
.output.js
/node_modules/**
**/*.svg
**/*.sh
/public/*

运行prettier

命令

npx prettier --write <文件路劲+文件名>

//例如,格式化当前路劲下的aaa.js文件
npx prettier --write  ./aaa.js

格式化全部

npx prettier --write  .

格式化某个文件

npx prettier --write  ./文件夹路径/文件名

格式化某个文件夹

npx prettier --write  ./文件夹路径

VsCode 插件

image-20220512111051393.png

git 规范

社区规范

社区认可的 commit 规范

feat: 新增 feature

fix: 修复 bug

docs: 仅仅修改了文档,比如 README, CHANGELOG, CONTRIBUTE等等

style: 仅仅修改了空格、格式缩进、逗号等等,不改变代码逻辑

refactor: 代码重构,没有加新功能或者修复 bug

perf: 优化相关,比如提升性能、体验

test: 测试用例,包括单元测试、集成测试等

chore: 改变构建流程、或者增加依赖库、工具等

revert: 回滚到上一个版本

build: 更新包的内容

release: release版本更新

书写格式如下:

type(scope): <subject>

例子:

revert: feat(form): add 'validate' option
最简写法:feat: add 'validate' option

但是每次手动 commit 都要写上对应的 type ,挺麻烦的?我们也可以用对应的插件来帮我们做类似的事,往下看。

git hooks

git Hooks它是一些自定义的脚本,用于控制git工作的流程,分为客户端钩子和服务端钩子,这里我们主要介绍客户端钩子

客户端钩子分为很多种。 下面把它们分为:提交工作流钩子、电子邮件工作流钩子和其它钩子。主要介绍提交工作流钩子:pre-commit、prepare-commit-msg、commit-msg、post-commit。

  • pre-commit(常用)

在键入提交信息前运行。 它用于检查即将提交的快照。例如,检查是否有所遗漏,确保测试运行,以及核查代码。 如果该钩子以非零值退出,Git 将放弃此次提交,不过你可以用 git commit --no-verify 来绕过这个环节。 你可以利用该钩子,来检查代码风格是否一致(运行类似 lint 的程序)、尾随空白字符是否存在(自带的钩子就是这么做的),或新方法的文档是否适当。

  • prepare-commit-msg

在启动提交信息编辑器之前,默认信息被创建之后运行。 它允许你编辑提交者所看到的默认信息。 该钩子接收一些选项:存有当前提交信息的文件的路径、提交类型和修补提交的提交的 SHA-1 校验。 它对一般的提交来说并没有什么用;然而对那些会自动产生默认信息的提交,如提交信息模板、合并提交、压缩提交和修订提交等非常实用。 你可以结合提交模板来使用它,动态地插入信息。

  • commit-msg(常用)

接收一个参数,此参数即上文提到的,存有当前提交信息的临时文件的路径。 如果该钩子脚本以非零值退出,Git 将放弃提交,因此,可以用来在提交通过前验证项目状态或提交信息

  • post-commit

在整个提交过程完成后运行。 它不接收任何参数,但你可以很容易地通过运行 git log -1 HEAD 来获得最后一次的提交信息。 该钩子一般用于通知之类的事情

git hooks安装

当你用git init初始化一个新版本库时,Git 默认会在这个目录中放置一些示例脚本,进入.git/hooks后会看到一些hooks的官方示例,他们都是以.sample结尾的文件名。

git hooks存储位置

git hooks被存储在Git目录下的.hooks子目录中,即绝大部分项目中的.git/hooks

调用git hooks

注意这些以.sample结尾的示例脚本默认是不会执行的,只有把一个正确命名(不带扩展名.sample)且可执行的文件放入 .git/hooks 目录中,才会激活该钩子脚本,生效且被git调用。像我们平常用的 git push、git commit 等命名都是用到了 hooks

本地.git/hooks的缺陷

【不能共享】由于.git文件夹是不会被git跟踪的,所以.git/hooks目录下的hooks钩子无法提交,就不能和他人共享钩子脚本。

git 工具链

前面我们已经了解 社区规范 和 git hooks ,那我们可以利用一些 git 工具 来帮我们统一 git commit 规范。

  • husky

    • 操作 git 钩子的工具
  • lint-staged

    • 本地暂存代码检查工具
  • commitlint

    • commit 信息校验工具
  • commitizen

    • 辅助 commit 信息 ,就像这样,通过选择输入,规范提交信息

husky

安装 husky

npm install husky --save-dev

在 package.json 中添加脚本,自动启用Git钩子

npm set-script prepare "husky install" // 会在 package.json 中的 scripts 里新增一个 prepare 命令

启用 husky

npm run prepare
// 或
npx husky install

执行完上述命令,会发生几个变化:

  1. .git同级目录生成.husky文件夹
  2. package.json中的scripts中添加了"prepare": "husky install"
  3. 更改git配置项core.hooksPath.husky

配置完 husky 后,我们可以去配置 对应的一些 hook

配置 husky 的方式,默认使用的配置是 .husky文件夹里对应的 hooks

    1. 更改hooks脚本
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"

// 脚本执行了 lint-staged 插件检测
npm run lint-staged
    1. 修改package.json
   "husky": {
        "hooks": {
            "pre-commit": "lint-staged"
        }
    },
    "lint-staged": {
      "*.{js,vue}": [
        "eslint --fix",
        "git add ."
      ]
    },

pre-commit

配置前置钩子,这里我们用 lint-staged 来做前置校验

添加 pre-commit 钩子

npx husky add .husky/pre-commit "npx lint-staged"

输完命令后,会在 .husky 下新增一个 pre-commit 文件,里面执行了 npx lint-staged 命令

配置 lint-staged,有两种配置方法

  • .lintstagedrc.json

    在根目录下新建 .lintstagedrc.json,运行 npx lint-staged 会读取这个文件里边的配置,配置如下

    // 这里是全局匹配了,可以指定对应文件夹,例如 src/**/*.{ts,vue}
    {
      "*.{js,jsx,ts,tsx}": ["prettier --write .", "eslint  --fix"],
      "*.md": ["prettier --write"],
    }
    

    这个配置做了什么? 匹配 git add 暂存区里对应后缀名的文件,然后执行 prettier格式化,eslint检测

  • package.json


{
  "husky": {
    "hooks": {
      "pre-commit": "lint-staged"
    }
  },
  "lint-staged": {
     "*.{js,jsx,ts,tsx}": ["prettier --write .", "eslint  --fix"],
  	 "*.md": ["prettier --write"]
  }
}

commit-msg

添加 commit-msg,这里用的是 commitlint,添加钩子使用 husky add 命令

// 添加 commitlint hook
npx husky add .husky/commit-msg 'npx --no-install commitlint --edit "$1"'

配置 commitlint 提交规范,新增 commitlint.config.js

// commitlint.config.js
module.exports = { extends: ["@commitlint/config-conventional"] };

做的事情,跟上边差不多。 commitlint 会校测你提交的 commit message 是否符合规范,默认是Angular的提交规范

类型描述
build编译相关的修改,例如发布版本、对项目构建或者依赖的改动
chore其他修改, 比如改变构建流程、或者增加依赖库、工具等
ci持续集成修改
docs文档修改
feat新特性、新功能
fix修改bug
perf优化相关,比如提升性能、体验
refactor代码重构
revert回滚到上一个版本
style代码格式修改, 注意不是 css 修改
test测试用例修改

也可以自己写校验方法,来检验校验内容,例如我写的校验在 verifyCommit.js,那添加的时候设置一下就行,代码如下

npx husky add .husky/commit-msg 'node [dir]/verifyCommit.js' # 指定目录文件

或者改 package.json 的配置

{
  "husky": {
    "hooks": {
      "commit-msg": "node [dir]/verifyCommit.js"
    }
  }
}

commitlint-config-cz

通过 commitlint-config-cz 可以定义commitlint 的提交规范

安装

npm i -D commitlint-config-cz  cz-customizable

修改 commitlint.config.js 提交规范,改为 cz

// 采用 cz 自定义的提交规范, > .cz-config.js
module.exports = { extends: ["cz"] };

增加 .cz-config.js

"use strict";
module.exports = {
  types: [
    { value: "✨feat", name: "新增:    新的内容" },
    { value: "🐛fix", name: "修复:    修复一个Bug" },
    { value: "📝docs", name: "文档:    变更的只有文档" },
    { value: "💄style", name: "格式:    空格, 分号等格式修复" },
    { value: "♻️refactor", name: "重构:    代码重构,注意和特性、修复区分开" },
    { value: "⚡️perf", name: "性能:    提升性能" },
    { value: "✅test", name: "测试:    添加一个测试" },
    { value: "🔧chore", name: "工具:    开发工具变动(构建、脚手架工具等)" },
    { value: "⏪revert", name: "回滚:    代码回退" },
    { value: "🏆build", name: "打包:    更新包内容" },
    { value: "🌀release", name: "更新:    版本更新" }
  ],
  scopes: [
    { name: "leetcode" },
    { name: "javascript" },
    { name: "typescript" },
    { name: "Vue" },
    { name: "node" }
  ],
  // it needs to match the value for field type. Eg.: 'fix'
  /*  scopeOverrides: {
    fix: [
      {name: 'merge'},
      {name: 'style'},
      {name: 'e2eTest'},
      {name: 'unitTest'}
    ]
  },  */
  // override the messages, defaults are as follows
  messages: {
    type: "选择一种你的提交类型:",
    scope: "选择一个scope (可选):",
    // used if allowCustomScopes is true
    customScope: "Denote the SCOPE of this change:",
    subject: "短说明:\n",
    body: '长说明,使用"|"换行(可选):\n',
    breaking: "非兼容性说明 (可选):\n",
    footer: "关联关闭的issue,例如:#31, #34(可选):\n",
    confirmCommit: "确定提交说明?(yes/no)"
  },
  allowCustomScopes: true,
  allowBreakingChanges: ["特性", "修复"],
  // limit subject length
  subjectLimit: 100
};

在 package.json 中, 新增 config 配置,修改 commitizen 使用的容器

  "config": {
    "commitizen": {
      "path": "node_modules/cz-customizable"
    }
  },

新增命令 commit 命令

// package.json  
"scripts": {
   "commit": "git-cz"
 },

执行命令, npm run commit