手写 git hooks 脚本(pre-commit、commit-msg)实现代码规范校验+Git提交日志校验
手写 git hooks 脚本(pre-commit、commit-msg)实现代码规范校验+Git提交日志校验。
创建脚本文件
init-dev.sh文件位置放在根目录下。
#!/bin/bash
set -e
echo '*******************************************'
echo '***********此脚本用于开发代码时使用************'
echo '*******************************************'
#拉取代码后先执行此文件
if [[ ! -e ".git/hooks/pre-commit" ]]; then
echo "初始化checkstyle基础配置"
else
echo "更新checkstyle基础配置"
rm -rf .git/hooks/commit-msg
rm -rf .git/hooks/pre-commit
fi
cp ./checkstyle/commit-msg .git/hooks
cp ./checkstyle/pre-commit .git/hooks
chmod 700 .git/hooks/*
项目根目录下创建checkstyle文件夹
文件夹下分别存放以下文件。
checkstyle-9.3-all.jar
checkstyle-9.3-all.jar自行去官网下载,传送链。
sun_checks.xml
sun_checks.xml内容如下,可以按需调整:
<?xml version="1.0"?>
<!DOCTYPE module PUBLIC
"-//Checkstyle//DTD Checkstyle Configuration 1.3//EN"
"https://checkstyle.org/dtds/configuration_1_3.dtd">
<!--
Checkstyle configuration that checks the sun coding conventions from:
- the Java Language Specification at
https://docs.oracle.com/javase/specs/jls/se11/html/index.html
- the Sun Code Conventions at https://www.oracle.com/java/technologies/javase/codeconventions-contents.html
- the Javadoc guidelines at
https://www.oracle.com/technical-resources/articles/java/javadoc-tool.html
- the JDK Api documentation https://docs.oracle.com/en/java/javase/11/
- some best practices
Checkstyle is very configurable. Be sure to read the documentation at
https://checkstyle.org (or in your downloaded distribution).
Most Checks are configurable, be sure to consult the documentation.
To completely disable a check, just comment it out or delete it from the file.
To suppress certain violations please review suppression filters.
Finally, it is worth reading the documentation.
-->
<module name="Checker">
<!--
If you set the basedir property below, then all reported file
names will be relative to the specified directory. See
https://checkstyle.org/config.html#Checker
<property name="basedir" value="${basedir}"/>
-->
<property name="severity" value="error"/>
<property name="fileExtensions" value="java, properties, xml"/>
<!-- Excludes all 'module-info.java' files -->
<!-- See https://checkstyle.org/config_filefilters.html -->
<module name="BeforeExecutionExclusionFileFilter">
<property name="fileNamePattern" value="module\-info\.java$"/>
</module>
<!-- https://checkstyle.org/config_filters.html#SuppressionFilter -->
<module name="SuppressionFilter">
<property name="file" value="${org.checkstyle.sun.suppressionfilter.config}"
default="checkstyle-suppressions.xml" />
<property name="optional" value="true"/>
</module>
<!-- Checks that a package-info.java file exists for each package. -->
<!-- See https://checkstyle.org/config_javadoc.html#JavadocPackage -->
<!-- Checks whether files end with a new line. -->
<!-- See https://checkstyle.org/config_misc.html#NewlineAtEndOfFile -->
<!-- 检查文件是否以一个空行结束 -->
<module name="NewlineAtEndOfFile"/>
<!-- Checks that property files contain the same keys. -->
<!-- See https://checkstyle.org/config_misc.html#Translation -->
<module name="Translation"/>
<!-- Checks for Size Violations. -->
<!-- See https://checkstyle.org/config_sizes.html -->
<!-- 文件长度 -->
<module name="FileLength"/>
<!-- 每行不超过300个字 -->
<module name="LineLength">
<property name="max" value="300"/>
<property name="fileExtensions" value="java"/>
</module>
<!-- Checks for whitespace -->
<!-- See https://checkstyle.org/config_whitespace.html -->
<!-- <module name="FileTabCharacter"/>-->
<!-- Miscellaneous other checks. -->
<!-- See https://checkstyle.org/config_misc.html -->
<!-- <module name="RegexpSingleline">-->
<!-- <property name="format" value="\s+$"/>-->
<!-- <property name="minimum" value="0"/>-->
<!-- <property name="maximum" value="0"/>-->
<!-- <property name="message" value="Line has trailing spaces."/>-->
<!-- </module>-->
<!-- Checks for Headers -->
<!-- See https://checkstyle.org/config_header.html -->
<!-- <module name="Header"> -->
<!-- <property name="headerFile" value="${checkstyle.header.file}"/> -->
<!-- <property name="fileExtensions" value="java"/> -->
<!-- </module> -->
<module name="TreeWalker">
<!-- Checks for Javadoc comments. -->
<!-- See https://checkstyle.org/config_javadoc.html -->
<module name="InvalidJavadocPosition"/>
<module name="JavadocMethod">
<property name="allowMissingReturnTag" value="true"/>
</module>
<module name="JavadocType">
<property name="allowUnknownTags" value="true"/>
</module>
<!-- 变量的javadoc -->
<module name="JavadocVariable">
<!-- 忽略检查的变量名 -->
<property name='ignoreNamePattern' value='.*Business|.*Service|.*Handler|.*Mapper|.*Encoder|.*ENCODER|.*Properties|.*Listener|.*Map|.*Manager|.*Template|.*Client|.*Util.*|LOG|LOGGER'/>
</module>
<!-- 检查Javadoc -->
<module name="JavadocStyle">
<!-- 忽略句号结尾检查 -->
<property name='checkFirstSentence' value='false'/>
<property name='checkEmptyJavadoc' value='true'/>
</module>
<!-- 检查所有方法的javadoc 注意方法上的@param XXX后必须跟参数说明检查才能通过 -->
<module name="MissingJavadocMethod"/>
<!-- Checks for Naming Conventions. -->
<!-- See https://checkstyle.org/config_naming.html -->
<module name="ConstantName"/>
<module name="LocalFinalVariableName"/>
<module name="LocalVariableName"/>
<module name="MemberName"/>
<module name="MethodName"/>
<!-- 包名检查 ^[a-z]+(\.[a-z][a-z0-9]*)*$ -->
<module name="PackageName">
<property name="format" value="^[a-z]+(\.[a-z][a-z0-9]*)*$"/>
<message key="name.invalidPattern" value="包名 ''{0}'' 要符合 ''{1}''格式."/>
</module>
<module name="ParameterName"/>
<module name="StaticVariableName"/>
<!-- 类型(Class或Interface)名 ^[A-Z][a-zA-Z0-9]*$-->
<module name="TypeName">
<property name="severity" value="warning"/>
<message key="name.invalidPattern" value="名称 ''{0}'' 要符合 ''{1}''格式."/>
</module>
<!-- Checks for imports -->
<!-- See https://checkstyle.org/config_imports.html -->
<!-- import中避免星号"*" -->
<module name="AvoidStarImport">
<property name="allowClassImports" value="true"/>
</module>
<!-- 检查是否从非法的包中导入了类 -->
<module name="IllegalImport"/> <!-- defaults to sun.* packages -->
<!-- 检查是否导入了多余的包 -->
<module name="RedundantImport"/>
<!--没用的import检查,比如:1.没有被用到 2.重复的 3.import java.lang的 4.import与该类在同一个package的-->
<module name="UnusedImports">
<property name="processJavadoc" value="false"/>
</module>
<!-- Checks for Size Violations. -->
<!-- See https://checkstyle.org/config_sizes.html -->
<!-- 方法不超过300行 -->
<module name="MethodLength">
<property name="tokens" value="METHOD_DEF"/>
<property name="max" value="300"/>
</module>
<module name="ParameterNumber"/>
<!-- Checks for whitespace -->
<!-- See https://checkstyle.org/config_whitespace.html -->
<module name="EmptyForIteratorPad"/>
<module name="GenericWhitespace"/>
<module name="MethodParamPad"/>
<module name="NoWhitespaceAfter"/>
<module name="NoWhitespaceBefore"/>
<module name="OperatorWrap"/>
<module name="ParenPad"/>
<module name="TypecastParenPad"/>
<module name="WhitespaceAfter"/>
<module name="WhitespaceAround"/>
<!-- Modifier Checks -->
<!-- See https://checkstyle.org/config_modifier.html -->
<module name="ModifierOrder"/>
<module name="RedundantModifier"/>
<!-- Checks for blocks. You know, those {}'s -->
<!-- See https://checkstyle.org/config_blocks.html -->
<!-- 多余的括号 -->
<module name="AvoidNestedBlocks">
<property name="allowInSwitchCase" value="true"/>
</module>
<module name="EmptyBlock"/>
<module name="LeftCurly"/>
<module name="NeedBraces"/>
<module name="RightCurly"/>
<!-- Checks for common coding problems -->
<!-- See https://checkstyle.org/config_coding.html -->
<module name="EmptyStatement"/>
<module name="EqualsHashCode"/>
<!-- 检查局部变量或参数是否隐藏了类中的变量 -->
<module name="HiddenField">
<property name="tokens" value="VARIABLE_DEF"/>
</module>
<module name="IllegalInstantiation"/>
<module name="InnerAssignment"/>
<!-- <module name="MagicNumber"/>-->
<module name="MissingSwitchDefault"/>
<module name="MultipleVariableDeclarations"/>
<module name="SimplifyBooleanExpression"/>
<module name="SimplifyBooleanReturn"/>
<!-- Checks for class design -->
<!-- See https://checkstyle.org/config_design.html -->
<!-- <module name="DesignForExtension"/>-->
<module name="FinalClass"/>
<!-- <module name="HideUtilityClassConstructor"/>-->
<module name="InterfaceIsType"/>
<module name="VisibilityModifier"/>
<!-- Miscellaneous other checks. -->
<!-- See https://checkstyle.org/config_misc.html -->
<module name="ArrayTypeStyle"/>
<!-- <module name="FinalParameters"/>-->
<module name="TodoComment"/>
<module name="UpperEll"/>
<!-- https://checkstyle.org/config_filters.html#SuppressionXpathFilter -->
<module name="SuppressionXpathFilter">
<property name="file" value="${org.checkstyle.sun.suppressionxpathfilter.config}"
default="checkstyle-xpath-suppressions.xml" />
<property name="optional" value="true"/>
</module>
<!-- 禁止使用System.out.println -->
<module name="Regexp">
<property name="format" value=".printStackTrace"/>
<property name="illegalPattern" value="true"/>
</module>
<module name="Regexp">
<property name="format" value="System.out.println"/>
<property name="illegalPattern" value="true"/>
</module>
<!-- 不许使用与代码同行的注释 -->
<module name="TrailingComment"/>
<!-- 不许存在TODO -->
<module name="TodoComment"/>
<!-- 除了正常的程序入口之外,所有的main方法都应该被删掉或注释掉 -->
<module name="UncommentedMain">
<property name="excludedClasses" value=".*[Application,Test]$"/>
</module>
</module>
</module>
pre-commit
pre-commit文件内容如下,可以配置具体的项目代码位置,或者仅扫描提交的代码。
#!/bin/sh
echo '*******************************************'
echo '***************强制检查代码规范***************'
echo '****参考:Checkstyle代码规范检查使用教程.md****'
echo '*******************************************'
#指定路径扫描
#java -jar checkstyle/checkstyle-9.3-all.jar -c checkstyle/sun_checks.xml abc-modules/abc-upms-biz/src
#每次扫描仅对当前提交的内容来扫
#java -jar checkstyle/checkstyle-9.3-all.jar -c checkstyle/sun_checks.xml $(git diff --cached --name-only --diff-filter=ACM -- '*.java')
java -jar checkstyle/checkstyle-9.3-all.jar -c checkstyle/sun_checks.xml $(git diff --cached --name-only --diff-filter=ACM -- '*')
exitCode="$?"
exit $exitCode
commit-msg
commit-msg的内容如下:
#!/bin/sh
echo '*******************************************'
echo '********强制检查git commit msg提交格式********'
echo '******提交格式参考文档:Git提交日志规范.md******'
echo '*******************************************'
# 用 `` 可以将命令的输出结果赋值给变量
# 获取当前提交的 commit msg
commit_msg=`cat $1`
# 获取用户 email
email=`git config user.email`
msg_re="^(feat|fix|docs|style|refactor|perf|test|workflow|build|ci|chore|release|workflow)(\(.+\))?: .{1,100}"
if [[ ! $commit_msg =~ $msg_re ]]
then
echo "\n不合法的 commit 消息提交格式,请使用正确的格式:\
\nfeat: add comments\
\nfix: handle events on blur (close #28)\
\n详情请查看 git commit 提交规范:https://github.com/woai3c/Front-end-articles/blob/master/git%20commit%20style.md"
# 异常退出
exit 1
fi
# 对用户权限做判断则比较简单,只需要检查用户的邮箱或用户名就可以了(假设现在只有 abc 公司的员工才有权限提交代码)。
#email_re="@abc\.com"
#if [[ ! $email =~ $email_re ]]
#then
# echo "此用户没有权限,具有权限的用户为: xxx@abc.com"
#
# # 异常退出
# exit 1
#fi
以上配置完成之后,执行脚本init-dev.sh初始化配置即可生效,之后在提交代码时,就可以针对代码规范进行检查、针对Git提交的msg信息格式进行检查。
sh init-dev.sh
以下是Git提交日志的规范:
Git提交日志规范
提交代码时,如果不能形成有效约束,依靠个人的自觉,这样即使每个人是积极的状态,但是每个人的知识构成不同,也会造成提交风格迥异。
commit-message规范必要性
- 统一格式的提交记录,更清晰和易读
- 可以通过提交记录来了解本次提交的目的,更好的CR和重构
- 更容易了解变更,定位和发现问题
- 每个提交描述都是经过思考的,改善提交质量
- 生成变更记录
git commit 提交规范
<type>(<scope>): <subject>
<body>
<footer>
大致分为三个部分(使用空行分割):
- 标题行: 必填, 描述主要修改类型和内容
- 主题内容: 描述为什么修改, 做了什么样的修改, 以及开发的思路等等
- 页脚注释: 放 Breaking Changes 或 Closed Issues
type
commit 的类型:
- feat: 新功能、新特性
- fix: 修改 bug
- perf: 更改代码,以提高性能(在不影响代码内部行为的前提下,对程序性能进行优化)
- refactor: 代码重构(重构,在不影响代码内部行为、功能下的代码修改)
- docs: 文档修改
- style: 代码格式修改, 注意不是 css 修改(例如分号修改)
- test: 测试用例新增、修改
- build: 影响项目构建或依赖项修改
- revert: 恢复上一次提交
- ci: 持续集成相关文件修改
- chore: 其他修改(不在上述类型中的修改)
- release: 发布新版本
scope
commit 影响的范围, 比如: route, component, utils, build…
subject
commit 的概述
body
commit 具体修改内容, 可以分为多行.
footer
一些备注, 通常是 BREAKING CHANGE 或修复的 bug 的链接.
约定式提交规范
以下内容来源于:https://www.conventionalcommits.org/zh-hans/v1.0.0-beta.4/
- 每个提交都必须使用类型字段前缀,它由一个名词组成,诸如
feat
或fix
,其后接一个可选的作用域字段,以及一个必要的冒号(英文半角)和空格。 - 当一个提交为应用或类库实现了新特性时,必须使用
feat
类型。 - 当一个提交为应用修复了
bug
时,必须使用fix
类型。 - 作用域字段可以跟随在类型字段后面。作用域必须是一个描述某部分代码的名词,并用圆括号包围,例如:
fix(parser):
- 描述字段必须紧接在类型/作用域前缀的空格之后。描述指的是对代码变更的简短总结,例如:
fix: array parsing issue when multiple spaces were contained in string.
- 在简短描述之后,可以编写更长的提交正文,为代码变更提供额外的上下文信息。正文必须起始于描述字段结束的一个空行后。
- 在正文结束的一个空行之后,可以编写一行或多行脚注。脚注必须包含关于提交的元信息,例如:关联的合并请求、Reviewer、破坏性变更,每条元信息一行。
- 破坏性变更必须标示在正文区域最开始处,或脚注区域中某一行的开始。一个破坏性变更必须包含大写的文本
BREAKING CHANGE
,后面紧跟冒号和空格。 - 在
BREAKING CHANGE:
之后必须提供描述,以描述对 API 的变更。例如:BREAKING CHANGE: environment variables now take precedence over config files.
- 在提交说明中,可以使用
feat
和fix
之外的类型。 - 工具的实现必须不区分大小写地解析构成约定式提交的信息单元,只有
BREAKING CHANGE
必须是大写的。 - 可以在类型/作用域前缀之后,: 之前,附加
!
字符,以进一步提醒注意破坏性变更。当有!
前缀时,正文或脚注内必须包含BREAKING CHANGE: description
示例
fix
如果修复的这个BUG只影响当前修改的文件,可不加范围。如果影响的范围比较大,要加上范围描述。
例如这次 BUG 修复影响到全局,可以加个 global。如果影响的是某个目录或某个功能,可以加上该目录的路径,或者对应的功能名称。
// 示例1
fix(global): 修复checkbox不能复选的问题
// 示例2 下面圆括号里的 common 为通用管理的名称
fix(common): 修复字体过小的BUG,将通用管理下所有页面的默认字体大小修改为 14px
// 示例3
fix: value.length -> values.length
feat
feat: 添加网站主页静态页面
这是一个示例,假设对点检任务静态页面进行了一些描述。
这里是备注,可以是放BUG链接或者一些重要性的东西。
chore
chore 的中文翻译为日常事务、例行工作,顾名思义,即不在其他 commit 类型中的修改,都可以用 chore 表示。
chore: 将表格中的查看详情改为详情
参考资料
更多推荐
所有评论(0)