不喜欢广告? 无广告 今天

Git 事件钩子 提交前、推送前以及在大门处阻止不良代码

更新于

预提交、提交信息和预推送钩子是shell脚本,会在git写入提交或发送推送之前运行。以下是将它们配置为捕获代码检查失败、不良的提交信息和泄露的密钥的详细方法——附有您可以立即使用的实际示例。

pre-commit、commit-msg 和 pre-push 钩子是运行在 Git 写入提交或推送之前的一系列 Shell 脚本。以下是配置它们以拦截 lint 失败、不良提交信息和泄露密钥的方法——附有你可以立即使用的实际示例。
广告 移除?

Git 内置了钩子——在工作流程中的特定阶段触发的 Shell 脚本。大多数仓库都拥有这些脚本,但它们处于休眠状态。 .git/hooks/ 作为 .sample 文件。大多数开发者都忽视它们,直到出现错误提交或泄露的 API 密钥,才后悔当初没有关注。

本文涵盖每个项目中值得配置的三个钩子: pre-commit, commit-msg,并且 pre-push。每个钩子都能拦截一类错误。每个钩子都是一个你可以立即使用的 Shell 脚本。

钩子的位置

每个 Git 仓库都有一个 .git/hooks/ 目录。运行 ls .git/hooks/ 后,你会看到示例文件。Git 忽略所有以 .sample 结尾的文件。要激活一个钩子,请移除该后缀并使其可执行:

cp .git/hooks/pre-commit.sample .git/hooks/pre-commit
chmod +x .git/hooks/pre-commit

约定很简单:退出码为 0,Git 继续执行;退出非零码,Git 中止,并打印你写入标准错误的内容。

pre-commit:你最值得使用的钩子

pre-commit 在你输入 git commit 之后、提交对象被写入之前运行。它无法看到提交信息——因为提交信息尚未被写入。它所做的就是检查已暂存的文件,如果发现异常则中止。 关键细节:使用

来获取你实际暂存的文件。每次提交都对整个项目进行检查会很慢,并且会暴露你未引入的问题。 git diff --cached --name-only lint 示例(ESLint)

标志会跳过已删除的文件——没有意义去检查你刚刚删除的内容。

#!/bin/sh
# Lint only staged JS files
STAGED_FILES=$(git diff --cached --name-only --diff-filter=ACM | grep '\.js$')

if [ -z "$STAGED_FILES" ]; then
  exit 0
fi

echo "Running ESLint on staged files..."
echo "$STAGED_FILES" | xargs ./node_modules/.bin/eslint

if [ $? -ne 0 ]; then
  echo "ESLint failed. Fix errors before committing."
  exit 1
fi

exit 0

--diff-filter=ACM 秘密扫描示例

一个直接的模式扫描,用于发现明显的错误——如硬编码的 API 密钥、配置文件中意外提交的密码:

对于超出玩具项目的场景,应搭配专用扫描工具使用。

#!/bin/sh
# Block commits with obvious secrets
PATTERNS="(AWS_SECRET|api_key\s*=|password\s*=|PRIVATE KEY)"

if git diff --cached | grep -qiP "$PATTERNS"; then
  echo "Potential secret detected in staged changes. Aborting commit."
  exit 1
fi

exit 0

detect-secrets 来自 Yelp 的工具非常适合作为 pre-commit 钩子——它维护一个基准文件,以避免现有标记字符串阻止每次提交。 trufflehog 更适合用于事后扫描历史或在 CI 中运行。 commit-msg:强制消息格式

此钩子接收一个参数:一个包含你草稿提交信息的临时文件路径。读取该文件,验证其内容,若无效则退出 1 以拒绝。该文件是可写的——你可以选择规范化消息而不是拒绝,尽管这在第一次使用时会让人感到意外。

强制执行

常规提交格式 是最常见的用途。其回报是自动生成的变更日志、可读的输出,以及能够解析提交类型以决定发布内容的 CI 流程: 这无法检测到格式正确但毫无意义的提交信息,例如 git log 。这是一个文化问题,而非工具问题。

#!/bin/sh
COMMIT_MSG_FILE=$1
COMMIT_MSG=$(cat "$COMMIT_MSG_FILE")

# type(scope): description — scope is optional
PATTERN="^(feat|fix|chore|docs|style|refactor|test|perf|ci|build|revert)(\(.+\))?: .{1,72}"

if ! echo "$COMMIT_MSG" | grep -qP "$PATTERN"; then
  echo ""
  echo "Invalid commit message. Use Conventional Commits format:"
  echo "  type(scope): short description"
  echo ""
  echo "Valid types: feat, fix, chore, docs, style, refactor, test, perf, ci, build, revert"
  echo "Example:     feat(auth): add OAuth2 login flow"
  echo ""
  echo "Your message: $COMMIT_MSG"
  exit 1
fi

exit 0

pre-push:在推送至远程仓库前的最后一道防线 fix: fix thingspre-push 在调用

之后、任何数据发送到远程之前运行。它通过标准输入接收远程名称和 URL。这里应运行实际测试——而不是一个检查器(在 pre-commit 中运行),而是验证行为的真正测试。

一个残酷的事实:如果你的测试套件耗时超过 60 到 90 秒,人们就会使用 git push 。这里只运行快速的单元测试。集成测试和端到端测试应放在 CI 中,因为慢是可接受的。一个慢到被绕过的钩子,比没有钩子更糟糕。

#!/bin/sh
echo "Running tests before push..."

npm test

if [ $? -ne 0 ]; then
  echo "Tests failed. Push aborted."
  exit 1
fi

exit 0

绕过钩子——以及何时可以这样做 --no-verify这两个标志存在是有原因的。一个故障的钩子会阻止热修复,这种事会令整个团队对 Git 钩子这一概念产生抵触。当你有正当理由时使用

:例如钩子在无关文件上误触发,或紧急情况下修复比门禁更重要。

git commit --no-verify
git push --no-verify

如果你频繁使用它,说明钩子需要调整。最常见的原因包括:运行过慢、在未更改的文件上失败,或模式匹配的误报你从未清理过。 --no-verify 与团队共享钩子

是每个克隆本地的——它被有意地不提交到仓库中。让钩子在团队中持续生效的两种方法:

方法 1:core.hooksPath

.git/hooks/ 将钩子存储在一个已提交的目录中(例如

),然后指向 Git 的该路径:

为了在新克隆时自动配置,添加一个 .githooks/脚本到

git config core.hooksPath .githooks

——npm 会在 prepare 时自动运行它。 package.json 确保脚本可执行,将其提交到仓库,任何克隆并运行 npm install:

{
  "scripts": {
    "prepare": "git config core.hooksPath .githooks"
  }
}

的人都会自动获得配置好的钩子。 npm install 方法 2:Husky

Husky

是 JavaScript/Node 项目中的标准选择。它为你处理钩子的配置,并为每个钩子提供一个独立的文件在 中。 core.hooksPath 然后以纯 Shell 脚本的形式添加钩子: .husky/:

npx husky init

Husky 9(2024 年初发布)完全弃用了 JSON 配置,转而使用纯 Shell 脚本。对于新设置而言,比 v4/v8 更简单,但从 Husky 4 升级是一个破坏性变更,官方迁移指南低估了这一点——旧的

echo "npm test" > .husky/pre-push
chmod +x .husky/pre-push

格式已完全不再有效。如果你正在升级现有仓库,需要预留时间。 .huskyrc 非 JavaScript 项目更适合使用

方法。没有必要为了钩子管理而引入 Node 依赖。 core.hooksPath 在钩子运行前审查你的差异

在终端中显示暂存更改。当你在比较两个版本的配置文件或检查重构实际改变了哪些内容时,视觉差异更易于快速扫描。

git diff --cached IO Tools’ 文本差异工具 让你可以粘贴两个版本并查看具体变化——在提交前审计即将进入的更改时非常有用。 Git 钩子是少数完全嵌入现有工作流程的自动化工具之一——无需 CI 账户、无需额外服务、无需成本。一个在 pre-commit 钩子中拒绝 lint 失败的钩子,其可靠性与你编写的 Shell 脚本完全一致。这是一个优点:你可以立即阅读、调试和修改它。配置上述三个钩子,你就能填补“本地能运行”与“主分支能运行”之间的最大差距。

Git 钩子:pre-commit、pre-push 和在门口阻止坏代码 2

想要享受无广告的体验吗? 立即无广告

安装我们的扩展

将 IO 工具添加到您最喜欢的浏览器,以便即时访问和更快地搜索

添加 Chrome 扩展程序 添加 边缘延伸 添加 Firefox 扩展 添加 Opera 扩展

记分板已到达!

记分板 是一种有趣的跟踪您游戏的方式,所有数据都存储在您的浏览器中。更多功能即将推出!

广告 移除?
广告 移除?
广告 移除?

新闻角 包含技术亮点

参与其中

帮助我们继续提供有价值的免费工具

给我买杯咖啡
广告 移除?