linux下git hooks可对sql脚本做提交前预检,涵盖语法校验、危险操作拦截、命名规范、敏感信息扫描四类检查,需配合sqlfluff等工具及工程实践落地。

在 Linux 环境下,利用 Git Hooks 对 SQL 脚本(尤其是数据库 Schema 变更文件,如 *.sql、*.up.sql)做提交前自动化预检,核心目标是:防止语法错误、不安全操作(如 DROP TABLE 无条件执行)、缺失注释、违反团队规范的 DDL/DML 进入暂存区。这不是简单“能运行就行”,而是构建可追溯、可协作、低风险的数据库变更起点。
明确预检范围与检查项
SQL 预检不是万能的,但应聚焦高价值、易出错、有共识的维度:
-
基础语法校验:用
sqlfluff(推荐)或mysqld --verbose --help模拟解析,检测 SQL 语法是否合法;对 PostgreSQL 可用psql -c "EXPLAIN (VERBOSE) ..." -v ON_ERROR_STOP=1快速试跑 -
危险操作拦截:正则匹配
^DROP\s+TABLE、^TRUNCATE、^ALTER\s+TABLE.*\s+DROP\s+COLUMN等,强制要求添加注释标记(如-- [SAFE: PRODUCTION_APPROVED])才允许通过 -
Schema 变更规范:检查文件名是否符合约定(如
V202405071420__add_user_status_column.up.sql),是否包含必要头部注释(作者、影响环境、关联需求 ID) -
敏感信息扫描:避免硬编码密码、连接字符串(如
mysql://user:pass@host/)出现在 SQL 文件中
编写可跨平台的 pre-commit 脚本
将以下脚本保存为 .git/hooks/pre-commit,并赋予执行权限(chmod +x .git/hooks/pre-commit):
使用四维度框架评估任意 GitLab MR 或 GitHub PR 的复杂度:规模(20%),认知负荷(30%),审查工作量(30%),风险/影响(20%)...
#!/usr/bin/env bash
<h1>获取所有暂存的 SQL 文件(支持 .sql, .up.sql, .down.sql)</h1><p>STAGED_SQL=$(git diff --cached --name-only --diff-filter=ACM | grep -E '.(sql|up.sql|down.sql)$')</p><p>if [ -z "$STAGED_SQL" ]; then
exit 0
fi</p><p>echo "? 正在预检暂存的 SQL 文件:"
echo "$STAGED_SQL"</p><h1>1. 检查敏感信息(密码、连接串等)</h1><p>if git diff --cached --name-only | xargs -r grep -l -i -E "(password|secret|mysql://|postgresql://|@.<em>:.</em>@)" 2>/dev/null | grep -q '.sql$'; then
echo "❌ 安全警告:检测到 SQL 文件中疑似硬编码凭证,请移除后重试"
exit 1
fi</p><h1>2. 检查危险 DDL(需团队确认是否启用)</h1><p>DANGEROUS_PATTERNS=(
"^DROP[[:space:]]+TABLE"
"^TRUNCATE[[:space:]]+TABLE"
"ALTER[[:space:]]+TABLE[[:space:]]+[^[:space:]]+[[:space:]]+DROP[[:space:]]+COLUMN"
)
for pattern in "${DANGEROUS_PATTERNS[@]}"; do
if git diff --cached --name-only | xargs -r grep -l "$pattern" 2>/dev/null | grep -q '.sql$'; then
echo "⚠️ 危险操作警告:检测到未标注的 $pattern 操作"
echo " 请添加类似 '-- [SAFE: REQUIRES_DB_OWNER_APPROVAL]' 的注释行"
exit 1
fi
done</p><h1>3. 使用 sqlfluff 校验语法(需提前安装:pipx install sqlfluff)</h1><p>if command -v sqlfluff &> /dev/null; then
for file in $STAGED_SQL; do
if [ -f "$file" ]; then
if ! sqlfluff lint --dialect postgres "$file" --quiet 2>/dev/null; then
echo "❌ 语法错误:$file 不符合 SQL 规范,请修正"
exit 1
fi
fi
done
else
echo "? 提示:建议安装 sqlfluff(pipx install sqlfluff)以启用语法校验"
fi</p><h1>4. 检查文件命名规范(示例:VYYYYMMDDHHMM__desc.up.sql)</h1><p>for file in $STAGED_SQL; do
if [[ ! "$file" =~ ^V[0-9]{12}<strong>.*.up.sql$ ]]; then
echo "? 命名不规范:$file 应遵循 VYYYYMMDDHHMM</strong>描述.up.sql 格式"
exit 1
fi
done</p><p>echo "✅ 所有 SQL 文件预检通过,允许提交"
exit 0
</p>
配套建议:提升团队落地效果
单靠钩子脚本不够,需配合工程实践:
-
把钩子纳入版本控制:不直接放
.git/hooks/(Git 不跟踪该目录),而是放在项目根目录如scripts/pre-commit-sql,再提供一键安装脚本./scripts/install-hooks.sh,内容为cp scripts/pre-commit-sql .git/hooks/pre-commit && chmod +x .git/hooks/pre-commit -
与 dbhub 或 Bytebase 集成:若团队已采用 Database-as-Code 工具,可让 pre-commit 调用
dbhub lint或bytebase schema check做更深层语义验证(如列类型兼容性、索引冗余) -
失败时给出修复指引:脚本中不要只写 “error”,而要提示“运行
sqlfluff fix --dialect postgres xxx.sql自动修复” 或 “参考 ./docs/sql-guidelines.md 第3条” -
预留绕过机制(谨慎使用):仅限紧急修复,加
git commit --no-verify,但应在 CI 流水线中二次拦截,确保不能跳过最终校验
为什么不用 Husky?
Husky 是 Node.js 生态主流方案,但对纯 SQL 项目或混合技术栈(Python + SQL + Bash)而言,原生 Git Hooks 更轻量、无依赖、跨语言友好。Husky 本质仍是封装了 .git/hooks/pre-commit,且需额外安装 Node 和 husky 包——当团队没有 JS 依赖时,反而增加维护负担。原生方式更直接可控。










