Skip to content

Repository files navigation

Git 钩子自动编译、防呆系统 - 快速指南

核心价值与降本增效

开发效率提升指标

部署自动编译系统后,依据团队规模测算的效益对比:

维度 手动编译模式 自动编译系统 效益提升
单次编译耗时 5-10 分钟(手动执行) < 1 分钟(自动执行) ⬇ 80-90%
编译失败发现周期 提交后/发布后(均值 6-12 小时) 编码阶段(< 5 分钟) ⬇ 99%
质量缺陷成本 发布后修复(人日成本 8-16) 本地修复(人日成本 0.5) ⬇ 94-97%
月度人力投入 10 人团队 × 6 小时/人 = 60 人时 10 人团队 × 0.5 小时/人 = 5 人时 ⬇ 91.7%
代码合并冲突率 自动合并后发现问题 合并前预编译检查 ⬇ 70%

关键业务收益

  1. 加快迭代速度:每个开发者月均节省 6 小时编译及验证时间,10 人团队月度释放 60 人时生产力
  2. 降低缺陷成本:在编码阶段捕获编译错误,避免进入测试/生产阶段(修复成本降低 15-30 倍)
  3. 保障代码质量:pre-commit 和 pre-rebase 强制编译检查通过,实现零编译错误入库
  4. 提升团队规模效应:自动化程度越高,团队扩张时边际成本越低;50 人团队可节省月度 300 人时

适用场景

  • 编译类项目:Go、Java、C++ 等需要编译的工程项目
  • 多分支并行开发:频繁切换分支与合并,自动拉取+编译降低遗漏风险
  • 大团队协作:团队规模 5+ 人,标准化流程收益显著
  • 严格质量要求:金融、医疗等行业,零容忍编译错误入库

文件结构

.git/hooks/
├── build-on-hook.py          # ✅ 公共编译脚本(Python 3,核心逻辑)
├── build-config              # ✅ 编译命令配置(可随时修改)
├── branch-protection.conf    # ✅ 分支保护配置(Push 禁推 + 删除保护)
├── post-checkout             # ✅ 分支切换后:自动 git pull(编译由 post-merge 触发)
├── post-merge                # ✅ 分支合并后:自动编译,手动 merge 成功后询问是否推送
├── pre-commit                # ✅ Commit 前:必须通过编译才能提交
├── post-commit               # ✅ Commit 后:询问是否推送到远程
├── pre-push                  # ✅ Push 前:校验分支推送和删除保护
└── pre-rebase                # ✅ Rebase 前:必须通过编译才能 rebase

自动编译触发场景

Git 操作 触发的 Hooks 特点
git checkout <branch> post-checkout + post-merge 自动拉取,如果产生合并则由 post-merge 编译
git pull origin <branch> post-merge 合并成功时编译(自动 pull 不询问 push)
git merge <branch> post-merge 合并成功后编译,编译通过后询问是否 push;合并保护分支时拒绝
git commit pre-commit + post-commit 编译失败则阻止 commit;成功后询问是否推送
git push pre-push 命中禁推分支或保护分支则阻止操作(手动和自动 push 均生效)
git push --delete <branch> pre-push 受保护分支禁止删除
git rebase pre-rebase 编译失败则阻止 rebaserebase 到保护分支时拒绝

配置管理

修改编译命令

编辑 .git/hooks/build-config 文件:

code .git/hooks/build-config

配置示例:

# go 项目(使用指定版本编译)
goenv shell 1.19.13 && go build ./main.go
# go 项目(使用系统中默认版本)
go build ./main.go
# maven 项目
mvn clean compile

说明:

  • 每行一条编译命令
  • # 开头的行为注释,空行被忽略
  • 命令按顺序执行,前一条失败会停止后续
  • 支持完整 shell 语法(&&|||、变量等)
  • 修改后立即生效,下次 hook 触发时生效

配置分支保护

编辑 .git/hooks/branch-protection.conf 文件:

code .git/hooks/branch-protection.conf

配置示例:

# Git 分支保护配置文件
# 列出的分支受到全面保护,包括:
#   - 禁止推送(git push origin <branch>)
#   - 禁止删除(git push origin --delete <branch>)
#   - 禁止其他分支 merge(仅允许 git pull origin <branch> 自身更新)
#   - 禁止其他分支 rebase(仅允许 git rebase origin/<branch> 自身更新)

main
master
develop
release
hotfix

说明:

  • 纯分支列表格式,每行一个分支名(精确匹配)
  • # 开头的行为注释,空行被忽略
  • 全面保护:列出的分支同时禁止推送、删除、merge 和 rebase
    • git push origin <branch> — 直接拒绝
    • git push origin --delete <branch> — 直接拒绝
    • git merge <protected-branch>(从其他分支 merge)— 由 pre-merge 检查拒绝
    • git rebase <protected-branch>(从其他分支 rebase)— 由 pre-rebase 检查拒绝
  • 该校验对手动操作和 hook 自动触发的操作都生效
  • 默认保护策略:配置为空(仅注释)时,保护所有分支

工作原理

分支切换自动拉取和编译流程

git checkout feature
  ↓
[1] post-checkout hook (Python 3)
    ├─ 创建标记: .git/AUTO_PULL_IN_PROGRESS
    ├─ 执行: git pull --no-rebase
    └─ 清除标记(finally)
  ↓
[2] post-merge hook (Python 3)(如果 pull 触发了合并)
    └─ 调用: python3 build-on-hook.py "post-merge"
           ├─ 读取: build-config
           ├─ 顺序执行: 每条编译命令
           └─ 全部成功后: 检查标记文件
               ├─ 标记存在 → 自动 pull 触发,跳过询问
               └─ 标记不存在 → 手动 merge,询问 git push [y/N]

工作流程说明:

  • post-checkout 负责代码同步(git pull),不执行编译
  • post-merge 负责编译和推送询问
  • 通过 .git/AUTO_PULL_IN_PROGRESS 标记文件协作,区分自动 pull 和手动 merge
  • 自动 pull 触发的编译成功后静默完成,手动 merge 后会询问是否推送

技术细节

Python 环境要求

  • 所有脚本使用 Python 3
  • 需要系统中有 python3 命令
  • 支持 Python 3.6+

用户输入机制

  • post-commitpost-merge/dev/tty 读取用户输入
  • Git hook 的 stdin 被重定向,无法使用标准 input()
  • CI/非交互环境:无法打开 /dev/tty 时自动跳过交互,不会阻塞

标记文件机制

  • .git/AUTO_PULL_IN_PROGRESS - 标记自动 pull 触发的 merge
  • 由 post-checkout 创建,post-merge 读取并清理
  • finally 块确保异常时也能清理

故障排除

Q1: Hook 脚本没有执行?

检查清单:

  1. 文件是否可执行:

    ls -lah .git/hooks/{build-on-hook.py,post-checkout,post-merge,pre-commit,post-commit,pre-push,pre-rebase}

    应看到 rwxr-xr-x 权限

  2. build-config 是否存在且有非注释命令:

    cat .git/hooks/build-config | grep -v "^#" | grep -v "^$"
  3. Hook 名称是否在 build-hooks-enabled 中:

    cat .git/hooks/build-hooks-enabled

Q2: 编译命令执行失败?

单独测试命令。检查错误信息,确保:

  • 代码无编译错误
  • 输出目录存在或可创建

Q3: pre-commit 编译失败,如何强制提交?

# 使用 --no-verify 跳过 pre-commit hook
git commit --no-verify -m "your message"

Q4: post-checkout 拉取失败?

  • 若远程分支不存在,会自动跳过拉取
  • 若拉取有冲突,hook 会提示,但不阻止分支切换
  • 需要手动解决冲突并继续编译

Q5: 为什么配置了 push-branch-config 但不生效?

原因:文件名错误

解决

# ❌ 错误的文件名(已废弃)
.git/hooks/push-branch-config

# ✅ 正确的文件名
.git/hooks/branch-protection.conf

Q6: 删除分支被拒绝但我没有配置保护?

原因:默认保护策略 - [delete-protected] 段落为空或不存在时保护所有分支

解决: 在 branch-protection.conf 中明确配置允许删除的策略:

[delete-protected]
main
master
# 仅保护 main 和 master,其他分支可删除

Q7: CI 环境中 post-commit/post-merge 卡住?

原因:非交互环境无法打开 /dev/tty 读取用户输入

解决

  • 脚本会自动检测并跳过交互,不会阻塞
  • 确保 CI 环境中 /dev/tty 不可用时脚本能正常退出(代码已处理)
  • 如果仍然卡住,检查 Python 版本和错误日志

输出示例

ℹ️  ========================== 自动编译开始 (Hook: post-checkout) ==========================
ℹ️ [1] 执行命令: goenv shell 1.19.13 && go build ./cmd/server/main.go
✅ [1] 命令执行成功
ℹ️  ========================== 自动编译完成 ==========================
✅ 3 条编译命令全部执行成功!

✅ 编译全部成功!
是否执行 git push?[y/N]: y
ℹ️  正在执行 git push ...
✅ Push 成功!

重要提示

  • .git/hooks 不在版本控制范围内 — 这些文件是本地的,不会被 git push
  • 编译脚本语言 — 所有脚本均使用 Python 3,需要 Python 3.x 环境
  • pre-commit 和 pre-rebase 会阻止操作 — 编译失败时无法 commit 或 rebase
  • pre-push 会阻止 push — 命中禁推分支时,push 会被拒绝(手动/自动均生效)
  • post-checkout 和 post-merge 不阻止操作 — 编译失败只输出错误,但 git 操作继续
  • post-merge 仅手动 merge 后询问推送 — 自动 pull 触发的 merge 不询问;手动 merge 编译成功后提示 [y/N],默认不推送;非交互环境自动跳过

更新日期: 2026-03-31
脚本语言: Python 3
已验证的 Hooks: post-checkout、post-commit、post-merge、pre-commit、pre-push、pre-rebase

About

一个利用 git hook 实现自动 pull 、自动编译等功能的脚本

Resources

Stars

7 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages