husky@9.1.7 发布日期 2024年11月18日
husky 是一个流行的 Git 钩子工具,用于在 Git 操作(如 commit、push 等)的特定阶段自动执行脚本(如代码 lint、格式化、测试等),从而在提交代码前拦截不规范的内容,保障代码质量和团队开发规范的一致性。
package.json
husky-9.1.7/package.json
{
"name": "husky",
"version": "9.1.7",
"type": "module",
"description": "Modern native Git hooks",
"keywords": [
"git",
"hooks",
"pre-commit"
],
"repository": {
"type": "git",
"url": "git+https://github.com/typicode/husky.git"
},
"funding": "https://github.com/sponsors/typicode",
"license": "MIT",
"author": "typicode",
"bin": {
"husky": "bin.js"
},
"exports": "./index.js",
"engines": {
"node": ">=18"
}
}
bin.js文件
husky-9.1.7/bin.js
#!/usr/bin/env node
import f, { writeFileSync as w } from 'fs'
import i from './index.js'
let p, a, n, s, o, d
p = process // 用于存储 process 对象(Node.js 进程信息)。
a = p.argv[2] // 存储命令行参数(用户输入的指令)。
// 1、处理 init 命令(初始化 husky)
if (a == 'init') {
n = 'package.json' // 存储文件名(如 package.json)。
s = f.readFileSync(n) // 存储package.json文件读取的字符串内容。
o = JSON.parse(s) // 存储解析后的 JSON 对象(如 package.json 的内容)。
// 确保 scripts 存在,并设置 prepare 脚本为 'husky'
;(o.scripts ||= {}).prepare = 'husky'
// 写回 package.json,保持原有的缩进格式(制表符或 2 空格)
w(n, JSON.stringify(o, 0, /\t/.test(s) ? '\t' : 2) + '\n')
// 输出 index.js 导出的信息(可能是初始化成功提示)
p.stdout.write(i())
// 创建 .husky 目录(忽略已存在的错误)
try { f.mkdirSync('.husky') } catch {}
// 在 .husky/pre-commit 中写入默认钩子脚本(用 npm/yarn/pnpm 执行 test)
w('.husky/pre-commit', (p.env.npm_config_user_agent?.split('/')[0] ?? 'npm') + ' test\n')
p.exit() // 退出进程
}
// 声明一个函数,用于输出 deprecated(废弃)命令的提示。
d = c => console.error(`husky - ${c} command is DEPRECATED`)
// 2、处理废弃命令(add/set/uninstall)
if (['add', 'set', 'uninstall'].includes(a)) { d(a); p.exit(1) }
// 3、处理 install 命令(兼容提示)
if (a == 'install') d(a)
// 4、默认处理
p.stdout.write(i(a == 'install' ? undefined : a))
执行 husky init 后做了什么?
- 在
package.json文件中,在scripts属性添加prepare:husky。 - 执行下面的
index.js文件。 - 创建
.husky目录,一般已存在,因为在index.js文件中已创建过。 - 在
.husky/pre-commit文件写入内容。
执行 husky 其他命令做了什么?
- 如果是执行了
husky add、husky set、husky uninstall回提示命令已废弃,然后退出。 - 如果执行了
husky install,也会提示该命令已废弃,然后执行index.js文件到逻辑。 husky、husky instll执行了逻辑一样,除了 install 会提示命令已废弃。
执行 npx huksy init,会多创建一个 .husky/pre-commit文件,以及在package.json文件的scripts添加 prepare:husky。
index.js文件
husky-9.1.7/index.js
import c from 'child_process'
import f, { readdir, writeFileSync as w } from 'fs'
import p from 'path'
export default (d = '.husky') => {
// 1. 环境与前置检查
// 若环境变量 HUSKY 被设置为 0,表示用户手动禁用 husky,直接返回跳过安装的提示。
if (process.env.HUSKY === '0') return 'HUSKY=0 skip install'
// 检查传入的路径 d 中是否包含 ..(上级目录),若有则返回错误(禁止跨目录操作,避免安全风险)。
if (d.includes('..')) return '.. not allowed'
// 检查当前目录是否存在 .git 文件夹(即是否在 Git 仓库中),若不存在则返回错误
// husky 依赖 Git 钩子机制,必须在 Git 仓库中使用
if (!f.existsSync('.git')) return `.git can't be found`
// 定义一个便捷函数 _,用于生成 husky 内部钩子目录(.husky/_)下的文件路径。例如:
// _() 返回 .husky/_
// _('husky.sh') 返回 .husky/_/husky.sh
let _ = (x = '') => p.join(d, '_', x)
// 执行 Git 命令 git config core.hooksPath .husky/_
// spawnSync 同步执行命令
// status 是命令退出码(0 表示成功,非 0 表示失败),stderr 是错误输出。
let {
status: s,
stderr: e
} = c.spawnSync('git', ['config', 'core.hooksPath', `${d}/_`])
// 若 status 为 null,表示 git 命令未找到(可能未安装 Git),返回错误提示。
if (s == null) return 'git command not found'
// 若 status 非 0(命令执行失败),返回 Git 命令的错误输出(如权限问题导致配置失败)。
if (s) return '' + e
// 强制删除旧的 husky.sh 文件(若存在),避免残留文件影响新配置。
f.rmSync(_('husky.sh'), { force: true })
// 创建 .husky/_ 目录
// recursive: true 确保父目录不存在时也能创建,如 .husky 未创建时自动生成
f.mkdirSync(_(), { recursive: true })
// 在 .husky/_ 目录下创建 .gitignore 文件,内容为 *(忽略该目录下所有文件,避免提交钩子脚本到 Git 仓库)。
w(_('.gitignore'), '*')
// 复制 husky 核心脚本
f.copyFileSync(new URL('husky', import.meta.url), _('h'))
// 为每个钩子生成对应的脚本文件
l.forEach(h => w(_(h), `#!/usr/bin/env sh\n. "\$(dirname "\$0")/h"`, { mode: 0o755 }))
// 向 .husky/_/husky.sh 写入消息 msg
w(_('husky.sh'), msg)
return ''
}
这段代码做了什么?
- 若环境变量
process.env.HUSKY设置0 ,退出。 - 若参数
路径d 中是否包含 ..,退出。 - 执行 git 命令
git config core.hooksPath .husky/_。 - 删除旧文件
husky.sh。 - 创建
.husky/_目录。 - 在
.husky/_目录下创建.gitignore文件,内容为*。 - 复制
husky文件 到_/h文件。 - 为每个钩子生成对应脚本文件。
- 在
.husky/_/husky.sh文件写入内容。
.husky/_/husky.sh
echo "husky - DEPRECATED
Please remove the following two lines from $0:
#!/usr/bin/env sh
. \"\$(dirname -- \"\$0\")/_/husky.sh\"
They WILL FAIL in v10.0.0
"
git config core.hooksPath
git config core.hooksPath 是用来配置 Git 钩子脚本的存放目录的命令 ——可以通过它修改 Git 钩子的默认路径,也可以查询当前钩子路径的配置值。
- Git 钩子脚本默认存放在仓库的
.git/hooks目录下。 .git目录是 Git 的私有目录,不会被提交到版本库,所以默认的.git/hooks里的钩子脚本无法在团队间同步。
# 将当前仓库的 Git 钩子路径设置为项目根目录的 .husky/_ 目录
git config core.hooksPath .husky/_