Git提交规范

目的

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

commit message格式

<type>: <subject>
// 空一行
 <body>
 // 空一行
 <footer>
  • 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

规范方式

为实现规范,我们使用commitlinthusky来进行提交检查,思路是:当执行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文件夹,<font color=red>切记要将node_modules/添加到忽略文件.gitignore中</font>

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

  • 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)

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,271评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,275评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,151评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,550评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,553评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,559评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,924评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,580评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,826评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,578评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,661评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,363评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,940评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,926评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,156评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,872评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,391评论 2 342

推荐阅读更多精彩内容