目的
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
规范方式
为实现规范,我们使用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文件夹,<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"
}
}
}
配置下载
快速运行
cd 规范目录
git init
npm i
效果展示
不符合规范的git commit
符合规范的git commit
引导式提交
生成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配置成功
Android TortoiseGit配置
通过TortoiseGit提交commit时,TortoiseGit同样会校验commit-msg的配置;如果需要使用TortoiseGit配置,需要进行如下操作:
桌面右键->TortoiseGit->点击设置->找到Hoot 脚本,点击添加,具体配置如下图。
出现如下效果,说明配置成功:
更新多个项目配置
目前基于以上这套配置,需要每个项目都单独配置一次,这样就产生一个问题,如果配置文件更改,那么需要所有项目都copy一次,暂时也并未找到合适的统一管理方案,因此就有了gitCommitRuleSet.py这个脚本,此脚本的目的是代替人工的copy文件以及git提交,其中destDirs、orgDirs、ignoreFileName三个变量需要自行根据项目仓库进行设置
环境要求
- 脚本使用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)