Back

使用 Git Pre-Commit Hook 自动化代码检查

使用 Git Pre-Commit Hook 自动化代码检查

每个开发者都经历过这样的挫折:推送代码后,CI/CD 流水线因为格式问题或 linting 错误而失败。如果你能在这些问题到达代码仓库之前就发现它们会怎样?Git pre-commit hook 提供了一个强大的解决方案,它在本地运行自动化检查,既节省时间又保持团队代码质量的一致性。

本文将指导你使用 pre-commit 框架设置 git pre-commit hook,配置 ESLint、Prettier 和 Black 等重要工具,并实施最佳实践来保持开发工作流程的顺畅和高效。

核心要点

  • Git pre-commit hook 在提交前运行自动化检查,防止常见问题进入代码仓库
  • pre-commit 框架通过 YAML 配置和跨语言支持简化了 hook 管理
  • 速度优化和渐进式采用对团队接受度至关重要
  • Husky 和 Lefthook 等替代工具为特定需求提供了不同的方法

什么是 Git Pre-Commit Hook?

Git hook 是 Git 在提交、推送和接收等事件之前或之后执行的脚本。git pre-commit hook 特指在你暂存更改之后但在 Git 创建提交之前运行的脚本。如果 hook 以非零状态退出,Git 会中止提交,让你有机会先修复问题。

虽然你可以在 .git/hooks/ 中编写简单的 shell 脚本作为 hook,但随着项目的增长,管理它们会变得复杂。这就是 pre-commit 框架 的优势所在——它提供了一种标准化的方式来管理和在团队间共享 hook。

为什么使用 Pre-Commit 框架?

pre-commit 框架解决了原生 Git hook 的几个痛点:

  • 简化安装和更新:Hook 有版本控制,通过简单的 YAML 配置安装
  • 跨语言支持:从一个配置文件运行 Python linter、JavaScript 格式化工具和 shell 脚本
  • 选择性执行:Hook 只在更改的文件上运行,保持提交速度
  • 团队一致性:在整个团队中共享相同的 .pre-commit-config.yaml 文件

在项目中设置 Pre-Commit

首先,安装 pre-commit 包:

pip install pre-commit

在项目根目录创建 .pre-commit-config.yaml 文件。以下是一个涵盖常见需求的实用配置:

repos:
  # 基础文件修复
  - repo: https://github.com/pre-commit/pre-commit-hooks
    rev: v4.5.0
    hooks:
      - id: trailing-whitespace
      - id: end-of-file-fixer
      - id: check-yaml
      - id: check-added-large-files

  # 使用 Black 进行 Python 格式化
  - repo: https://github.com/psf/black
    rev: 24.2.0
    hooks:
      - id: black
        files: \.py$

  # 使用 Mypy 进行 Python 类型检查
  - repo: https://github.com/pre-commit/mirrors-mypy
    rev: v1.8.0
    hooks:
      - id: mypy
        additional_dependencies: [types-all]
        files: \.py$

  # 使用 Prettier 处理 JavaScript/TypeScript
  - repo: https://github.com/pre-commit/mirrors-prettier
    rev: v3.1.0
    hooks:
      - id: prettier
        files: \.(js|jsx|ts|tsx|json|css|md)$

  # 使用 ESLint 进行 JavaScript/TypeScript 代码检查
  - repo: https://github.com/pre-commit/mirrors-eslint
    rev: v8.56.0
    hooks:
      - id: eslint
        files: \.(js|jsx|ts|tsx)$
        additional_dependencies:
          - eslint-config-standard
          - eslint-plugin-react

  # 运行项目测试
  - repo: local
    hooks:
      - id: pytest
        name: pytest
        entry: pytest
        language: system
        pass_filenames: false
        always_run: true

安装 git hook:

pre-commit install

现在你的 hook 将在每次提交时自动运行。要在所有文件上手动运行它们:

pre-commit run --all-files

优化 Hook 性能

速度很重要——缓慢的 hook 会阻碍开发者频繁提交。遵循以下实践:

仅在暂存文件上运行 hook:pre-commit 框架默认这样做,但要确保你的自定义 hook 遵循这个模式。

使用快速工具:在速度至关重要时,选择 Ruff 而不是 Flake8 处理 Python,或选择 Biome 而不是 ESLint 处理 JavaScript。

在本地跳过昂贵的检查:将全面的测试套件保留给 CI/CD。本地 hook 应专注于格式化和基础 linting 等快速收益。

尽可能并行化:一些工具支持并行执行。例如,pytest 可以使用 pytest-xdist 并行运行测试。

团队采用最佳实践

让团队采用 pre-commit hook 需要周到的实施:

从小处开始:从去除尾随空格等非侵入性 hook 开始。逐步添加更严格的检查。

记录设置过程:在 README 中包含安装说明。将其作为入职流程的一部分。

处理环境差异:尽可能使用与语言无关的 hook。对于特定语言的工具,确保你的 .pre-commit-config.yaml 指定兼容版本。

提供逃生通道:有时开发者需要绕过 hook。--no-verify 标志跳过所有 hook:

git commit --no-verify -m "Emergency fix"

谨慎使用这个功能,并记录何时适合使用。

替代方案

虽然 pre-commit 是最受欢迎的框架,但也存在替代方案:

Husky:在 JavaScript 项目中很受欢迎,与 npm 脚本集成良好。

原生 Git hook.git/hooks/ 中的直接 shell 脚本提供最大控制权,但缺乏可移植性。

Lefthook:快速、跨平台的替代方案,支持并行执行。

对于大多数团队,pre-commit 在功能、性能和生态系统支持方面提供了最佳平衡。

常见陷阱和解决方案

CI 上的 Hook 失败:确保 CI 环境安装了所有必要的依赖项。考虑将 pre-commit run --all-files 作为 CI 步骤运行。

平台特定问题:在团队使用的所有平台上测试 hook。如果需要,使用 Docker 创建一致的环境。

配置文件中的合并冲突:保持 .pre-commit-config.yaml 更改最小化和原子化。在单独的提交中更新 hook 版本。

结论

Git pre-commit hook 将代码质量从被动过程转变为主动过程。通过在问题进入代码仓库之前捕获它们,你节省了时间,减少了上下文切换,并在代码库中保持了更高的标准。从基础格式化 hook 开始,逐步添加 linter 和类型检查器,并始终优先考虑速度以保持团队工作流程的顺畅。

成功采用的关键在于平衡彻底性与开发者体验。快速、专注的 hook 提供即时价值,将成为团队工作流程中不可或缺的一部分。

常见问题

可以,pre-commit 在 monorepo 中表现出色。你可以为不同的文件模式和目录配置不同的 hook。在配置中使用 files 和 exclude 键来针对仓库中的特定语言或文件夹。

将 nvm 或 pyenv 等语言版本管理器与 pre-commit 一起使用。或者,在 hook 配置中指定 language_version,或使用基于 Docker 的 hook 来确保所有开发者机器上的环境一致。

没有安装 pre-commit 时,hook 不会在本地运行,但你的代码仍会提交。为了强制执行标准,在 CI 流水线中运行 pre-commit 检查作为安全网,并将 pre-commit 安装作为项目设置文档的一部分。

Gain control over your UX

See how users are using your site as if you were sitting next to them, learn and iterate faster with OpenReplay. — the open-source session replay tool for developers. Self-host it in minutes, and have complete control over your customer data. Check our GitHub repo and join the thousands of developers in our community.

OpenReplay