Skip to content

如何

¥How To

添加新钩子

¥Adding a New Hook

添加钩子就像创建文件一样简单。这可以使用你最喜欢的编辑器、脚本或基本的 echo 命令来完成。例如,在 Linux/macOS 上:

¥Adding a hook is as simple as creating a file. This can be accomplished using your favorite editor, a script or a basic echo command. For example, on Linux/macOS:

shell
echo "npm test" > .husky/pre-commit

启动文件

¥Startup files

Husky 允许你在运行钩子之前执行本地命令。它从这些文件中读取命令:

¥Husky allows you to execute local commands before running hooks. It reads commands from these files:

  • $XDG_CONFIG_HOME/husky/init.sh

  • ~/.config/husky/init.sh

  • ~/.huskyrc(已弃用)

    ¥~/.huskyrc (deprecated)

在 Windows 上:C:\Users\yourusername\.config\husky\init.sh

¥On Windows: C:\Users\yourusername\.config\husky\init.sh

跳过 Git 钩子

¥Skipping Git Hooks

用于单个命令

¥For a Single Command

大多数 Git 命令都包含一个 -n/--no-verify 选项来跳过钩子:

¥Most Git commands include a -n/--no-verify option to skip hooks:

sh
git commit -m "..." -n # Skips Git hooks

对于没有此标志的命令,请使用 HUSKY=0 暂时禁用钩子:

¥For commands without this flag, disable hooks temporarily with HUSKY=0:

shell
HUSKY=0 git ... # Temporarily disables all Git hooks
git ... # Hooks will run again

用于多个命令

¥For multiple commands

要在较长时间内禁用钩子(例如,在 rebase/merge 期间):

¥To disable hooks for an extended period (e.g., during rebase/merge):

shell
export HUSKY=0 # Disables all Git hooks
git ...
git ...
unset HUSKY # Re-enables hooks

用于 GUI 或全局

¥For a GUI or Globally

要在 GUI 客户端或全局禁用 Git 钩子,请修改 husky 配置:

¥To disable Git hooks in a GUI client or globally, modify the husky config:

sh
# ~/.config/husky/init.sh
export HUSKY=0 # Husky won't install and won't run hooks on your machine

CI 服务器和 Docker

¥CI server and Docker

要避免在 CI 服务器或 Docker 中安装 Git Hooks,请使用 HUSKY=0。例如,在 GitHub Actions 中:

¥To avoid installing Git Hooks on CI servers or in Docker, use HUSKY=0. For instance, in GitHub Actions:

yml
# https://docs.github.com/en/actions/learn-github-actions/variables
env:
  HUSKY: 0

如果仅安装 dependencies(而不是 devDependencies),"prepare": "husky" 脚本可能会失败,因为不会安装 Husky。

¥If installing only dependencies (not devDependencies), the "prepare": "husky" script may fail because Husky won't be installed.

你有多种解决方案。

¥You have multiple solutions.

修改 prepare 脚本以永不失败:

¥Modify the prepare script to never fail:

json
// package.json
"prepare": "husky || true"

你仍会在输出中收到 command not found 错误消息,这可能会造成混淆。要使其保持静默,请创建 .husky/install.mjs

¥You'll still get a command not found error message in your output which may be confusing. To make it silent, create .husky/install.mjs:

js
// Skip Husky install in production and CI
if (process.env.NODE_ENV === 'production' || process.env.CI === 'true') {
  process.exit(0)
}
const husky = (await import('husky')).default
console.log(husky())

然后,在 prepare 中使用它:

¥Then, use it in prepare:

json
"prepare": "node .husky/install.mjs"

无需提交即可测试钩子

¥Testing Hooks Without Committing

要测试钩子,请将 exit 1 添加到钩子脚本以中止 Git 命令:

¥To test a hook, add exit 1 to the hook script to abort the Git command:

shell
# .husky/pre-commit

# Your WIP script
# ...

exit 1
shell
git commit -m "testing pre-commit code"
# A commit will not be created

项目不在 Git 根目录中目录

¥Project Not in Git Root Directory

出于安全原因,Husky 不会安装在父目录 (../) 中。但是,你可以在 prepare 脚本中更改目录。

¥Husky doesn't install in parent directories (../) for security reasons. However, you can change the directory in the prepare script.

考虑这个项目结构:

¥Consider this project structure:

.
├── .git/
├── backend/  # No package.json
└── frontend/ # Package.json with husky

像这样设置你的准备脚本:

¥Set your prepare script like this:

json
"prepare": "cd .. && husky frontend/.husky"

在你的钩子脚本中,将目录更改回相关子目录:

¥In your hook script, change the directory back to the relevant subdirectory:

shell
# frontend/.husky/pre-commit
cd frontend
npm test

非 shell 钩子

¥Non-shell hooks

为了运行需要使用脚本语言的脚本,请对每个适用的钩子使用以下模式:

¥In order to run scripts that require the use of a scripting language, use the following pattern for each applicable hook:

(使用钩子 pre-commit 和 NodeJS 的示例)

¥(Example using hook pre-commit and NodeJS)

  1. 为钩子创建一个入口点:

    ¥Create an entrypoint for the hook:

    shell
    .husky/pre-commit
  2. 在文件中添加以下内容

    ¥In the file add the following

    shell
    node .husky/pre-commit.js
  3. .husky/pre-commit.js

    ¥in .husky/pre-commit.js

    javascript
    // Your NodeJS code
    // ...

Bash

钩子脚本需要符合 POSIX 标准以确保最佳兼容性,因为并非每个人都拥有 bash(例如 Windows 用户)。

¥Hook scripts need to be POSIX compliant to ensure best compatibility as not everyone has bash (e.g. Windows users).

话虽如此,如果你的团队不使用 Windows,你可以通过这种方式使用 Bash:

¥That being said, if your team doesn't use Windows, you can use Bash this way:

shell
# .husky/pre-commit

bash << EOF
# Put your bash script inside
# ...
EOF

Node 版本管理器和 GUI

¥Node Version Managers and GUIs

如果你在通过版本管理器安装 Node 的 GUI 中使用 Git 钩子(如 nvmnfnmasdfvolta 等),你可能会因为 PATH 环境变量问题而遇到 command not found 错误。

¥If you're using Git hooks in GUIs with Node installed via a version manager (like nvm, n, fnm, asdf, volta, etc...), you might face a command not found error due to PATH environment variable issues.

了解 PATH 和版本管理器

¥Understanding PATH and Version Managers

PATH 是一个包含目录列表的环境变量。你的 shell 会在这些目录中搜索命令。如果找不到命令,你会收到一条 command not found 消息。

¥PATH is an environment variable containing a list of directories. Your shell searches these directories for commands. If it doesn't find a command, you get a command not found message.

在 shell 中运行 echo $PATH 以查看其内容。

¥Run echo $PATH in a shell to view its contents.

版本管理器的工作方式:

¥Version managers work by:

  1. 将初始化代码添加到你的 shell 启动文件(.zshrc.bashrc 等)中,该文件在你每次打开终端时运行。

    ¥Adding initialization code to your shell startup file (.zshrc, .bashrc, etc.), which runs each time you open a terminal.

  2. 将 Node 版本下载到主文件夹中的目录中。

    ¥Downloading Node versions to a directory in your home folder.

例如,如果你有两个 Node 版本:

¥For example, if you have two Node versions:

shell
~/version-manager/Node-X/node
~/version-manager/Node-Y/node

打开终端初始化

¥Opening a terminal initializes the version manager, which picks a version (say Node-Y) and prepends its path to PATH:

shell
echo $PATH
# Output
~/version-manager/Node-Y/:...

现在,node 指的是 Node-Y。切换到 Node-X 会相应地更改 PATH

¥Now, node refers to Node-Y. Switching to Node-X changes PATH accordingly:

shell
echo $PATH
# Output
~/version-manager/Node-X/:...

出现此问题的原因是,在终端外启动的 GUI 不会初始化版本管理器,导致 PATH 没有 Node 安装路径。因此,来自 GUI 的 Git 钩子经常会失败。

¥The issue arises because GUIs, launched outside a terminal, don't initialize the version manager, leaving PATH without the Node install path. Thus, Git hooks from GUIs often fail.

解决方案

¥Solution

Husky 在每个 Git 钩子之前获取 ~/.config/husky/init.sh 源。在此处复制你的版本管理器初始化代码以确保它在 GUI 中运行。

¥Husky sources ~/.config/husky/init.sh before each Git hook. Copy your version manager initialization code here to ensure it runs in GUIs.

nvm 示例:

¥Example with nvm:

shell
# ~/.config/husky/init.sh
export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" # This loads nvm

或者,如果你的 shell 启动文件快速且轻量,请直接获取它:

¥Alternatively, if your shell startup file is fast and lightweight, source it directly:

shell
# ~/.config/husky/init.sh
. ~/.zshrc

手动设置

¥Manual setup

Git 需要配置,husky 需要在 .husky/ 中设置文件。

¥Git needs to be configured and husky needs to setup files in .husky/.

在你的 repo 中运行一次 husky 命令。理想情况下,将其包含在 package.json 中的 prepare 脚本中,以便在每次安装后自动执行(推荐)。

¥Run the husky command once in your repo. Ideally, include it in the prepare script in package.json for automatic execution after each install (recommended).

json
{
  "scripts": {
    "prepare": "husky"
  }
}
json
{
  "scripts": {
    "prepare": "husky"
  }
}
json
{
  "scripts": {
    // Yarn doesn't support prepare script
    "postinstall": "husky",
    // Include this if publishing to npmjs.com
    "prepack": "pinst --disable",
    "postpack": "pinst --enable"
  }
}
json
{
  "scripts": {
    "prepare": "husky"
  }
}

运行 prepare 一次:

¥Run prepare once:

sh
npm run prepare
sh
pnpm run prepare
sh
# Yarn doesn't support `prepare`
yarn run postinstall
sh
bun run prepare

.husky/ 目录中创建一个 pre-commit 文件:

¥Create a pre-commit file in the .husky/ directory:

shell
# .husky/pre-commit
npm test
shell
# .husky/pre-commit
pnpm test
shell
# .husky/pre-commit
yarn test
sh
# .husky/pre-commit
bun test