惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

P
Proofpoint News Feed
H
Hacker News: Front Page
C
CXSECURITY Database RSS Feed - CXSecurity.com
C
Cisco Blogs
P
Palo Alto Networks Blog
Know Your Adversary
Know Your Adversary
D
Darknet – Hacking Tools, Hacker News & Cyber Security
C
Cybersecurity and Infrastructure Security Agency CISA
AWS News Blog
AWS News Blog
Spread Privacy
Spread Privacy
S
Schneier on Security
The Hacker News
The Hacker News
Cyberwarzone
Cyberwarzone
T
Tenable Blog
C
Cyber Attacks, Cyber Crime and Cyber Security
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
T
Tailwind CSS Blog
S
Secure Thoughts
N
Netflix TechBlog - Medium
T
The Exploit Database - CXSecurity.com
I
Intezer
Application and Cybersecurity Blog
Application and Cybersecurity Blog
Help Net Security
Help Net Security
K
Kaspersky official blog
Google Online Security Blog
Google Online Security Blog
L
LangChain Blog
Martin Fowler
Martin Fowler
L
LINUX DO - 热门话题
Hacker News: Ask HN
Hacker News: Ask HN
www.infosecurity-magazine.com
www.infosecurity-magazine.com
有赞技术团队
有赞技术团队
P
Privacy International News Feed
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
Recent Announcements
Recent Announcements
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
The Register - Security
The Register - Security
云风的 BLOG
云风的 BLOG
Google DeepMind News
Google DeepMind News
阮一峰的网络日志
阮一峰的网络日志
WordPress大学
WordPress大学
Recorded Future
Recorded Future
The Last Watchdog
The Last Watchdog
G
Google Developers Blog
T
Threatpost
小众软件
小众软件
S
Securelist
Recent Commits to openclaw:main
Recent Commits to openclaw:main
O
OpenAI News

博客园 - SKILL·NULL

一文了解大模型、小模型与各类神经网络的关系 如何在Mac上调整外星人鼠标AW720M的灯光颜色 Karabiner-Elements最常用配置 IndexedDB封装 echarts获取坐标上的点距离顶部底部高度 Let`s Encrypt 生成免费自动续签 HTTPS 证书 H5滚动截取长图 ReactNative常见问题及处理 根据.nvmrc自动切换项目所需node版本 Command PhaseScriptExecution failed with a nonzero exit code echarts双Y轴,实现均分为包含刻度0的指定段数,同时对齐刻度 env(safe-area-inset-bottom) 兼容写法 缩放实现0.5px 禁止 IOS 橡皮筋效果 JS 拦截浏览器返回 海康威视DS-IPC-E42H-IWPT监控画面竖线处理 Echarts 5 动态按需引入图表 React 18 自定义 Hook 获取 useState 最新值 处理报错 ResizeObserver loop completed with undelivered notifications.
如何为GIT设置全局勾子,为每次提交追加信息
SKILL·NULL · 2026-04-16 · via 博客园 - SKILL·NULL

全局 Git 钩子 + Husky 合并

本文说明:如何用单脚本 global-git-hooks + 符号链接,在任意环境复现「全局钩子与仓库内 Husky 链式执行」,并在指定目录下的仓库为提交标题追加 [AI]


一、原理与数据流

  1. Git 只认一个 core.hooksPath
    指向的目录里必须有名为 pre-commitprepare-commit-msg文件(Git 按文件名调用)。
    因此:目录里放多个同名符号链接,全部指向同一个可执行脚本 global-git-hooks

  2. 脚本如何知道当前是哪个钩子
    Git 执行的是 …/hooks/pre-commit 这类路径,$0 为 symlink 路径,basename "$0" 得到 pre-commitprepare-commit-msg 等,在脚本里 case 分发。

  3. 与 Husky 的关系

    • core.hooksPath=.husky/_:只会跑 Husky 自带桩脚本,不会进本目录。
    • core.hooksPath=$HOME/.config/git/hooks(或你自定义的目录):由 global-git-hooks 按顺序调用 .husky/<钩子名>.git/hooks/<钩子名>
    • 仓库 package.jsonprepare 里在 husky 之后有条件地把本仓库 core.hooksPath 指到全局目录:本机 global-git-hooks 才合并;没有的同事保持 Husky 默认 .husky/_,互不干扰。
  4. prepare-commit-msg 顺序(与「其它钩子」不同)

    .git/hooks/prepare-commit-msg(若存在且可执行)
         → .husky/prepare-commit-msg(若存在)
         → 满足 PREFIX 且未设 NO_AI 时,给说明文件首行末追加「 [AI]」
    
  5. 其它已链接钩子pre-commitcommit-msg 等)

    .husky/<同名>(若存在)
         → .git/hooks/<同名>(若存在,最后一个用 exec)
    
  6. _run_husky 必须先 shift 钩子名
    调用形式为 _run_husky "$HOOK" "$@"。函数内第一参数是逻辑钩子名(如 commit-msg),必须 shift 再执行 sh "$_f" "$@",否则子脚本会把 commit-msg 当成 $1(误以为是提交说明文件路径),导致 commitlint --edit 等报错。


二、从零搭建流程

1. 定目录

约定全局钩子目录为(可改,下文用 $HOOKS_HOME 表示):

export HOOKS_HOME="${GIT_HOOKS_HOME:-$HOME/.config/git/hooks}"
mkdir -p "$HOOKS_HOME"

也可长期用环境变量 GIT_HOOKS_HOME 指向别的路径(与 package.jsonprepare 一致)。

2. 写入脚本 global-git-hooks

$HOOKS_HOME/global-git-hooks 保存下文「四、完整脚本 global-git-hooks」中的全部内容。

必须修改的一处:脚本内 PREFIX=...,改成「允许追加 [AI]」的仓库根路径前缀(规范化路径,例如你所有公司代码都在 /data/work 下,则写 PREFIX="/data/work")。不匹配该前缀的仓库仍会执行链式钩子,但不会改提交说明。

然后:

chmod 700 "$HOOKS_HOME/global-git-hooks"

3. 建立符号链接(Git 要求的多个入口文件名)

cd "$HOOKS_HOME"
for h in pre-commit commit-msg prepare-commit-msg pre-push post-merge post-commit pre-rebase; do
  ln -sf global-git-hooks "$h"
done

4. 让 Git 使用本目录(二选一或都用)

方式 A — 本机所有仓库默认走全局钩子(最简单)

git config --global core.hooksPath "$HOOKS_HOME"

方式 B — 仅部分仓库、且与 Husky 合并(推荐团队)

  • 不设全局 hooksPath,或接受全局仍指向 $HOOKS_HOME
  • 在具体仓库的 package.json 里配置 prepare(见下文「五、仓库 package.json(Husky)」)。
  • 这样: $HOOKS_HOME/global-git-hooks 的机器在 pnpm install 后会把该仓库的 core.hooksPath 指到 $HOOKS_HOME没有该文件的机器保持 Husky 写入的 .husky/_

5. 自检

git config --get core.hooksPath
test -e "$HOOKS_HOME/global-git-hooks" && echo "global-git-hooks ok"

在「应追加 AI」的仓库根下:

printf 'feat: test\n' > /tmp/cm.txt
"$HOOKS_HOME/prepare-commit-msg" /tmp/cm.txt message
head -1 /tmp/cm.txt
# 期望:feat: test [AI]

三、环境变量与开关

变量 作用
NO_AI 仅当变量已设置(值可为空)时不追加 [AI]。须用 VAR= command 形式,不能写 NO_AI git …(shell 会把 NO_AI 当成命令名)。示例:NO_AI= git commit -m "..."NO_AI=1 git commit -m "...";多次提交可先 export NO_AI,用完 unset NO_AI
HUSKY=0 与 Husky 文档一致,为 0 时跳过执行 .husky/<钩子>
GIT_HOOKS_HOME 全局钩子目录不是默认路径时,与 package.jsonprepareGH=... 一致,指向含 global-git-hooks 的目录

四、完整脚本 global-git-hooks

保存为 $HOOKS_HOME/global-git-hooks(与下面内容一致;请改其中 PREFIX= 为你的工作区路径前缀)。

#!/usr/bin/env sh
# 单入口:各钩子名为指向本文件的 symlink,basename "$0" 区分钩子名。
# prepare-commit-msg:.git/hooks → .husky/prepare-commit-msg → [AI]
# 其它:.husky/<同名> → .git/hooks/<同名>

HOOK=$(basename "$0")
GIT_DIR=$(git rev-parse --git-dir 2>/dev/null) || exit 0
ROOT=$(git rev-parse --show-toplevel 2>/dev/null) || exit 0
ROOT_CANON=$(cd "$ROOT" 2>/dev/null && pwd -P) || ROOT_CANON="$ROOT"
PREFIX="/Users/macadmin/Work/code"

_run_husky() {
	_hook=$1
	shift
	_f="$ROOT/.husky/$_hook"
	[ -f "$_f" ] || return 0
	export PATH="$ROOT/node_modules/.bin:$PATH"
	_i="${XDG_CONFIG_HOME:-$HOME/.config}/husky/init.sh"
	[ -f "$_i" ] && . "$_i"
	[ "${HUSKY-}" = "0" ] && return 0
	sh "$_f" "$@" || exit $?
}

case "$HOOK" in
prepare-commit-msg)
	COMMIT_MSG_FILE=$1
	LEGACY="$GIT_DIR/hooks/prepare-commit-msg"
	if [ -x "$LEGACY" ]; then
		case "$LEGACY" in "$0") ;; *) sh "$LEGACY" "$@" || exit $? ;; esac
	fi
	_run_husky prepare-commit-msg "$@"
	[ -z "$COMMIT_MSG_FILE" ] || [ ! -f "$COMMIT_MSG_FILE" ] && exit 0
	case "$ROOT_CANON" in "$PREFIX"|"$PREFIX"/*) ;; *) exit 0 ;; esac
	# 跳过追加:须 export NO_AI 或 NO_AI= git commit …(勿写 NO_AI git,会被当作命令)
	[ "${NO_AI+x}" = "x" ] && exit 0
	_fl=$(head -n 1 "$COMMIT_MSG_FILE")
	_tr=$(printf '%s' "$_fl" | tr -d ' \t\r\n')
	[ -z "$_tr" ] && exit 0
	printf '%s' "$_fl" | grep -qE ' \[AI\]$' && exit 0
	sed -i.bak '1s/$/ [AI]/' "$COMMIT_MSG_FILE"
	rm -f "${COMMIT_MSG_FILE}.bak"
	exit 0
	;;
pre-commit|commit-msg|pre-push|post-merge|post-commit|pre-rebase)
	_run_husky "$HOOK" "$@"
	LEG="$GIT_DIR/hooks/$HOOK"
	[ -x "$LEG" ] && exec sh "$LEG" "$@"
	exit 0
	;;
*)
	exit 0
	;;
esac

移植说明

  • PREFIX:改成你环境的工作区根,例如 Linux PREFIX="/home/you/projects"。判断用的是 ROOT_CANONpwd -P),需与实际磁盘路径前缀一致。
  • sed -i.bak:适配 macOS BSD sed;Linux GNU sed 同样可用。
  • 未列出的钩子名:若自行增加 ln -sf global-git-hooks my-hook,需在脚本末尾 case 中增加分支,否则落入 *) 直接退出。

五、仓库 package.json(与 Husky 合并,可选)

在已有 husky 的前提下,让仅当本机存在全局脚本时,把当前仓库core.hooksPath 指到 $HOOKS_HOMEchmod 失败不阻断后续配置。

"prepare": "husky && (chmod 700 .husky/* 2>/dev/null || true) && sh -c 'GH=\"${GIT_HOOKS_HOME:-$HOME/.config/git/hooks}\"; [ -e \"$GH/global-git-hooks\" ] && git config core.hooksPath \"$GH\" || true'"

含义简述:

  1. husky:安装/更新 .husky/_,并可能把 core.hooksPath 写成 .husky/_
  2. chmod … || true:避免无文件匹配等导致整条 prepare 失败,从而跳过后面的 git config
  3. [ -e "$GH/global-git-hooks" ] && git config core.hooksPath "$GH":只有本机已部署全局脚本时才覆盖为全局目录;否则保持 Husky 默认。
  4. GIT_HOOKS_HOME:全局目录非默认路径时,在 shell 或 CI 里导出该变量与脚本内 GH 一致。

六、commitlint[AI]

prepare-commit-msgcommit-msg 之前执行,标题会变成 type: subject [AI]。若规则不允许尾部标记,需在 commitlint.config.js 中放宽 subject 等规则。


七、卸载 / 排错

去掉全局默认钩子目录

git config --global --unset core.hooksPath

某个仓库曾写入本地 core.hooksPath

git config --unset core.hooksPath

未追加 [AI]

检查 说明
git config --get core.hooksPath 合并生效时应为 $HOOKS_HOME,不是 .husky/_
PREFIX 仓库根路径(pwd -P)是否以 PREFIX 为前缀
NO_AI 是否误设
首行已以 [AI] 结尾 脚本会跳过,避免 commit --amend 重复追加

提示 NO_AI: command not found

  • 说明写成了 NO_AI git commit;应改为 NO_AI= git commitNO_AI=1 git commit(等号与命令之间要有空格)。

commit-msg / commitlint 报找不到文件

  • 多为旧版转发把钩子名当成 $1 传给 commitlint;请确认 global-git-hooks_run_husky 已含 shift(与上文「一、6」一致)。

八、文件清单(部署完成后)

$HOOKS_HOME/
  global-git-hooks          # 唯一实现(可执行)
  pre-commit            -> global-git-hooks
  commit-msg            -> global-git-hooks
  prepare-commit-msg    -> global-git-hooks
  pre-push              -> global-git-hooks
  post-merge            -> global-git-hooks
  post-commit           -> global-git-hooks
  pre-rebase            -> global-git-hooks