Class: Pindo::GitHookHelper
- Inherits:
-
Object
- Object
- Pindo::GitHookHelper
- Includes:
- Singleton
- Defined in:
- lib/pindo/module/utils/git_hook_helper.rb
Constant Summary collapse
- HOOK_VERSION =
Hook 版本号,修改 hook 内容时递增此版本
'1.0.0'- HOOK_VERSION_PREFIX =
版本标记前缀(用于在 hook 文件中识别版本)
'# pindo_commit_stats_hook_version:'- COMMIT_STATS_MARKER =
变更统计关键字(用于旧版 hook 特征识别)
'变更统计'- GLOBAL_HOOKS_DIR =
全局 hook 目录(由 install_global_commit_stats_hook 使用)不放在 ~/.pindo 下,便于后续 shell 脚本入口以同一路径写入
File.('~/.git-hooks').freeze
- GIT_HOOK_NAMES =
Git 官方支持的 hook 名称列表(来自 githooks(5))不含 prepare-commit-msg —— 该 hook 由 pindo 装完整统计逻辑,不做转发
%w[ applypatch-msg pre-applypatch post-applypatch pre-commit pre-merge-commit commit-msg post-commit pre-rebase post-checkout post-merge pre-push pre-receive update proc-receive post-receive post-update reference-transaction push-to-checkout pre-auto-gc post-rewrite sendemail-validate fsmonitor-watchman p4-changelist p4-prepare-changelist p4-post-changelist p4-pre-submit post-index-change ].freeze
- LFS_AWARE_HOOKS =
git-lfs 相关的 4 个 hook —— 使用 LFS-aware 转发桩执行顺序: 1) 调 git lfs <name> 完成 LFS 工作 → 2) 无条件转发仓库本地同名 hook 标准 git-lfs 本地 hook 会让 LFS 被调用两次,但 LFS 是幂等的无副作用;换取“用户自定义逻辑(含 hybrid 脚本)完整执行”的保证。其余 23 个 hook 使用纯转发桩。
%w[pre-push post-checkout post-commit post-merge].freeze
Class Method Summary collapse
Instance Method Summary collapse
-
#install_commit_stats_hook(git_root_dir) ⇒ Object
为仓库及其子模块安装 prepare-commit-msg hook(自动追加变更统计) 支持普通仓库、子模块、Husky 项目 版本匹配则跳过,版本不匹配或无版本则覆盖.
-
#install_global_commit_stats_hook ⇒ String
全局安装 commit 变更统计 hook(通过 core.hooksPath 对所有 Git 仓库生效).
-
#verbose? ⇒ Boolean
verbose 模式: PINDO_DEBUG 环境变量(由命令层 –verbose 透传).
-
#vstart(msg) ⇒ Object
verbose 模式下才打印的 start 消息.
Class Method Details
.share_instance ⇒ Object
10 11 12 |
# File 'lib/pindo/module/utils/git_hook_helper.rb', line 10 def share_instance instance end |
Instance Method Details
#install_commit_stats_hook(git_root_dir) ⇒ Object
为仓库及其子模块安装 prepare-commit-msg hook(自动追加变更统计)支持普通仓库、子模块、Husky 项目版本匹配则跳过,版本不匹配或无版本则覆盖
53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 |
# File 'lib/pindo/module/utils/git_hook_helper.rb', line 53 def install_commit_stats_hook(git_root_dir) Funlog.instance.("安装 commit 变更统计 hook (v#{HOOK_VERSION})...") # 1. 主仓库 install_hook_to_repo(git_root_dir) # 2. 子模块 begin submodule_output = Pindo::GitHandler.git!(%W(-C #{git_root_dir} submodule status --recursive)).strip unless submodule_output.empty? submodule_output.each_line do |line| parts = line.strip.split(' ') next if parts.length < 2 sub_path = File.join(git_root_dir, parts[1]) if File.directory?(sub_path) && (File.directory?(File.join(sub_path, '.git')) || File.file?(File.join(sub_path, '.git'))) install_hook_to_repo(sub_path) end end end rescue => e Funlog.instance.("子模块检测跳过: #{e.}") if ENV['PINDO_DEBUG'] end Funlog.instance.("commit 变更统计 hook 安装完成!") end |
#install_global_commit_stats_hook ⇒ String
全局安装 commit 变更统计 hook(通过 core.hooksPath 对所有 Git 仓库生效)
执行四件事:
1. 解析目标目录 —— 读 global + system 级 core.hooksPath:
- 已指向某目录 → 沿用(adaptive,避免破坏已有全局 hook 体系)
- 未设置 → 使用默认 GLOBAL_HOOKS_DIR (~/.git-hooks),并负责设置 core.hooksPath
2. 写入 prepare-commit-msg —— 主 hook,**完全接管**,不调用仓库本地同名 hook
3. 写入 27 个转发桩 —— 逐个独立判断:空位写入 / pindo 老版本升级 / foreign 保留
其中 LFS_AWARE_HOOKS (4 个) 使用 LFS-aware 模板,其余 23 个使用纯转发桩
4. 若是默认路径 → 设置 git config --global core.hooksPath
101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 |
# File 'lib/pindo/module/utils/git_hook_helper.rb', line 101 def install_global_commit_stats_hook vstart("开始安装全局 Git hook (pindo v#{HOOK_VERSION})") vstart(" 包含: 1 个 prepare-commit-msg 主 hook + #{GIT_HOOK_NAMES.size} 个转发桩 (#{LFS_AWARE_HOOKS.size} LFS-aware + #{GIT_HOOK_NAMES.size - LFS_AWARE_HOOKS.size} 纯转发)") vstart("[4.1] 解析目标 hooks 目录 (自适应 core.hooksPath)") target_dir, need_set_config = resolve_target_hooks_dir FileUtils.mkdir_p(target_dir) unless File.writable?(target_dir) Funlog.instance.(" 目标目录不可写: #{target_dir}") raise Informative, "target hooks dir not writable: #{target_dir}" end vstart("[4.2] 安装 prepare-commit-msg 主 hook (完全接管,不调用仓库本地同名 hook)") install_main_global_hook(target_dir) vstart("[4.3] 安装 #{GIT_HOOK_NAMES.size} 个 hook 转发桩 (逐文件独立判断,foreign 保留不动)") install_forwarder_stubs(target_dir) vstart("[4.4] 配置 core.hooksPath") if need_set_config vstart(" 执行: git config --global core.hooksPath #{target_dir}") Pindo::GitHandler.git!(%W(config --global core.hooksPath #{target_dir})) Funlog.instance.(" core.hooksPath 已设置: #{target_dir}") else vstart(" core.hooksPath 已指向 #{target_dir},跳过") end Funlog.instance.("全局 Git hook 安装完成! (target: #{target_dir})") target_dir end |
#verbose? ⇒ Boolean
verbose 模式: PINDO_DEBUG 环境变量(由命令层 –verbose 透传)
80 81 82 |
# File 'lib/pindo/module/utils/git_hook_helper.rb', line 80 def verbose? !ENV['PINDO_DEBUG'].to_s.empty? end |