Last Updated on
前言
Git作为最常用的项目版本管理工具,Git的使用,一直都没有写文章来详细说说,后续有机会,会把git系列更一下,基础当很重要。
这里,由于最近碰到一些机会,先来说说pre-commit预提交。
正文
git hook
Git能在特定的重要动作发生时触发自定义脚本钩子。钩子分为两组:
- 客户端钩子:
pre-commit
,prepare-commit-msg
,commit-msg
,post-commit
等,主要在服务端接收提交对象时、推送到服务器之前调用。 - 服务器钩子:
pre-receive
,post-receive
,update
等,主要在服务端接收提交对象时、推送到服务器之前调用。
git hooks位置位于每个git项目下的.git/hooks
目录里,进去后会看到这些钩子的官方示例,都是以.sample
结尾的文件,这些示例脚本是不会执行的,去掉.sample
后缀可激活该钩子脚本。
PS:GIt hooks的每个钩子的作用和说明,详细的以官方文档为准:https://git-scm.com/docs/githooks
pre-commit说明
pre-commit预提交,是git hooks中的一个钩子,由git commit
命令调用,可以通过--no-verify
参数绕过调用pre-commit
。通常用于在提交代码前,进行代码规范检查。
但是如果直接通过编写git hooks脚本来实现代码规范检查,会有如下的一些问题:
- 规范越多,编写的脚本越复杂
- 本地的规范修改,没法方便的同步到项目中其他开发人员
- 不同语言,代码规范不一样,脚本设置都不同
那为了更方便的管理pre-commit的设置,于是有了一个同名的工具项目pre-commit,一个用于管理和维护多语言预提交挂钩的框架。官网地址:https://pre-commit.com/
PS:由于工具项目名称和git hooks的钩子同名,容易混淆概念,主要注意一下。这里我们详细说明使用的则是同名的工具项目,而不是git自身的pre-commit脚本钩子
pre-commit框架使用
此框架是多语言的,这里以Python为例,下面内容均为Python相关的使用说明。版本为最新版2.15.0
官方文档:https://pre-commit.com/
pre-commit框架,随着发展,已经不单单只能用于git hooks的pre-commit阶段,而是能作用于所有git hooks的所有阶段,如上面说的prepare-commit-msg
, commit-msg
, post-commi
等,具体有哪些阶段,参考git官方文档:https://git-scm.com/docs/githooks
也就是说,pre-commit不单单可以用于规范代码检测,还可以在git的不同阶段,自定义做出各种不同的操作,灵活性很大,非常好用。
使用步骤
-
安装
# 直接使用pip安装即可 pip install pre-commit
安装成功后,使用
pre-commit --version
可正常查看版本。 -
设置配置文件
pre-commit依赖项目根目录配置文件.pre-commit-config.yaml
。需要手动在根目录创建此文件。# 在根目录执行如下命令,生成一个默认的配置,python版本 pre-commit sample-config > .pre-commit-config.yaml
这里配置的详细设置,后面详细说,这里先使用官方示例。
-
设置git hooks钩子脚本
pre-commit框架是通过git hooks本身的钩子来调用的,所以在设置好配置文件后,会根据配置,在git项目中将钩子脚本配置到.git/hooks
路径下。因为pre-commit框架支持各种不同阶段的钩子,所以需要根据配置,配置中使用到什么阶段的钩子,就回自动配置对应的
hooks
脚本到.git/hooks
中# 直接执行此命令,设置git hooks钩子脚本 pre-commit install
-
对所有文件进行一次检查(可选)
配置设置好后,默认是需要git commit
命令来出发调用的,只会检查git commit
中变更的文件。对所有文件进行检查:# 直接执行此命令,进行全文件检查 pre-commit run --all-files
.pre-commit-config.yaml配置详细说明
首先,是顶层的全局配置,配置项有如下这些:
repos | (必需)存储库映射列表 |
---|---|
default_language_version | (可选)从语言到应该用于该语言的默认language_version的映射。这将只覆盖没有设置language_version的单个钩子。默认为:{} |
default_stages | (可选)钩子的stages属性的配置范围默认值。这将只覆盖没有设置stages的单个钩子。默认值:all stages |
files | (可选)全局文件包含,正则匹配模版,1.21.0新配置,默认值:"" |
exclude | (可选)全局文件排除,正则匹配模版,1.1.0版本新配置,默认值:^$ |
fail_fast | (可选)设置为true时,预提交将在第一次失败后停止运行钩子。1.1.0版本新配置 |
minimum_pre_commit_version | (可选)需要pre-commit的最小版本。1.15.0版本新配置 |
举个例子说明一下,一般常用的顶层配置大致如下:
# 设置默认的阶段为commit,只在提交时进行检查
default_stages:
- commit
# 设置默认的语言版本,你也可以在每个repos中单独设置language_version
default_language_version:
python: python3.7
# 设置排除的文件,正则匹配,这个也可以在每个repos中的hooks脚本中单独配置,以灵活实现不同文件对不同规则的检测排除
exclude: "^$"
# 起码顶层配置,一般使用默认值即可。
# 这个repos配置下面的内容,就是最重要的核心配置,下面细说
repos:
- ......
repos配置
repos配置是一个存储库映射列表,用来告诉pre-commit从哪里获取钩子的代码。其有三个下层配置,都是必填,如下:
repo | git clone的存储库url |
---|---|
rev | git clone要拉取的tag或者revision |
hooks | 钩子映射列表,也就是要进行检测的钩子列表 |
第二层配置很简单,就是指定repo库的地址和版本tag,拉取代码,然后指定使用这个库中具体的哪些hooks脚本。
其中,hooks
配置为核心配置。
有哪些hooks甲脚本可选,都是从git库中的配置获得。需要具体看这个git库的使用方式。因此允许自定义库,自定义hooks脚本,然后通过pre-commit拉取使用。
hooks配置下层又有如下配置项:
id | (必须)要使用存储库中的哪个钩子,钩子的id |
---|---|
alias | (可选)允许钩子在使用pre-commit运行 |
name | (可选)重写钩子的名称-在钩子执行时显示 |
language_version | (可选) 覆盖钩子的语言版本 |
files | (可选) 覆盖默认的文件包含,正则匹配模版 |
exclude | (可选) 覆盖默认的文件排除,正则匹配模版 |
types | (可选)要运行的文件类型列表(AND) |
types_or | (可选) 要在(OR)上运行的文件类型列表 |
exclude_types | (可选)要排除的文件的类型列表 |
args | (可选)要传递给钩子的附加参数列表 |
stages | (可选)将钩子限制在commit , merge-commit , push , prepare-commit-msg , commit-msg , post-checkout , post-commit , post-merge , post-rewrite , or manual 阶段。这也就是git自身支持的不同阶段的钩子 |
additional_dependencies | (可选) 将被安装在该钩子运行的环境中的依赖项列表。 |
always_run | (可选) 如果为true,即使没有匹配的文件,这个钩子也会运行 |
verbose | (可选)如果为true,则强制打印该钩子的输出,即使该钩子通过 |
log_file | 日志文件路径,如果存在,当钩子失败或verbose为true时,钩子输出将额外写入此文件 |
举例说明,下面就列出一份常用的配置,看看一般常见的配置是怎样的,自定义的配置则自行设置即可。python为例
default_stages:
- commit
default_language_version:
python: python3.7
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.0.1
hooks:
- id: trailing-whitespace
- id: end-of-file-fixer
- id: check-yaml
- id: check-symlinks
- id: check-merge-conflict
- id: check-json
- id: check-added-large-files
args: [--maxkb=51200]
- repo: https://gitlab.com/PyCQA/flake8
rev: 4.0.1
hooks:
- id: flake8
args: [--max-line-length=120]
如上,则是一个常用的检测配置,使用了flake8
检测python代码风格以遵守pep8
规范,同时还添加了pre-commit框架项目提供的一些公共hooks,具体的使用说明,都可以直接访问repo地址,查看文档说明。
自动启用pre-commit
看上上面的介绍和使用,会发现有个问题。但我从git库中clone一个项目到本地后,即使项目中有.pre-commit-config.yaml
配置文件,但是.git/hooks
中还是没有设置钩子,需要运行pre-commit install
安装后,才能正常使用。
那如果让他根据.per-commit-config.yaml
配置自动安装git钩子呢。让我们直接clone项目后,便自动启用了pre-commit。
官方给了一个解决方式:
使用pre-commit init-templatedir命令,自动设置git项目的初始化模版,在版本中自动执行pre-commit install
以启用pre-commit。
设置步骤如下:
# 设置git全局变量,制定初始化模版目录
git config --global init.templateDir ~/.git-template
# 自动设置初始化模版
pre-commit init-templatedir ~/.git-template
ok,到此就可以了,然后可以测试一下,clone一个带.per-commit-config.yaml
配置的库,然后进行提交,则会自动进行pre-commit的检测。如果没有.per-commit-config.yaml
配置,则会跳过,普通正常使用。
尾声
pre-commit还有很多的命令和用法,这里只是列举了常见的使用,如果要进行更高级的自定义和使用,详细参考官方文档:https://pre-commit.com/
官方文档比较简单,看起来也不难,以上大多都是官方文档中的内容,后续更新和使用也以官方文档为准
👍🏻👍🏻👍🏻
设置自动启用时,git全局变量在哪里设置的
1
问题是:别人必须先装pre-commit才能生效自动启动?