高级功能¶
Advanced features
迁移模式(migration)下运行¶
Running in migration mode
默认情况下,如果您已存在钩子,pre-commit install
将以迁移模式安装,它会同时运行您现有的钩子和 pre-commit 的钩子。
要禁用此行为,请在 install
命令中传递 -f
/ --overwrite
参数。
如果您决定不使用 pre-commit,pre-commit uninstall
将恢复您的钩子到安装前的状态。
By default, if you have existing hooks pre-commit install
will install in a
migration mode which runs both your existing hooks and hooks for pre-commit.
To disable this behavior, pass -f
/ --overwrite
to the install
command.
If you decide not to use pre-commit, pre-commit uninstall
will
restore your hooks to the state prior to installation.
暂时关闭钩子¶
Temporarily disabling hooks
不是所有的钩子都是完美的,所以有时您可能需要跳过一个或多个钩子的执行。pre-commit 通过查询 SKIP
环境变量来解决这个问题。SKIP
环境变量是一个用逗号分隔的钩子 ID 列表。这允许您跳过单个钩子,而不是使用 --no-verify
跳过整个提交。
$ SKIP=flake8 git commit -m "foo"
Not all hooks are perfect so sometimes you may need to skip execution of one
or more hooks. pre-commit solves this by querying a SKIP
environment
variable. The SKIP
environment variable is a comma separated list of hook
ids. This allows you to skip a single hook instead of --no-verify
ing the
entire commit.
$ SKIP=flake8 git commit -m "foo"
限制钩子在某些阶段运行¶
Confining hooks to run at certain stages
pre-commit 支持许多不同类型的 git
钩子(不仅仅是 pre-commit
!)。
钩子的提供者可以通过在 .pre-commit-hooks.yaml
中设置 stages
属性来选择他们运行的 git 钩子类型——这也可以被 .pre-commit-config.yaml
中的 stages
覆盖。如果在这两个地方都没有设置 stages
,那么将从顶级的 default_stages
选项中获取默认值(默认为所有阶段)。默认情况下,工具会为 pre-commit 支持的每个钩子类型启用。
新功能 3.2.0:stages
的值与钩子名称匹配。以前,commit
、push
和 merge-commit
分别对应 pre-commit
、pre-push
和 pre-merge-commit
。
通过 stages: [manual]
设置的 manual
阶段是一个特殊阶段,它不会被任何 git
钩子自动触发——这在您想要添加一个不自动运行的工具时很有用,但可以使用 pre-commit run --hook-stage manual [hookid]
按需运行。
如果您是工具的作者,通常最好提供一个合适的 stages
属性。例如,对于一个 linter 或代码格式化工具来说,合理的设置可能是 stages: [pre-commit, pre-merge-commit, pre-push, manual]
。
要为特定的 git 钩子安装 pre-commit
,请向 pre-commit install
传递 --hook-type
。这可以多次指定,例如:
$ pre-commit install --hook-type pre-commit --hook-type pre-push
pre-commit installed at .git/hooks/pre-commit
pre-commit installed at .git/hooks/pre-push
此外,可以通过设置顶级的 default_install_hook_types
来指定一组默认的 git 钩子类型进行安装。
例如:
default_install_hook_types: [pre-commit, pre-push, commit-msg]
$ pre-commit install
pre-commit installed at .git/hooks/pre-commit
pre-commit installed at .git/hooks/pre-push
pre-commit installed at .git/hooks/commit-msg
pre-commit supports many different types of git
hooks (not just
pre-commit
!).
Providers of hooks can select which git hooks they run on by setting the
stages
property in .pre-commit-hooks.yaml
-- this can
also be overridden by setting stages
in
.pre-commit-config.yaml
. If stages
is not set in either of those places
the default value will be pulled from the top-level
default_stages
option (which defaults to all
stages). By default, tools are enabled for every hook type
that pre-commit supports.
new in 3.2.0: The values of stages
match the hook names. Previously,
commit
, push
, and merge-commit
matched pre-commit
, pre-push
, and
pre-merge-commit
respectively.
The manual
stage (via stages: [manual]
) is a special stage which will not
be automatically triggered by any git
hook -- this is useful if you want to
add a tool which is not automatically run, but is run on demand using
pre-commit run --hook-stage manual [hookid]
.
If you are authoring a tool, it is usually a good idea to provide an appropriate
stages
property. For example a reasonable setting for a linter or code
formatter would be stages: [pre-commit, pre-merge-commit, pre-push, manual]
.
To install pre-commit
for particular git hooks, pass --hook-type
to
pre-commit install
. This can be specified multiple times such as:
$ pre-commit install --hook-type pre-commit --hook-type pre-push
pre-commit installed at .git/hooks/pre-commit
pre-commit installed at .git/hooks/pre-push
Additionally, one can specify a default set of git hook types to be installed
for by setting the top-level default_install_hook_types
.
For example:
default_install_hook_types: [pre-commit, pre-push, commit-msg]
$ pre-commit install
pre-commit installed at .git/hooks/pre-commit
pre-commit installed at .git/hooks/pre-push
pre-commit installed at .git/hooks/commit-msg
支持的git钩子¶
Supported git hooks
- commit-msg
- post-checkout
- post-commit
- post-merge
- post-rewrite
- pre-commit
- pre-merge-commit
- pre-push
- pre-rebase
- prepare-commit-msg
commit-msg¶
commit-msg
钩子将传递一个文件名参数——此文件包含要验证的当前提交消息的内容。如果退出码非零,提交将被中止。
commit-msg
hooks will be passed a single filename -- this file contains the
current contents of the commit message to be validated. The commit will be
aborted if there is a nonzero exit code.
post-checkout¶
新功能 2.2.0
post-checkout
钩子在 checkout
操作之后运行,可以用来设置或管理仓库中的状态。
post-checkout
钩子不操作文件,所以它们必须设置为 always_run: true
,否则它们将总是被跳过。
环境变量:
PRE_COMMIT_FROM_REF
:post-checkout
git 钩子的第一个参数PRE_COMMIT_TO_REF
:post-checkout
git 钩子的第二个参数PRE_COMMIT_CHECKOUT_TYPE
:post-checkout
git 钩子的第三个参数
new in 2.2.0
post-checkout hooks run after a checkout
has occurred and can be used to
set up or manage state in the repository.
post-checkout
hooks do not operate on files so they must be set as
always_run: true
or they will always be skipped.
environment variables:
- PRE_COMMIT_FROM_REF
: the first argument to the post-checkout
git hook
- PRE_COMMIT_TO_REF
: the second argument to the post-checkout
git hook
- PRE_COMMIT_CHECKOUT_TYPE
: the third argument to the post-checkout
git hook
post-commit¶
新功能 2.4.0
post-commit
钩子在提交已经成功之后运行,因此它不能用来阻止提交发生。
post-commit
钩子不操作文件,所以它们必须设置为 always_run: true
,否则它们将总是被跳过。
new in 2.4.0
post-commit
runs after the commit has already succeeded so it cannot be used
to prevent the commit from happening.
post-commit
hooks do not operate on files so they must be set as
always_run: true
or they will always be skipped.
post-merge¶
新功能 2.11.0
post-merge
在 git merge
操作成功之后运行。
post-merge
钩子不操作文件,所以它们必须设置为 always_run: true
,否则它们将总是被跳过。
环境变量:
PRE_COMMIT_IS_SQUASH_MERGE
:post-merge
git 钩子的第一个参数。
new in 2.11.0
post-merge
runs after a successful git merge
.
post-merge
hooks do not operate on files so they must be set as
always_run: true
or they will always be skipped.
environment variables:
- PRE_COMMIT_IS_SQUASH_MERGE
: the first argument to the post-merge
git hook.
post-rewrite¶
new in 2.15.0
post-rewrite
在像 git commit --amend
或 git rebase
这样修改历史记录的 git 命令之后运行。
post-rewrite
钩子不会操作文件,所以它们必须设置为 always_run: true
,否则它们将总是被跳过。
环境变量:
PRE_COMMIT_REWRITE_COMMAND
:post-rewrite
git 钩子的第一个参数。
new in 2.15.0
post-rewrite
runs after a git command which modifies history such as
git commit --amend
or git rebase
.
post-rewrite
hooks do not operate on files so they must be set as
always_run: true
or they will always be skipped.
environment variables:
PRE_COMMIT_REWRITE_COMMAND
: the first argument to thepost-rewrite
git hook.
pre-commit¶
pre-commit
在提交最终确定之前被触发,以允许对正在提交的代码进行检查。如果在提交过程中对未暂存的更改运行钩子,可能会导致提交期间出现误报和漏报。pre-commit 仅在暂存的文件内容上运行,通过在运行钩子时临时存储未暂存的更改。
pre-commit
is triggered before the commit is finalized to allow checks on the
code being committed. Running hooks on unstaged changes can lead to both
false-positives and false-negatives during committing. pre-commit only runs
on the staged contents of files by temporarily stashing the unstaged changes
while running hooks.
pre-merge-commit¶
pre-merge-commit
在合并成功后但创建合并提交之前触发。这个钩子在合并的所有暂存文件上运行。
注意,你需要使用至少 git 2.24 版本才能使用这个钩子。
pre-merge-commit
fires after a merge succeeds but before the merge commit is
created. This hook runs on all staged files from the merge.
Note that you need to be using at least git 2.24 for this hook.
pre-push¶
pre-push
在执行 git push
时被触发。
环境变量:
- PRE_COMMIT_FROM_REF
: 正在被推送到的修订版。
- PRE_COMMIT_TO_REF
: 正在被推送到远程的本地修订版。
- PRE_COMMIT_REMOTE_NAME
: 正在推送到的远程名称(例如 origin
)。
- PRE_COMMIT_REMOTE_URL
: 正在推送到的远程的 URL(例如 git@github.com:pre-commit/pre-commit
)。
- PRE_COMMIT_REMOTE_BRANCH
: 我们正在推送到的远程分支的名称(例如 refs/heads/target-branch
)。
- PRE_COMMIT_LOCAL_BRANCH
: 正在推送到远程的本地分支的名称(例如 HEAD
)。
pre-push
is triggered on git push
.
environment variables:
- PRE_COMMIT_FROM_REF
: the revision that is being pushed to.
- PRE_COMMIT_TO_REF
: the local revision that is being pushed to the remote.
- PRE_COMMIT_REMOTE_NAME
: which remote is being pushed to (for example origin
)
- PRE_COMMIT_REMOTE_URL
: the url of the remote that is being pushed to (for
example git@github.com:pre-commit/pre-commit
)
- PRE_COMMIT_REMOTE_BRANCH
: the name of the remote branch to which we are
pushing (for example refs/heads/target-branch
)
- PRE_COMMIT_LOCAL_BRANCH
: the name of the local branch that is being pushed
to the remote (for example HEAD
)
pre-rebase¶
在版本 3.2.0 中引入的新特性:
pre-rebase
钩子在执行变基操作之前被触发。如果钩子执行失败,可以取消变基操作。
pre-rebase
钩子不操作文件,因此它们必须设置为 always_run: true
,否则它们将总是被跳过。
环境变量:
- PRE_COMMIT_PRE_REBASE_UPSTREAM
:pre-rebase
Git 钩子的第一个参数
- PRE_COMMIT_PRE_REBASE_BRANCH
:pre-rebase
Git 钩子的第二个参数。
new in 3.2.0
pre-rebase
is triggered before a rebase occurs. A hook failure can cancel a
rebase from occurring.
pre-rebase
hooks do not operate on files so they must be set as
always_run: true
or they will always be skipped.
environment variables:
- PRE_COMMIT_PRE_REBASE_UPSTREAM
: the first argument to the pre-rebase
git hook
- PRE_COMMIT_PRE_REBASE_BRANCH
: the second argument to the pre-rebase
git hook.
prepare-commit-msg¶
prepare-commit-msg
钩子在提交信息编辑器启动之前被调用,它将接收一个文件名参数——这个文件可能是空的,或者它可能包含来自 -m
参数或其他模板的提交信息。prepare-commit-msg
钩子可以修改这个文件的内容,从而改变将要提交的内容。钩子可能需要检查 GIT_EDITOR=:
,因为这表示不会启动编辑器。如果钩子以非零状态退出,则会中止提交。
环境变量:
PRE_COMMIT_COMMIT_MSG_SOURCE
:prepare-commit-msg
Git 钩子的第二个参数PRE_COMMIT_COMMIT_OBJECT_NAME
:prepare-commit-msg
Git 钩子的第三个参数
prepare-commit-msg
hooks will be passed a single filename -- this file may
be empty or it could contain the commit message from -m
or from other
templates. prepare-commit-msg
hooks can modify the contents of this file to
change what will be committed. A hook may want to check for GIT_EDITOR=:
as
this indicates that no editor will be launched. If a hook exits nonzero, the
commit will be aborted.
environment variables:
- PRE_COMMIT_COMMIT_MSG_SOURCE
: the second argument to the
prepare-commit-msg
git hook
- PRE_COMMIT_COMMIT_OBJECT_NAME
: the third argument to the
prepare-commit-msg
git hook
给钩子传递参数¶
Passing arguments to hooks
在某些情况下,钩子(hooks)需要参数才能正确运行。你可以通过在 .pre-commit-config.yaml
文件中的 args
属性里指定参数来传递静态参数,如下所示:
- repo: https://github.com/PyCQA/flake8
rev: 4.0.1
hooks:
- id: flake8
args: [--max-line-length=131]
这将会把 --max-line-length=131
参数传递给 flake8
工具。
Sometimes hooks require arguments to run correctly. You can pass static
arguments by specifying the args
property in your .pre-commit-config.yaml
as follows:
- repo: https://github.com/PyCQA/flake8
rev: 4.0.1
hooks:
- id: flake8
args: [--max-line-length=131]
This will pass --max-line-length=131
to flake8
.
钩子中的参数模式¶
Arguments pattern in hooks
如果您正在编写自己的自定义钩子,则您的钩子应该预期接收 args
参数值,然后是一组已暂存的文件列表。
例如,假设有一个 .pre-commit-config.yaml
文件:
- repo: https://github.com/path/to/your/hook/repo
rev: badf00ddeadbeef
hooks:
- id: my-hook-script-id
args: [--myarg1=1, --myarg1=2]
当您下次运行 pre-commit
时,将调用您的脚本:
path/to/script-or-system-exe --myarg1=1 --myarg1=2 dir/file1 dir/file2 file3
如果 args
属性为空或未定义,将调用您的脚本:
path/to/script-or-system-exe dir/file1 dir/file2 file3
在创建本地钩子时,没有必要将命令参数放入 args
中,因为没有什么东西可以覆盖它们——相反,直接把参数直接放入钩子的 entry
中。
例如:
- repo: local
hooks:
- id: check-requirements
name: 检查需求文件
language: system
entry: python -m scripts.check_requirements --compare
files: ^requirements.*\.txt$
If you are writing your own custom hook, your hook should expect to receive
the args
value and then a list of staged files.
For example, assuming a .pre-commit-config.yaml
:
- repo: https://github.com/path/to/your/hook/repo
rev: badf00ddeadbeef
hooks:
- id: my-hook-script-id
args: [--myarg1=1, --myarg1=2]
When you next run pre-commit
, your script will be called:
path/to/script-or-system-exe --myarg1=1 --myarg1=2 dir/file1 dir/file2 file3
If the args
property is empty or not defined, your script will be called:
path/to/script-or-system-exe dir/file1 dir/file2 file3
When creating local hooks, there's no reason to put command arguments
into args
as there is nothing which can override them --
instead put your arguments directly in the hook entry
.
For example:
- repo: local
hooks:
- id: check-requirements
name: check requirements files
language: system
entry: python -m scripts.check_requirements --compare
files: ^requirements.*\.txt$
本地仓库钩子¶
Repository local hooks
仓库本地钩子在以下情况下很有用:
- 当脚本与仓库紧密相关,并且将钩子脚本与仓库一起分发是有意义的。
- 钩子需要的状态仅存在于仓库构建产物中(例如,用于 pylint 的应用虚拟环境)。
- 某个 linter 的官方仓库没有 pre-commit 元数据。
您可以通过指定 repo
为哨兵值 local
来配置仓库本地钩子。
本地钩子可以使用支持 additional_dependencies
的任何语言,或者使用 docker_image
/ fail
/ pygrep
/ script
/ system
。
这使您能够安装以前需要一个简单的镜像仓库的东西。
一个 local
钩子必须定义 id
, name
, language
, entry
, 和 files
/ types
如在 创建新钩子 下所指定。
这里有一个带有一些 local
钩子的示例配置:
- repo: local
hooks:
- id: pylint
name: pylint
entry: pylint
language: system
types: [python]
require_serial: true
- id: check-x
name: 检查 X
entry: ./bin/check-x.sh
language: script
files: \.x$
- id: scss-lint
name: scss-lint
entry: scss-lint
language: ruby
language_version: 2.1.5
types: [scss]
additional_dependencies: ['scss_lint:0.52.0']
Repository-local hooks are useful when:
- The scripts are tightly coupled to the repository and it makes sense to distribute the hook scripts with the repository.
- Hooks require state that is only present in a built artifact of your repository (such as your app's virtualenv for pylint).
- The official repository for a linter doesn't have the pre-commit metadata.
You can configure repository-local hooks by specifying the repo
as the
sentinel local
.
local hooks can use any language which supports additional_dependencies
or docker_image
/ fail
/ pygrep
/ script
/ system
.
This enables you to install things which previously would require a trivial
mirror repository.
A local
hook must define id
, name
, language
,
entry
, and files
/ types
as specified under Creating new hooks.
Here's an example configuration with a few local
hooks:
- repo: local
hooks:
- id: pylint
name: pylint
entry: pylint
language: system
types: [python]
require_serial: true
- id: check-x
name: Check X
entry: ./bin/check-x.sh
language: script
files: \.x$
- id: scss-lint
name: scss-lint
entry: scss-lint
language: ruby
language_version: 2.1.5
types: [scss]
additional_dependencies: ['scss_lint:0.52.0']
内置钩子¶
meta hooks
pre-commit
提供了几个钩子,这些钩子对于检查 pre-commit 配置本身非常有用。这些钩子可以使用 repo: meta
来启用。
- repo: meta
hooks:
- id: ...
当前可用的 meta
钩子:
配置项 | 描述 |
---|---|
check-hooks-apply |
确保配置的钩子至少适用于仓库中的一个文件。 |
check-useless-excludes |
确保 exclude 指令适用于仓库中的任何一个文件。 |
identity |
一个简单的钩子,它打印传给它的所有参数,对调试很有用。 |
pre-commit
provides several hooks which are useful for checking the
pre-commit configuration itself. These can be enabled using repo: meta
.
- repo: meta
hooks:
- id: ...
The currently available meta
hooks:
=r=
=c= [`check-hooks-apply`](_#meta-check_hooks_apply)
=c= ensures that the configured hooks apply to at least one file in the
repository.
=r=
=c= [`check-useless-excludes`](_#meta-check_useless_excludes)
=c= ensures that `exclude` directives apply to _any_ file in the
repository.
=r=
=c= [`identity`](_#meta-identity)
=c= a simple hook which prints all arguments passed to it, useful for
debugging.
自动启用存储库的预提交¶
automatically enabling pre-commit on repositories
pre-commit init-templatedir
可用于设置 git
的 init.templateDir
选项的骨架。这意味着任何新克隆的仓库将自动设置钩子,无需运行 pre-commit install
。
要配置,请首先设置 git
的 init.templateDir
——在这个例子中,我使用 ~/.git-template
作为我的模板目录。
$ git config --global init.templateDir ~/.git-template
$ pre-commit init-templatedir ~/.git-template
pre-commit installed at /home/asottile/.git-template/hooks/pre-commit
现在,每当您克隆一个启用了 pre-commit 的仓库时,钩子已经被设置好了!
$ git clone -q git@github.com:asottile/pyupgrade
$ cd pyupgrade
$ git commit --allow-empty -m 'Hello world!'
Check docstring is first.............................(no files to check)Skipped
Check Yaml...........................................(no files to check)Skipped
Debug Statements (Python)............................(no files to check)Skipped
...
init-templatedir
使用了 pre-commit install
的 --allow-missing-config
选项,因此没有配置的仓库将被跳过:
$ git init sample
Initialized empty Git repository in /tmp/sample/.git/
$ cd sample
$ git commit --allow-empty -m 'Initial commit'
`.pre-commit-config.yaml` config file not found. Skipping `pre-commit`.
[main (root-commit) d1b39c1] Initial commit
要仍然需要选择加入,但提示用户设置 pre-commit,使用如下的模板钩子(例如在 ~/.git-template/hooks/pre-commit
中)。
#!/usr/bin/env bash
if [ -f .pre-commit-config.yaml ]; then
echo 'pre-commit configuration detected, but `pre-commit install` was never run' 1>&2
exit 1
fi
这样,如果忘记运行 pre-commit install
,在提交时会产生错误:
$ git clone -q https://github.com/asottile/pyupgrade
$ cd pyupgrade/
$ git commit -m 'foo'
pre-commit configuration detected, but `pre-commit install` was never run
pre-commit init-templatedir
can be used to set up a skeleton for git
's
init.templateDir
option. This means that any newly cloned repository will
automatically have the hooks set up without the need to run
pre-commit install
.
To configure, first set git
's init.templateDir
-- in this example I'm
using ~/.git-template
as my template directory.
$ git config --global init.templateDir ~/.git-template
$ pre-commit init-templatedir ~/.git-template
pre-commit installed at /home/asottile/.git-template/hooks/pre-commit
Now whenever you clone a pre-commit enabled repo, the hooks will already be set up!
$ git clone -q git@github.com:asottile/pyupgrade
$ cd pyupgrade
$ git commit --allow-empty -m 'Hello world!'
Check docstring is first.............................(no files to check)Skipped
Check Yaml...........................................(no files to check)Skipped
Debug Statements (Python)............................(no files to check)Skipped
...
init-templatedir
uses the --allow-missing-config
option from
pre-commit install
so repos without a config will be skipped:
$ git init sample
Initialized empty Git repository in /tmp/sample/.git/
$ cd sample
$ git commit --allow-empty -m 'Initial commit'
`.pre-commit-config.yaml` config file not found. Skipping `pre-commit`.
[main (root-commit) d1b39c1] Initial commit
To still require opt-in, but prompt the user to set up pre-commit use a
template hook as follows (for example in ~/.git-template/hooks/pre-commit
).
#!/usr/bin/env bash
if [ -f .pre-commit-config.yaml ]; then
echo 'pre-commit configuration detected, but `pre-commit install` was never run' 1>&2
exit 1
fi
With this, a forgotten pre-commit install
produces an error on commit:
$ git clone -q https://github.com/asottile/pyupgrade
$ cd pyupgrade/
$ git commit -m 'foo'
pre-commit configuration detected, but `pre-commit install` was never run
根据文件类型过滤¶
Filtering files with types
使用 types
进行过滤相比传统的使用 files
过滤有多个优势:
- 不需要容易出错的正则表达式。
- 可以通过文件的 shebang(即使是没有扩展名的文件)进行匹配。
- 可以轻松忽略符号链接/子模块。
types
是按钩子指定为标签数组。这些标签是通过 identify 库的一组启发式方法发现的。选择 identify
是因为它是一个小型的、可移植的、纯 Python 库。
以下是一些 identify
常见的标签:
file
symlink
directory
- 在 pre-commit 的上下文中,这将是子模块executable
- 文件是否设置了可执行位text
- 文件是否看起来像文本文件binary
- 文件是否看起来像二进制文件- 按扩展名/命名约定的标签
- 按 shebang (
#!
) 的标签
要发现任何文件在磁盘上的类型,您可以使用 identify
的命令行界面:
$ identify-cli setup.py
["file", "non-executable", "python", "text"]
$ identify-cli some-random-file
["file", "non-executable", "text"]
$ identify-cli --filename-only some-random-file; echo $?
1
如果您使用的文件扩展名不受支持,请提交一个拉取请求!
types
、types_or
和 files
在过滤时会与 AND
一起评估。types
内的标签也使用 AND
评估。
2.9.0 版本新功能:types_or
内的标签使用 OR
评估。
例如:
files: ^foo/
types: [file, python]
将匹配文件 foo/1.py
,但不会匹配 setup.py
。
另一个例子:
files: ^foo/
types_or: [javascript, jsx, ts, tsx]
将匹配 foo/bar.js
/ foo/bar.jsx
/ foo/bar.ts
/ foo/bar.tsx
中的任何一个,但不会匹配 baz.js
。
如果您想匹配在使用现有钩子时未包含在 type
中的文件路径,则需要回退到仅使用 files
匹配,通过覆盖 types
设置。以下是使用 check-json
对非 JSON 文件进行匹配的示例:
- id: check-json
types: [file] # 覆盖 `types: [json]`
files: \.(json|myext)$
文件也可以通过 shebang 匹配。使用 types: python
时,以 #!/usr/bin/env python3
开始的 exe
也将被匹配。
与 files
和 exclude
一样,如果需要,也可以使用 exclude_types
排除类型。
Filtering with types
provides several advantages over traditional filtering
with files
.
- no error-prone regular expressions
- files can be matched by their shebang (even when extensionless)
- symlinks / submodules can be easily ignored
types
is specified per hook as an array of tags. The tags are discovered
through a set of heuristics by the
identify library. identify
was
chosen as it is a small portable pure python library.
Some of the common tags you'll find from identify:
file
symlink
directory
- in the context of pre-commit this will be a submoduleexecutable
- whether the file has the executable bit settext
- whether the file looks like a text filebinary
- whether the file looks like a binary file- tags by extension / naming convention
- tags by shebang (
#!
)
To discover the type of any file on disk, you can use identify
's cli:
$ identify-cli setup.py
["file", "non-executable", "python", "text"]
$ identify-cli some-random-file
["file", "non-executable", "text"]
$ identify-cli --filename-only some-random-file; echo $?
1
If a file extension you use is not supported, please submit a pull request!
types
, types_or
, and files
are evaluated together with AND
when
filtering. Tags within types
are also evaluated using AND
.
new in 2.9.0: Tags within types_or
are evaluated using OR
.
For example:
files: ^foo/
types: [file, python]
will match a file foo/1.py
but will not match setup.py
.
Another example:
files: ^foo/
types_or: [javascript, jsx, ts, tsx]
will match any of foo/bar.js
/ foo/bar.jsx
/ foo/bar.ts
/ foo/bar.tsx
but not baz.js
.
If you want to match a file path that isn't included in a type
when using an
existing hook you'll need to revert back to files
only matching by overriding
the types
setting. Here's an example of using check-json
against non-json
files:
- id: check-json
types: [file] # override `types: [json]`
files: \.(json|myext)$
Files can also be matched by shebang. With types: python
, an exe
starting
with #!/usr/bin/env python3
will also be matched.
As with files
and exclude
, you can also exclude types if necessary using
exclude_types
.
正则表达式¶
Regular expressions
模式 files
和 exclude
使用的是 Python 的
正则表达式,
并通过 re.search
进行匹配。
因此,您可以使用 Python 正则表达式支持的任何特性。
如果您发现由于排除/包含的项过多,正则表达式变得复杂,可以考虑使用
详细模式。可以通过 YAML 的多行字面量和
(?x)
正则标志来启用此模式。
# ...
- id: my-hook
exclude: |
(?x)^(
path/to/file1.py|
path/to/file2.py|
path/to/file3.py
)$
The patterns for files
and exclude
are python
regular expressions
and are matched with re.search
.
As such, you can use any of the features that python regexes support.
If you find that your regular expression is becoming unwieldy due to a long
list of excluded / included things, you may find a
verbose regular
expression useful. One can enable this with yaml's multiline literals and
the (?x)
regex flag.
# ...
- id: my-hook
exclude: |
(?x)^(
path/to/file1.py|
path/to/file2.py|
path/to/file3.py
)$
覆盖语言版本¶
Overriding language version
有时您只想在特定版本的语言上运行钩子。对于每种语言,它们默认使用系统安装的语言(例如,如果我正在运行 python3.7
且钩子指定 python
,则 pre-commit 会使用 python3.7
运行钩子)。有时您可能不想使用默认的系统安装版本,可以通过设置 language_version
逐钩子覆盖此设置。
- repo: https://github.com/pre-commit/mirrors-scss-lint
rev: v0.54.0
hooks:
- id: scss-lint
language_version: 2.1.5
这告诉 pre-commit 使用 Ruby 2.1.5
来运行 scss-lint
钩子。
以下是特定语言的有效值:
- python: 使用您系统中安装的任何 Python 解释器。该参数的值作为
-p
传递给virtualenv
。- 在 Windows 上,
pep394 名称将被转换为 py 启动器调用以实现可移植性。因此,即使在 Windows 上,也应继续使用
python3
(py -3
) 或python3.6
(py -3.6
)。
- 在 Windows 上,
pep394 名称将被转换为 py 启动器调用以实现可移植性。因此,即使在 Windows 上,也应继续使用
- node: 参见 nodeenv。
- ruby: 参见 ruby-build。
- 在 2.21.0 中新增 rust:
language_version
被传递给rustup
。 - 在 3.0.0 中新增 golang: 使用 go.dev/dl 上的版本,例如
1.19.5
。
您可以在配置的 顶层 设置 default_language_version
来控制所有钩子的语言默认版本。
default_language_version:
# 强制所有未指定的 Python 钩子运行 python3
python: python3
# 强制所有未指定的 Ruby 钩子运行 Ruby 2.1.5
ruby: 2.1.5
Sometimes you only want to run the hooks on a specific version of the
language. For each language, they default to using the system installed
language (So for example if I’m running python3.7
and a hook specifies
python
, pre-commit will run the hook using python3.7
). Sometimes you
don’t want the default system installed version so you can override this on a
per-hook basis by setting the language_version
.
- repo: https://github.com/pre-commit/mirrors-scss-lint
rev: v0.54.0
hooks:
- id: scss-lint
language_version: 2.1.5
This tells pre-commit to use ruby 2.1.5
to run the scss-lint
hook.
Valid values for specific languages are listed below:
- python: Whatever system installed python interpreters you have. The value of
this argument is passed as the -p
to virtualenv
.
- on windows the
pep394 name will be
translated into a py launcher call for portability. So continue to use
names like python3
(py -3
) or python3.6
(py -3.6
) even on
windows.
- node: See nodeenv.
- ruby: See ruby-build.
- new in 2.21.0 rust: language_version
is passed to rustup
- new in 3.0.0 golang: use the versions on go.dev/dl such as 1.19.5
you can set default_language_version
at the top level in your configuration to
control the default versions across all hooks of a language.
default_language_version:
# force all unspecified python hooks to run python3
python: python3
# force all unspecified ruby hooks to run ruby 2.1.5
ruby: 2.1.5
标记你的存储库¶
badging your repository
您可以在您的仓库中添加一个徽章,向贡献者/用户展示您使用 pre-commit!
- Markdown:
[](https://github.com/pre-commit/pre-commit)
- HTML:
<a href="https://github.com/pre-commit/pre-commit"><img src="https://img.shields.io/badge/pre--commit-enabled-brightgreen?logo=pre-commit" alt="pre-commit" style="max-width:100%;"></a>
- reStructuredText:
.. image:: https://img.shields.io/badge/pre--commit-enabled-brightgreen?logo=pre-commit
:target: https://github.com/pre-commit/pre-commit
:alt: pre-commit
- AsciiDoc:
image:https://img.shields.io/badge/pre--commit-enabled-brightgreen?logo=pre-commit[pre-commit, link=https://github.com/pre-commit/pre-commit]
you can add a badge to your repository to show your contributors / users that you use pre-commit!
- Markdown:
[](https://github.com/pre-commit/pre-commit)
- HTML:
<a href="https://github.com/pre-commit/pre-commit"><img src="https://img.shields.io/badge/pre--commit-enabled-brightgreen?logo=pre-commit" alt="pre-commit" style="max-width:100%;"></a>
- reStructuredText:
.. image:: https://img.shields.io/badge/pre--commit-enabled-brightgreen?logo=pre-commit
:target: https://github.com/pre-commit/pre-commit
:alt: pre-commit
- AsciiDoc:
image:https://img.shields.io/badge/pre--commit-enabled-brightgreen?logo=pre-commit[pre-commit, link=https://github.com/pre-commit/pre-commit]
在持续集成中的使用¶
Usage in continuous integration
pre-commit 还可以作为持续集成的工具。例如,将 pre-commit run --all-files
添加为 CI 步骤可以确保所有内容保持最佳状态。要仅检查已更改的文件(这可能更快),可以使用类似于 pre-commit run --from-ref origin/HEAD --to-ref HEAD
的命令。
pre-commit can also be used as a tool for continuous integration. For
instance, adding pre-commit run --all-files
as a CI step will ensure
everything stays in tip-top shape. To check only files which have changed,
which may be faster, use something like
pre-commit run --from-ref origin/HEAD --to-ref HEAD
管理 CI 缓存¶
Managing CI Caches
默认情况下,pre-commit
将其仓库存储在 ~/.cache/pre-commit
中——这可以通过两种方式进行配置:
PRE_COMMIT_HOME
:如果设置了该环境变量,pre-commit 将使用该位置。XDG_CACHE_HOME
:如果设置了该环境变量,pre-commit 将使用$XDG_CACHE_HOME/pre-commit
,遵循 XDG 基础目录规范。
pre-commit
by default places its repository store in ~/.cache/pre-commit
-- this can be configured in two ways:
PRE_COMMIT_HOME
: if set, pre-commit will use that location instead.XDG_CACHE_HOME
: if set, pre-commit will use$XDG_CACHE_HOME/pre-commit
following the XDG Base Directory Specification.
pre-commit.ci 样例¶
pre-commit.ci example
no additional configuration is needed to run in pre-commit.ci!
pre-commit.ci also has the following benefits:
- it's faster than other free CI solutions
- it will autofix pull requests
- it will periodically autoupdate your configuration
appveyor 样例¶
appveyor example
cache:
- '%USERPROFILE%\.cache\pre-commit'
cache:
- '%USERPROFILE%\.cache\pre-commit'
azure pipelines 样例¶
azure pipelines example
注意:Azure Pipelines 使用不可变缓存,因此 Python 版本和 .pre-commit-config.yaml
哈希必须包含在缓存键中。有关仓库模板,请参见 asottile@job--pre-commit.yml。
jobs:
- job: precommit
# ...
variables:
PRE_COMMIT_HOME: $(Pipeline.Workspace)/pre-commit-cache
steps:
# ...
- script: echo "##vso[task.setvariable variable=PY]$(python -VV)"
- task: CacheBeta@0
inputs:
key: pre-commit | .pre-commit-config.yaml | "$(PY)"
path: $(PRE_COMMIT_HOME)
note: azure pipelines uses immutable caches so the python version and
.pre-commit-config.yaml
hash must be included in the cache key. for a
repository template, see asottile@job--pre-commit.yml.
jobs:
- job: precommit
# ...
variables:
PRE_COMMIT_HOME: $(Pipeline.Workspace)/pre-commit-cache
steps:
# ...
- script: echo "##vso[task.setvariable variable=PY]$(python -VV)"
- task: CacheBeta@0
inputs:
key: pre-commit | .pre-commit-config.yaml | "$(PY)"
path: $(PRE_COMMIT_HOME)
circleci 样例¶
circleci example
像 Azure Pipelines 一样,CircleCI 也使用不可变缓存:
steps:
- run:
command: |
cp .pre-commit-config.yaml pre-commit-cache-key.txt
python --version --version >> pre-commit-cache-key.txt
- restore_cache:
keys:
- v1-pc-cache-{{ checksum "pre-commit-cache-key.txt" }}
# ...
- save_cache:
key: v1-pc-cache-{{ checksum "pre-commit-cache-key.txt" }}
paths:
- ~/.cache/pre-commit
(来源:@chriselion)
like azure pipelines, circleci also uses immutable caches:
steps:
- run:
command: |
cp .pre-commit-config.yaml pre-commit-cache-key.txt
python --version --version >> pre-commit-cache-key.txt
- restore_cache:
keys:
- v1-pc-cache-{{ checksum "pre-commit-cache-key.txt" }}
# ...
- save_cache:
key: v1-pc-cache-{{ checksum "pre-commit-cache-key.txt" }}
paths:
- ~/.cache/pre-commit
(source: @chriselion)
github actions 样例¶
github actions example
与 Azure Pipelines 类似,GitHub Actions 也使用不可变缓存:
- name: set PY
run: echo "PY=$(python -VV | sha256sum | cut -d' ' -f1)" >> $GITHUB_ENV
- uses: actions/cache@v3
with:
path: ~/.cache/pre-commit
key: pre-commit|${{ env.PY }}|${{ hashFiles('.pre-commit-config.yaml') }}
see the official pre-commit github action
like azure pipelines, github actions also uses immutable caches:
- name: set PY
run: echo "PY=$(python -VV | sha256sum | cut -d' ' -f1)" >> $GITHUB_ENV
- uses: actions/cache@v3
with:
path: ~/.cache/pre-commit
key: pre-commit|${{ env.PY }}|${{ hashFiles('.pre-commit-config.yaml') }}
gitlab CI 样例¶
gitlab CI example
查看 GitLab 缓存最佳实践 以优化缓存范围。
my_job:
variables:
PRE_COMMIT_HOME: ${CI_PROJECT_DIR}/.cache/pre-commit
cache:
paths:
- ${PRE_COMMIT_HOME}
pre-commit 的缓存需要在不同构建之间保持在一个固定位置。当在 GitLab 上使用 k8s 运行器时,这并不是默认设置。如果遇到错误 InvalidManifestError
,请在 [[runner]]
配置中将 builds_dir
设置为某个静态值,例如 builds_dir = "/builds"
。
See the Gitlab caching best practices to fine tune the cache scope.
my_job:
variables:
PRE_COMMIT_HOME: ${CI_PROJECT_DIR}/.cache/pre-commit
cache:
paths:
- ${PRE_COMMIT_HOME}
pre-commit's cache requires to be served from a constant location between the different builds. This isn't the default when using k8s runners
on GitLab. In case you face the error InvalidManifestError
, set builds_dir
to something static e.g builds_dir = "/builds"
in your [[runner]]
config
travis-ci 样例¶
travis-ci example
cache:
directories:
- $HOME/.cache/pre-commit
cache:
directories:
- $HOME/.cache/pre-commit
与 tox 一起使用¶
Usage with tox
tox 对于配置测试/CI 工具(如 pre-commit)非常有用。tox>=2
的一个特点是它会清除环境变量,从而使测试更加可重复。在某些情况下,pre-commit 需要一些环境变量,因此必须允许它们通过。
在通过 SSH 克隆仓库时(repo: git@github.com:...
),git
需要 SSH_AUTH_SOCK
变量,否则会失败:
[INFO] 正在为 git@github.com:pre-commit/pre-commit-hooks 初始化环境。
发生意外错误:CalledProcessError: command: ('/usr/bin/git', 'fetch', 'origin', '--tags')
返回代码:128
预期返回代码:0
标准输出:(无)
标准错误:
git@github.com: 权限被拒绝(公钥)。
fatal: 无法从远程仓库读取。
请确保您拥有正确的访问权限
并且仓库存在。
请查看位于 /home/asottile/.cache/pre-commit/pre-commit.log 的日志。
在您的 tox 测试环境中添加以下内容:
[testenv]
passenv = SSH_AUTH_SOCK
同样,在通过 HTTP/HTTPS 克隆仓库时(repo: https://github.com:...
),您可能在公司 HTTP(S) 代理服务器后面,此时 git
需要设置 http_proxy
、https_proxy
和 no_proxy
变量,否则克隆可能会失败:
[testenv]
passenv = http_proxy https_proxy no_proxy
tox is useful for configuring test / CI tools
such as pre-commit. One feature of tox>=2
is it will clear environment
variables such that tests are more reproducible. Under some conditions,
pre-commit requires a few environment variables and so they must be
allowed to be passed through.
When cloning repos over ssh (repo: git@github.com:...
), git
requires the
SSH_AUTH_SOCK
variable and will otherwise fail:
[INFO] Initializing environment for git@github.com:pre-commit/pre-commit-hooks.
An unexpected error has occurred: CalledProcessError: command: ('/usr/bin/git', 'fetch', 'origin', '--tags')
return code: 128
expected return code: 0
stdout: (none)
stderr:
git@github.com: Permission denied (publickey).
fatal: Could not read from remote repository.
Please make sure you have the correct access rights
and the repository exists.
Check the log at /home/asottile/.cache/pre-commit/pre-commit.log
Add the following to your tox testenv:
[testenv]
passenv = SSH_AUTH_SOCK
Likewise, when cloning repos over http / https
(repo: https://github.com:...
), you might be working behind a corporate
http(s) proxy server, in which case git
requires the http_proxy
,
https_proxy
and no_proxy
variables to be set, or the clone may fail:
[testenv]
passenv = http_proxy https_proxy no_proxy
使用存储库的最新版本¶
Using the latest version for a repository
pre-commit
配置旨在提供可重复和快速的体验,因此故意不为钩子仓库提供“未锁定的最新版本”功能。
相反,pre-commit
提供工具,使您能够轻松升级到最新版本,使用 pre-commit autoupdate
。如果您需要钩子的绝对最新版本(而不是最新的标签版本),请将 --bleeding-edge
参数传递给 autoupdate
。
pre-commit
假设 rev
的值是不可变的引用(如标签或 SHA),并将基于此进行缓存。不支持将分支名称(或 HEAD
)用作 rev
的值,这仅表示在钩子安装时该可变引用的状态(并且 不会 自动更新)。
pre-commit
configuration aims to give a repeatable and fast experience and
therefore intentionally doesn't provide facilities for "unpinned latest
version" for hook repositories.
Instead, pre-commit
provides tools to make it easy to upgrade to the
latest versions with pre-commit autoupdate
. If
you need the absolute latest version of a hook (instead of the latest tagged
version), pass the --bleeding-edge
parameter to autoupdate
.
pre-commit
assumes that the value of rev
is an immutable ref (such as a
tag or SHA) and will cache based on that. Using a branch name (or HEAD
) for
the value of rev
is not supported and will only represent the state of
that mutable ref at the time of hook installation (and will NOT update
automatically).
创建日期: 2024年9月24日