文章目录
引言
在软件开发过程中,保持代码的一致性和高质量是非常重要的。
pre-commit
是一个强大的工具,它可以帮助我们在提交代码到版本控制系统(如 Git)之前自动运行一系列的代码检查和格式化操作。通过这种方式,我们可以确保每次提交的代码都是干净的、格式化的并且符合项目的编码标准。
本文将详细介绍
pre-commit
的工作原理、如何安装
pre-commit
,如何配置它,并提供一些实用的示例。
什么是 Hook?
在版本控制系统中,hook 是一种脚本,用于在某些事件发生时触发。例如,在 Git 中,你可以设置一个 hook 在提交前运行。
pre-commit
利用了 Git 的这一特性,允许用户定义一组钩子(hook),这些钩子会在提交之前自动执行。
Hook 的类型
pre-commit
支持以下几种类型的 hook:
- pre-commit:这是最常用的一种 hook,它会在提交之前运行。
- pre-push:这种 hook 会在 push 操作之前运行。
- post-merge:这种 hook 会在合并分支之后运行。
- prepare-commit-msg:这种 hook 会在创建提交信息时运行。
本文主要关注
pre-commit
类型的 hook。
安装
在开始之前,请确保环境中已经安装了 Python 和 Git。通过以下命令安装
pre-commit
:
pip install pre-commit
配置
一旦安装完成,接下来就是配置
pre-commit
的过程。
首先,在你的项目根目录下创建一个
.pre-commit-config.yaml
文件。
这个文件定义了你的
pre-commit
钩子的行为。
示例配置文件
下面是一个简单的
.pre-commit-config.yaml
文件示例,它包含了几个常用的钩子:
repos:-repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.4.0
hooks:-id: trailing-whitespace
-id: end-of-file-fixer
-id: check-yaml
-id: debug-statements
-repo: https://github.com/psf/black
rev: stable
hooks:-id: black
-repo: https://github.com/pycqa/flake8
rev: 6.0.0
hooks:-id: flake8
这里,我们定义了四个来自
pre-commit-hooks
仓库的钩子,以及两个分别来自
black
和
flake8
的钩子。这些钩子的功能分别是:
- trailing-whitespace: 移除行尾的空白字符。
- end-of-file-fixer: 确保文件以单个新行结束。
- check-yaml: 检查 YAML 文件的格式是否正确。
- debug-statements: 检查 Python 代码中的调试语句(如
print
)。 - black: 自动格式化 Python 代码。
- flake8: 进行 Python 代码的静态分析和格式检查。
选择 Hook
选择合适的 hook 来满足对应的项目需求
- 编程语言规范:选择与项目编程语言兼容的 hook。例如,对于 Python 项目,可以选择
black
或flake8
。 - 编码标准:选择符合项目编码标准的 hook。例如,如果项目使用 PEP 8 编码标准,可以使用
flake8
。 - 自动化需求:选择能够自动修复常见错误的 hook。例如,
end-of-file-fixer
可以自动添加缺失的新行。
限制 Hook 的作用范围
你可以通过以下方式限制 hook 的作用范围:
- **使用
types
**:限制 hook 应用于特定类型的文件。例如,只对.py
文件应用black
:-repo: https://github.com/psf/black rev: stable hooks:-id: black types:[python]
- **使用
exclude
**:排除特定的文件或目录。例如,不检查.venv
目录下的文件:-repo: https://github.com/pre-commit/pre-commit-hooks rev: v4.4.0 hooks:-id: trailing-whitespace exclude: ^\.venv/
- **使用
files
**:只检查匹配正则表达式的文件。例如,只检查以test_
开头的 Python 文件:-repo: https://github.com/psf/black rev: stable hooks:-id: black files: ^test_.*\.py$
安装钩子
创建完配置文件后,需要安装这些钩子才能让它们生效。在项目根目录下运行以下命令:
pre-commit install
这将在你的
.git/hooks
目录下生成一个可执行的
pre-commit
脚本。
如果之后有修改,不需要再次安装,会自动采用最新的yaml或者自定义hooks来运行。
使用 pre-commit
现在当你尝试提交更改时,
pre-commit
将自动运行配置好的钩子。如果任何钩子失败,则提交会被阻止,并显示错误信息。
如果你想要手动运行所有的钩子,可以使用以下命令:
pre-commit run --all-files
如果你只想运行特定的一个钩子,可以这样做:
pre-commit run black --files path/to/file.py
自定义 Hook
除了使用已有的 hook 之外,
pre-commit
还允许你定义自己的 hook。例如,假设你有一个 Python 脚本
my_custom_hook.py
,它可以检查文件中的特定模式:
# my_custom_hook.pyimport sys
import re
defmain():
pattern =r'pattern_to_search'for filename in sys.argv[1:]:withopen(filename,'r')asfile:ifany(re.search(pattern, line)for line infile):print(f"Found pattern in {filename}")return1return0if __name__ =='__main__':
sys.exit(main())
然后,你可以在
.pre-commit-config.yaml
文件中添加这个自定义钩子:
repos:-repo: local
hooks:-id: custom-pattern-check
name: Custom pattern check
entry: python my_custom_hook.py
language: system
files: \.py$
使用了
local
作为 repo,因为这个钩子是直接在项目中定义的。
Eg:commit消息规范
希望每一次commit的message是符合一定的规则的,首先创建一个自定义的hook,写一个python脚本
# commit_message_validator.pyimport sys
import re
defvalidate_commit_message(message):# 第一行以大写字母开头ifnot message.startswith(tuple('ABCDEFGHIJKLMNOPQRSTUVWXYZ')):print("Error: Commit message must start with a capital letter.")returnFalse# 第一行不能超过 50 个字符iflen(message.split('\n')[0])>50:print("Error: The first line must not exceed 50 characters.")returnFalse# 检查是否包含关键字
valid_types =['feat','fix','docs','style','refactor','perf','test','chore','ci','build','revert']
type_pattern = re.compile(r'^('+'|'.join(valid_types)+')')ifnot type_pattern.match(message.split(':')[0].split(' ')[0]):print("Error: Commit message should start with one of the following keywords: ",', '.join(valid_types))returnFalsereturnTrueif __name__ =="__main__":
message = sys.stdin.read().strip()ifnot validate_commit_message(message):
sys.exit(1)
将该自定义的hook写入到yaml文件中
.pre-commit-config.yaml
repos:-repo: local
hooks:-id: commit-message-validator
name: Validate commit messages
entry: python commit_message_validator.py
language: system
files:''stages:[commit-msg]
stages: [commit-msg]
,告诉
pre-commit
这个 hook 应该在
commit-msg
阶段运行,即在提交消息被创建之后,但实际提交还没有发生之前
最后就是安装这一个hook
pre-commit install --hook-type commit-msg
结论
使用
pre-commit
,可以确保每次提交的代码都是高质量的。这也就可以帮助我们避免常见的编码错误,还可以提高团队成员之间的协作效率。
无论你是个人开发者还是团队的一员,
pre-commit
都是一个值得使用的工具。
笔者记录pre-commit的一大原因也是希望能够在笔记本仓库中,规范每次commit message的内容,让commit message起到一个更好的摘要作用。
版权归原作者 One_Danzel♂ 所有, 如有侵权,请联系我们删除。