git-pre-commit-hook:让代码质量检查自动化起来

276 阅读9分钟

引言:为什么我们需要代码提交前的「安全检查」?

作为开发者,你有没有遇到过这些情况?

  • 不小心把调试代码提交到了远程仓库
  • 代码格式混乱导致团队协作出现分歧
  • 因为一个简单的语法错误,CI/CD 流水线反复失败
  • 甚至无意中把敏感信息(如密钥)推送到了公开仓库

这些看似小问题,却常常浪费团队大量时间和精力。今天我们要聊的 pre-commit 工具,就是解决这些问题的「代码提交守门员」。

一、pre-commit 是什么?它如何保护你的代码质量?

理解 pre-commit 的核心概念

pre-commit 是一个 Git 钩子管理工具,它能在你执行 git commit 命令时,自动运行一系列检查脚本,只有通过这些检查,代码才能被成功提交。

简单来说,它就像是你代码提交前的一道「安检门」,帮助你在代码进入版本控制系统前就发现并解决潜在问题。

pre-commit 的工作原理

它利用 Git 的 pre-commit 钩子机制,在代码提交前拦截操作,运行配置好的检查项(如代码格式化、语法检查、静态分析等),帮助开发者在本地就发现并解决问题。

具体流程是这样的:

  1. 你执行 git commit 命令
  2. pre-commit 钩子被触发
  3. pre-commit 工具运行你配置的所有检查项
  4. 如果所有检查都通过,commit 操作继续执行
  5. 如果有任何检查失败,commit 操作被中止,你需要修复问题后重新提交

使用 pre-commit 的三大好处

  • 提前发现问题:在代码进入远程仓库前就解决大多数质量问题,避免把问题带入后续流程
  • 统一团队规范:确保所有提交的代码都符合团队约定的标准,减少代码审查时关于格式的讨论
  • 减少 CI/CD 失败:避免因低级错误导致的流水线反复构建,提高开发效率

二、如何在 Windows 下快速上手 pre-commit?

安装 pre-commit(Windows 版本)

在 Windows 系统上安装 pre-commit 非常简单,只需要几个步骤:

  1. 确保已安装 Python pre-commit 是一个 Python 工具,所以首先需要确保你的系统上已经安装了 Python。你可以通过在命令提示符(CMD)或 PowerShell 中运行以下命令来检查:

python --version

如果没有安装 Python,可以访问 Python 官方网站 下载最新版本的安装包,并在安装时勾选「Add Python to PATH」选项。

  1. 使用 pip 安装 pre-commit 打开命令提示符(CMD)或 PowerShell,运行以下命令:

pip install pre-commit

  1. 验证安装是否成功 安装完成后,运行以下命令来验证:

pre-commit --version

如果能看到版本号信息,说明 pre-commit 已经成功安装。

创建并配置 pre-commit 配置文件

  1. 初始化 pre-commit 进入你的 Git 项目目录,在命令提示符或 PowerShell 中运行:

pre-commit install

这个命令会在你的项目的 .git/hooks 目录下创建 pre-commit 钩子脚本。

  1. 创建配置文件 在项目根目录下创建一个名为 .pre-commit-config.yaml 的文件。这是 pre-commit 的核心配置文件,用于定义要运行的检查项。

一个简单的配置文件示例:


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: check-added-large-files

  1. 理解配置文件结构
  • repos:包含一个或多个 Git 仓库,这些仓库提供 pre-commit 钩子
  • repo:钩子仓库的 URL
  • rev:要使用的钩子仓库版本
  • hooks:要使用的钩子列表
  • id:钩子的唯一标识符

常用的 pre-commit 钩子推荐

以下是一些在日常开发中非常实用的 pre-commit 钩子:

通用检查类

  • trailing-whitespace:删除行尾的空白字符
  • end-of-file-fixer:确保文件以换行符结尾
  • check-yaml:检查 YAML 文件的语法是否正确
  • check-added-large-files:避免意外将大文件引入到仓库

代码格式化类

black:自动格式化 Python 代码,确保代码风格一致

black 是一个 Python 代码格式化工具,它的主要功能是自动格式化 Python 代码,确保代码风格一致。 注意black只能修复代码中的格式问题,不能修复代码中的语法错误。

安装依赖:


pip install black==23.3.0

pre-commit 配置如下:


-   repo: https://github.com/psf/black
    rev: 23.3.0
    hooks:
    -   id: black

isort:自动排序 Python 导入语句

isort 用于自动排序和格式化 Python 文件中的导入语句。它的主要功能包括:

  1. 分类导入:自动将导入分为三类
    • 标准库导入
    • 第三方库导入
    • 本地模块导入
  2. 字母排序 :在每个类别内按字母顺序排序导入
  3. 格式化 :处理导入的格式,如合并相同模块的导入

安装依赖:


pip install isort==5.12.0

运行isort:


# 检查并修改导入语句

isort HelloWorld.py
# 检查但不修改

isort --check HelloWorld.py

pre-commit 配置如下:


- repo: https://github.com/pycqa/isort
  rev: 5.12.0
  hooks:
  - id: isort

语法检查类

flake8:检查 Python 代码中的语法错误和风格问题

flake8 主要是一个代码质量检查工具,它的核心功能是检测代码中的语法错误、编码规范问题、潜在的逻辑问题和代码质量问题,但不提供自动修复这些问题的能力。 注意:

  1. 若有语法错误,flake8 会报告错误位置和类型,并停止后续检测,因此报告语法错误时可能还有其他未检测到的问题。
  2. 如果风格问题已经被black修复,flake8就不会再报告这些问题了,因此推荐将black和flake8结合使用,使用时要注意先后顺序。

安装依赖:


pip install flake8==6.0.0

检测语法和代码风格:


# 检测 flake8_test.py 中的语法错误和风格问题

flake8 flake8_test.py

# --show-source 显示错误的代码位置

flake8 --show-source flake8_test.py

pre-commit 配置如下:


- repo: https://github.com/pycqa/flake8
  rev: 6.0.0
  hooks:
  -   id: flake8

安全检查类

detect-secrets:检测代码中是否包含敏感信息(如 API 密钥、密码等)

detect-secrets 是 Yelp 开发的一个工具,用于扫描代码仓库中可能包含的敏感信息,如 API 密钥、密码、证书等。它使用多种启发式规则来识别潜在的敏感信息,并可以帮助团队避免将敏感信息意外提交到代码仓库中。

注意:它不是 100% 准确的,可能会产生误报或漏报,因此仍然需要人工审查。

安装依赖:


pip install detect-secrets==1.5.0

检测敏感信息:


detect-secrets scan

当运行 pre-commit run detect-secrets --all-files 时,如果检测到大量敏感信息(尤其是在 lock 文件中),这是正常现象,因为这些文件通常包含许多看起来像敏感信息的高熵字符串。 解决方法:

  • 跳过 lock 文件
  • 添加基线文件

跳过 lock 文件

  • 可以使用 --exclude-files 参数来排除特定文件

detect-secrets scan --exclude-files "package-lock.json|pnpm-lock.yaml|yarn.lock"

  • 在 .pre-commit-config.yaml 中有两种方式:
    • 添加排除规则,跳过 lock 文件
    • 使用--exclude-files参数来排除特定文件

- repo: https://github.com/Yelp/detect-secrets
  rev: v1.5.0
  hooks:
    - id: detect-secrets
      # 跳过lock文件,因为它们通常包含大量看起来像敏感信息的高熵字符串
      exclude: |
        (?x)^(
          package-lock.json|
          pnpm-lock.yaml|
          yarn.lock
        )$
      # 也可以使用--exclude-files参数来排除特定文件
      args: [--exclude-files, "package-lock.json|pnpm-lock.yaml|yarn.lock"]

添加基线文件

  1. 初始化基线文件(baseline),记录当前已知的敏感信息,这样后续的检查只会关注新添加的敏感信息:

# 扫描当前目录下所有被Git跟踪的文件

detect-secrets scan > .secrets.baseline
# 扫描当前目录下 所有文件 ,包括未被Git跟踪的文件

detect-secrets scan --all > .secrets.baseline

  1. 将当前代码状态与已有的基线文件进行比较,检测是否引入了新的敏感信息:

detect-secrets scan --baseline .secrets.baseline

  1. .pre-commit-config.yaml中为detect-secrets钩子添加参数,指定使用这个 baseline 文件:

- repo: https://github.com/Yelp/detect-secrets
  rev: v1.5.0
  hooks:
    - id: detect-secrets
      args: [--baseline, .secrets.baseline]

这样,pre-commit 就只会报告 baseline 文件中未记录的新敏感信息,避免每次运行都报告大量已知的误报,不仅仅是 lock 文件,其他已知的敏感信息也会过滤不再报告。

三、pre-commit 的进阶技巧与最佳实践

在团队中推广 pre-commit

当你在个人项目中尝到 pre-commit 的甜头后,可能会想要在团队中推广它。以下是一些实用的推广技巧:

  1. 在项目 README 中添加 pre-commit 安装指南,确保新成员能够快速上手

  2. 将 pre-commit 配置纳入版本控制,确保团队成员使用相同的配置

  3. 在 CI/CD 流程中强制执行 pre-commit 检查,可以使用 pre-commit run --all-files 命令

  4. 定期更新钩子版本,以获取最新的功能和修复

开发自定义 pre-commit 钩子

当现成的钩子不能满足你的特定需求时,你可以开发自己的 pre-commit 钩子。以下是创建自定义钩子的基本步骤:

  1. 创建一个简单的脚本,该脚本将执行你想要的检查逻辑

  2. 确保脚本具有执行权限(在 Windows 上这一步通常不是必需的)

  3. .pre-commit-config.yaml 中添加自定义钩子:

    -   repo: local
        hooks:
        -   id: my-custom-hook
            name: My Custom Hook
            entry: path/to/your/script.py
            language: python
            types: [python]
    

与 CI/CD 流程结合

为了确保代码质量,最好在 CI/CD 流程中也运行 pre-commit 检查。这样可以避免有人绕过本地检查直接提交代码。

在 CI/CD 配置文件中,你可以添加类似以下的步骤:


jobs:
  lint:
    runs-on: windows-latest
    steps:
      - uses: actions/checkout@v3
      - name: Set up Python
        uses: actions/setup-python@v4
        with:
          python-version: '3.10'
      - name: Install pre-commit
        run: pip install pre-commit
      - name: Run pre-commit checks
        run: pre-commit run --all-files

结论:让 pre-commit 成为你的代码质量「第一道防线」

pre-commit 不是一个复杂的工具,但它能为你的项目带来显著的质量提升。通过在代码提交前就解决掉大多数常见问题,你和你的团队可以把更多精力放在真正重要的功能开发上。

无论是个人项目还是大型团队协作,pre-commit 都值得尝试——它可能不会解决所有代码质量问题,但绝对能帮你避免大多数低级错误。

现在就给你的项目加上这道「安全门」吧!打开命令提示符或 PowerShell,按照本文的指南安装 pre-commit,让你的代码提交更有保障。