Git提交规范

目的

commit message应该清晰明了,说明本次提交的目的

commit message格式

: 
// 空一行
 
 // 空一行
 
  • type(必须项)
    用于说明commit类别,均应使用下面这些标识
标识符 描述
feat 新功能(feature)
fix 修复bug
docs 文档变更、文档注释
style 不影响代码内容的修改(格式修改,比如空格、分号、缩进等)
refactor 重构(即不是新增功能,也不是修改bug的代码变动)
improvement 对当前功能的改进
perf 提高性能的代码修改
test 添加测试或修正现有的测试
chore 构建过程或辅助工具的变动
ci CI配置文件和脚本的改动
revert 回滚先前提交
delete 删除(代码、文档等)
  • subject(必须项)
    是commit目的的简短描述,不超过50个字符

  • body
    是对本次commit的详细描述,可分成多行描述

  • footer
    一般用于关闭issue

Closes #1, #2, #3

规范方式

为实现规范,我们使用commitlint和husky来进行提交检查,思路是:当执行git commit时会在对应的git钩子上做校验,只有符合格式的才能提交成功。
为方便使用,增加了commitizen支持,使用cz-customizable进行配置。

配置package.json

如果已存在package.json,请直接跳到安装步骤

不存在package.json,在根目录(.git同级目录)新建文件package.json,内容如下

{
  "name": "application-name",
  "version": "1.0.0",
  "scripts": {},
  "author": "",
  "devDependencies": {
  }
}

安装

需要node/npm环境,自行安装相关环境

npm i commitlint @commitlint/config-conventional husky commitizen  --save-dev

此过程会自动生成node_modules文件夹,切记要将node_modules/添加到忽略文件.gitignore

以下内容说明安装几个依赖的作用

  • commitlint
    当我们运行 git commmit -m 'xxx' 时,用来检查 xxx 是否满足固定格式的工具
    使用 commitlint 可以规范我们每一次的 commit,我们可以用来自动生成 changeLog 等文件,方便代码管理

  • @commitlint/config-conventional
    commitlint 推荐我们使用 config-conventional 配置去写 commit
    config-conventional是一种规范配置方案,这是一个从 config-angular 衍生出的一个分支

  • husky
    一款git hook工具,可以hook git的命令

  • commitizen
    一个帮助规范commit message的工具
    在命令行窗口可通过使用git cz进入引导式提交,即替代git commit

  • cz-customizable
    可定制的commitizen插件

配置commitlint.config.js

在根目录(.git同级目录)新建文件commitlint.config.js,内容如下

module.exports = {
    extends: ['@commitlint/config-conventional'],
    rules: {
      // type 类型定义
      'type-enum': [2, 'always', [
        "feat", // 新功能(feature)
        "fix", // 修复bug
        "docs", // 文档变更、文档注释
        "style", // 不影响代码内容的修改(格式修改,比如空格、分号、缩进等)
        "refactor", // 重构(即不是新增功能,也不是修改bug的代码变动)
        "improvement", // 对当前功能的改进
        "perf", // 提高性能的代码修改
        "test", // 添加测试或修正现有的测试
        "chore", // 构建过程或辅助工具的变动
        "ci", // CI配置文件和脚本的改动
        "revert", // 回滚先前提交
        "delete", // 删除(代码、文档等)
      ]],
      // subject 大小写不做校验
      // 自动部署的BUILD ROBOT的commit信息大写,以作区别
      'subject-case': [0],
      'subject-max-length': [2, 'always', 50]
    }
  };

配置husky

方案一
在package.json文件中增加相关配置

"husky": {
  "hooks": {
    "commit-msg": "commitlint -E HUSKY_GIT_PARAMS"
  }
}

方案二
在根目录(.git同级目录)新建文件.huskyrc.json,内容如下

{
  "hooks": {
    "commit-msg": "commitlint -E HUSKY_GIT_PARAMS"
  }
}

commit-msg 代表对commit message进行hook,hook的时候执行后面的命令commitlint -E HUSKY_GIT_PARAMS进行检查

配置commitizen

如果没有全局安装commitizen,先运行npm install -g commitizen
项目根目录运行commitizen init cz-customizable --save --save-exact
在package.json文件中增加相关配置

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

配置.cz-config.js

在根目录(.git同级目录)新建文件.cz-config.js,内容如下

'use strict';

module.exports = {
  types: [
    {value: 'feat',        name: 'feat:           新功能(feature)'},
    {value: 'fix',         name: 'fix:            修复bug'},
    {value: 'docs',        name: 'docs:           文档变更、文档注释'},
    {value: 'style',       name: 'style:          不影响代码内容的修改(格式修改,比如空格、分号、缩进等)'},
    {value: 'refactor',    name: 'refactor:       重构(即不是新增功能,也不是修改bug的代码变动)'},
    {value: 'improvement', name: 'improvement:    对当前功能的改进'},
    {value: 'perf',        name: 'perf:           提高性能的代码修改'},
    {value: 'test',        name: 'test:           添加测试或修正现有的测试'},
    {value: 'chore',       name: 'chore:          构建过程或辅助工具的变动'},
    {value: 'ci',          name: 'ci:             CI配置文件和脚本的改动'},
    {value: 'revert',      name: 'revert:         回滚先前提交'},
    {value: 'delete',      name: 'delete:         删除(代码、文档等)'}
  ],
  // override the messages, defaults are as follows
  messages: {
    type: '请选择提交类型:',
    // 不需要跳过即可
    scope: '请输入文件修改范围(可选):',
    // used if allowCustomScopes is true
    customScope: '请输入修改范围(可选):',
    subject: '请简要描述提交(必填):',
    // 不需要跳过即可
    body: '请输入详细描述(可选):',
    // breaking: 'List any BREAKING CHANGES (optional):\n',
    // 不需要跳过即可
    footer: '请输入要关闭的issue:',
    confirmCommit: '确认将以上信息提交?(y/n/e/h)'
  },
  allowCustomScopes: false,
//   allowBreakingChanges: ['feat', 'fix'],
  skipQuestions: ['scope', 'body', 'footer'], //
  // limit subject length, commitlint默认是72
  subjectLimit: 50
};

完整的package.json

如果直接copy此配置,项目根目录仅运行npm i即可

{
  "name": "application-name",
  "version": "1.1.0",
  "scripts": {
    "changelog": "standard-version"
  },
  "author": "",
  "devDependencies": {
    "@commitlint/config-conventional": "^9.1.2",
    "commitizen": "^4.2.1",
    "commitlint": "^9.1.2",
    "cz-customizable": "^6.3.0",
    "husky": "^4.3.0",
    "standard-version": "^9.0.0"
  },
  "husky": {
    "hooks": {
      "commit-msg": "commitlint -E HUSKY_GIT_PARAMS"
    }
  },
  "config": {
    "commitizen": {
      "path": "./node_modules/cz-customizable"
    }
  }
}

配置下载

git-commit-rule

快速运行

cd 规范目录
git init
npm i

效果展示

不符合规范的git commit

image
image

符合规范的git commit

image

引导式提交

image

生成CHANGELOG

  • 安装
npm i standard-version --save-dev
  • 配置package.json
"scripts": {
    "changelog ": "standard-version"
  },
  • 运行
npm run changelog

Mac Sourcetree配置

通过Sourcetree提交commit时,如果Sourcetree并没有校验commit提交内容,打开命令历史,如出现如下内容

git --no-optional-locks -c color.branch=false -c color.diff=false -c color.status=false -c diff.mnemonicprefix=false -c core.quotepath=false -c credential.helper=sourcetree commit -q -F /var/folders/rh/0skht59d3tnflgwtr4m99r9c0000gn/T/SourceTreeTemp.3X5RLA 
Can't find npx in PATH: /Applications/Sourcetree.app/Contents/Resources/git_local/libexec/git-core:/Applications/Sourcetree.app/Contents/Resources/bin:/Applications/Sourcetree.app/Contents/Resources/git_local/bin:/Applications/Sourcetree.app/Contents/Resources/git_local/gitflow:/Applications/Sourcetree.app/Contents/Resources/git_local/git-lfs:/usr/bin:/bin:/usr/sbin:/sbin
Skipping commit-msg hook
Completed successfully

需进行如下配置
新建文件~/.huskyrc,其中~指的是用户主目录,加入如下内容

PATH="/usr/local/bin:$PATH"

出现如下内容,表示Sourcetree配置成功


image

Android TortoiseGit配置

通过TortoiseGit提交commit时,TortoiseGit同样会校验commit-msg的配置;如果需要使用TortoiseGit配置,需要进行如下操作:
桌面右键->TortoiseGit->点击设置->找到Hoot 脚本,点击添加,具体配置如下图。

image

出现如下效果,说明配置成功:

image

更新多个项目配置

目前基于以上这套配置,需要每个项目都单独配置一次,这样就产生一个问题,如果配置文件更改,那么需要所有项目都copy一次,暂时也并未找到合适的统一管理方案,因此就有了gitCommitRuleSet.py这个脚本,此脚本的目的是代替人工的copy文件以及git提交,其中destDirsorgDirsignoreFileName三个变量需要自行根据项目仓库进行设置

环境要求

  • 脚本使用Python3开发,需要Python3环境
  • 需要安装gitpython,gitpython是git版本控制库的python版本
pip install gitpython

运行

python3 gitCommitRuleSet.py

源码

# -*- coding: utf-8 -*-
import os
import shutil
from git import Repo, exc

# 目标路径 项目仓库
destDirs = [
    '/Users/nb-mac/Desktop/j-ios/a',
    '/Users/nb-mac/Desktop/j-ios/b',
    '/Users/nb-mac/Desktop/j-ios/c',
    '/Users/nb-mac/Desktop/j-ios/d',
]

# 原始路径 存放git commit配置的文件夹
orgDirs = [
    '/Users/nb-mac/Desktop/j-ios/gitCommitRule',
]

# 忽略文件
ignoreFileName = [
    '.DS_Store'
]

def copyFile(orgFile, destFile):
    '''
    copy文件
    :param orgFile: 原文件
    :param destFile: 目标文件
    :return:
    '''
    shutil.copyfile(orgFile, destFile)

def copyDir(orgDir, destDir, level1Path, commitAddList):
    '''
    copy目录
    :param orgDir: 原目录
    :param destDir: 目标目录
    :param level1Path: 原始目录第一层
    :param commitAddList: 用于存储文件名
    :return:
    '''
    # 获取原始目录
    list = os.listdir(orgDir)
    for i in list:
        # 如果是忽略文件,则跳过
        if i in ignoreFileName:
            continue
        tmpOrg = os.path.join(orgDir, i)
        tmpDest = os.path.join(destDir, i)
        # 是否是目录
        if os.path.isdir(tmpOrg):
            # 目标目录不存在,则创建目录
            if not os.path.exists(tmpDest):
                os.mkdir(tmpDest)
            copyDir(tmpOrg, tmpDest, level1Path, commitAddList)
            continue
        copyFile(tmpOrg, tmpDest)
        commitAddList.append(tmpOrg.replace(level1Path + "/", ''))

def gitCommit(destDir, commitAddList):
    '''
    git提交
    :param destDir: 目标目录
    :param commitAddList: 用于git add的文件
    :return:
    '''
    try:
        # 在包含.git文件夹的版本库路径创建git.Repo对象
        repo = Repo(destDir)
        # 获取版本库暂存区
        git = repo.git
        git.add(commitAddList)
        print("提交的文件", commitAddList)
        git.commit("-m", "chore: git commit规范工具修改")
        print("git commit succeed")
        # 获取远程仓库
        remote = repo.remote()
        # 推送本地修改到远程仓库
        remote.push()
        print("推送本地数据成功")
    except exc.InvalidGitRepositoryError:
        print("无效的Git仓库")
    except Exception as error:
        print("出现错误:", error)

def start(orgDirs, destDirs):
    '''
    开始执行copy操作
    :param orgDirs: 原目录列表
    :param destDirs: 目标目录列表
    :return:
    '''
    print("start")
    for d in range(len(destDirs) - 1, -1, -1):
        print("-" * 100)
        destDir = destDirs[d]
        print(destDir, "仓库开始操作")
        isDestDirExist = os.path.exists(destDir)
        if not isDestDirExist:
            print(destDir, "目标路径不存在")
            del destDir
            continue

        commitAddList = []
        for o in range(len(orgDirs) - 1, -1, -1):
            orgDir = orgDirs[o]
            isOrgDirExist = os.path.exists(orgDir)
            if not isOrgDirExist:
                print(orgDir, "原始路径不存在")
                del orgDir
                continue

            copyDir(orgDir, destDir, orgDirs[o], commitAddList)

        print('*' * 50)
        print("配置copy完成,开始向远程仓库提交数据")
        # 执行git commit
        gitCommit(destDir, commitAddList)
    print("end")

start(orgDirs, destDirs)

你可能感兴趣的:(Git提交规范)