原文:towardsdatascience.com/pre-commit-git-hooks-automate-high-code-quality-fbcbaa720e52

什么是 Pre-Commit?

Pre-commit 是一个 Python 包,它使得创建 pre-commit 钩子变得非常简单。钩子是 git 的原生功能,是一些在执行特定 git 命令之前运行的脚本。

你可以在你的仓库的 .git/hooks 目录中找到钩子,这个目录是由 git 自动填充的。如果你查看这个目录,你会找到类似这样的文件:

applypatch-msg.sample     pre-commit.sample         prepare-commit-msg.sample
commit-msg.sample         pre-merge-commit.sample   push-to-checkout.sample
fsmonitor-watchman.sample pre-push.sample           update.sample
post-update.sample        pre-rebase.sample
pre-applypatch.sample     pre-receive.sample

.sample 扩展名阻止这些钩子执行。要启用钩子,请删除 .sample 扩展名并编辑文件。

然而,这很繁琐,并且不太用户友好,而且难以通过版本控制来管理。这就是 pre-commit 发挥作用的地方。它为 commit 命令创建一个钩子,以自动检测代码中的任何问题,并使创建脚本变得无缝。

它创建了一个配置文件,在调用 git commit 命令时执行。如果配置文件中的任何检查失败,则提交将被中止。这确保了代码库始终具有质量和一致性。

更多信息请见下文关于 git 钩子。

Git – Git Hooks

为什么对数据科学来说很重要?

如果你是一名数据科学家,可能会想知道为什么你需要学习 git 钩子。嗯,社区内部有一个转变,那就是熟练的软件工程变得越来越重要,能够将你自己的模型部署到生产中是非常有价值的。

在保持良好代码质量的同时确保机器学习模型稳健部署的一种技术是使用 git 钩子和 pre-commit。机器学习模型很复杂,所以你能做的任何自动化工作流程和捕捉潜在错误,在模型达到生产状态之前,都是理想的。

要了解更多关于全栈数据科学的信息,请查看这两篇文章 [这里](https://medium.com/towards-data-science/the-predictable-rise-of-full-stack-data-science-8862dad32eb0?sk=v2%2F4f8df975-d03d-4159-9e10-a5562c3d5de0) 和这里。

使用方法

安装

安装 pre-commit 非常简单,与使用 pip 安装任何其他 Python 库相同。我个人使用 Poetry,但它们中的任何一个都可以正常工作。

pip install pre-commit # pip 
poetry add pre-commit # I personally use poetry

你可以通过运行以下命令来确认其已安装。

pre-commit --version

配置文件

导航到你的仓库根目录,并在你的项目中创建一个 .pre-commit-config.yaml 文件。你可以通过运行以下命令来完成此操作:

touch .pre-commit-config.yaml 

此文件将定义在提交代码之前你想运行的内容。一个例子如下:

repos:
-   repo: https://github.com/pre-commit/pre-commit-hooks
    rev: v2.3.0
    hooks:
    -   id: check-yaml
    -   id: end-of-file-fixer
    -   id: trailing-whitespace

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

- repo: https://github.com/PyCQA/flake8
  rev: v6.0.0 
  hooks:
    - id: flake8
      additional_dependencies: [flake8-docstrings, flake8-import-order]
      args: ['--max-line-length=88']

这里发生的事情是repos指示了一个包含我们想要运行的钩子的仓库列表。第一个是pre-commit-hooks仓库,其中包含钩子:

  • id: check-yaml

  • id: end-of-file-fixer

  • id: trailing-whitespace

在这种情况下,id是您想要从仓库中运行的特定且唯一的预提交钩子的标识符。

我们然后按照相同的流程处理blackflake8包。

想了解更多关于代码质量和格式化工具的信息,请查看我之前的文章

数据科学家提高 Python 代码质量的指南

执行

在定义您的文件后,您需要运行pre-commit install来让 pre-commit 知道您想要使用指定的脚本为此仓库使用 pre-commit。

然后,进行代码更改并尝试提交您的代码。您应该会看到 pre-commit 钩子正在工作。

您也可以通过运行以下命令来查看您的pre-commit正在做什么:pre-commit run --all-files

如果您想在运行钩子之前提交代码,可以使用git commit --no-verify来绕过它。

好的,现在让我们通过一个例子来了解一下!

示例

我在我的Medium-Articles仓库上安装了 pre-commit,我们将使用它来展示一个例子。

在我的仓库中,我有以下 Makefile。

SHELL=/bin/bash

PHONY: install
install:
    poetry install

PHONY: lint
lint:
    poetry run black .
    poetry run isort .

我的两个命令是installlint,用于设置我的环境并确保我的代码看起来很漂亮。

如果您不熟悉 Makefile,请查看我之前关于它们的帖子

Makefile 教程

我的.pre-commit-config.yaml看起来像这样,这与我之前展示的模板略有不同。

repos:
  - repo: local
    hooks:
      - id: lint
        name: lint
        entry: make lint
        language: python
        types: [python]
        stages: [commit]

在这种情况下,钩子所在的仓库是本地的,即在我的项目中。这个钩子将使用entry命令,并在 make 文件中定义的钩子部分执行make lint命令。

我的一个文件看起来像这样(relu.py):

# Import packages
import numpy as np
import os
import plotly.express as px

# relu function
def relu(x):
    return np.maximum(0, x)

# Generate data
x = np.linspace(-5, 5, 100)
y = relu(x)

# Graph
fig = px.line(x=x, y=y)
fig.update_layout(template="simple_white", font=dict(size=18), title_text="ReLU", width=650, title_x=0.5, height=400,)

if not os.path.exists("../images"):
    os.mkdir("../images")
fig.write_image("../images/relu.png")

fig.show()

现在我们尝试提交这段代码,看看会发生什么。

(medium-articles-py3.11) egorhowell@Egors-MBP Medium-Articles % git add .
(medium-articles-py3.11) egorhowell@Egors-MBP Medium-Articles % git commit -m "testing pre-commit"
[INFO] Initializing environment for local.
[INFO] Installing environment for local.
[INFO] Once installed this environment will be reused.
[INFO] This may take a few minutes...
lint.....................................................................Failed
- hook id: lint
- files were modified by this hook

poetry run black .
Skipping .ipynb files as Jupyter dependencies are not installed.
You can fix this by running ``pip install "black[jupyter]"``
reformatted /Users/egorhowell/Repos/Medium-Articles/Data Science Basics/relu.py
reformatted /Users/egorhowell/Repos/Medium-Articles/Time Series/Exponential Smoothing/holt_winters.py

All done! ✨ 🍰  ✨
2 files reformatted, 67 files left unchanged.
poetry run isort .
Fixing /Users/egorhowell/Repos/Medium-Articles/Time Series/Exponential Smoothing/holt_winters.py
Skipped 2 files
make: Nothing to be done for `Data Science Basics/relu.py'.

钩子失败了,因为它重新格式化了relu.py。现在它看起来像:

# Import packages
import os

import numpy as np
import plotly.express as px

# relu function
def relu(x):
    return np.maximum(0, x)

# Generate data
x = np.linspace(-5, 5, 100)
y = relu(x)

# Graph
fig = px.line(x=x, y=y)
fig.update_layout(
    template="simple_white",
    font=dict(size=18),
    title_text="ReLU",
    width=650,
    title_x=0.5,
    height=400,
)

if not os.path.exists("../images"):
    os.mkdir("../images")
fig.write_image("../images/relu.png")

fig.show()

所以,我们的预提交钩子成功工作了!

下面是一些更多的预提交钩子示例。

GitHub – pre-commit/pre-commit-hooks: 预提交的一些开箱即用的钩子

摘要 & 进一步思考

Pre-commit 是一个有用的 Python 包,它改进了您的 git 钩子工作流程,简化了您的脚本。它旨在通过自动化您的代码检查过程来保持您软件的质量并消除 bug 的风险。作为数据科学家,我们越来越多地参与到模型部署中,使用像 git hooks 和 pre-commit 这样的技术来确保我们的模型安全地达到生产环境。

另一件事!

我有一个免费的通讯简报,分享数据,在这里我作为实践中的数据科学家分享每周的技巧和建议。此外,当你订阅时,你将获得我的免费数据科学简历,并学习 AI 路线图**!!

分享数据 | Egor Howell | Substack

与我建立联系!

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐