pre-commit钩子自动暂存构建产物后提交信息模板未更新如何解决
解决方案
你观察到的提交信息模板状态不同步问题确实由git内部状态缓存导致:git在调用pre-commit钩子前就已经将当前暂存区的状态加载到内存中,pre-commit钩子内执行的git add操作只会修改磁盘上的暂存区,不会刷新git的内存快照,因此后续生成的提交信息模板仍然是旧的状态。
以下是两种可直接落地的解决方案:
方案1:调整逻辑触发时机,从根源规避缓存问题
最简单的方案是把「构建产物生成+暂存」的逻辑从pre-commit钩子中移出来,用git别名包装提交命令,在git启动前就完成产物更新和暂存,这样git读取到的暂存区就是最新状态,提交模板自然会同步更新。
你可以在项目的.git/config或者全局.gitconfig中添加如下配置:
[alias] ci = "!f() { \ # 替换为你实际的构建产物生成命令,例如 npm run build npm run build; \ # 暂存指定构建产物 git add artifact; \ # 执行原生commit命令,透传所有参数 git commit \"$@\"; \ }; f"
后续使用git ci替代git commit执行提交操作即可,完全不会出现状态不同步的问题,逻辑简单且易维护。
方案2:在prepare-commit-msg钩子中重写提交模板
如果你不想修改提交习惯,希望直接使用git commit触发流程,可以通过prepare-commit-msg钩子覆盖git生成的旧提交模板。
你之前查阅的git源码逻辑是正确的,确实没有原生单条命令可以直接输出完整的COMMIT_EDITMSG内容,但可以用现有git命令拼接出和原生模板完全一致的内容,直接替换即可:
- 保留
pre-commit钩子中原有的构建产物生成、git add artifact逻辑不变 - 新增
.git/hooks/prepare-commit-msg钩子文件,添加执行权限,写入如下内容:
#!/bin/sh COMMIT_MSG_FILE=$1 # 仅处理默认生成的空白提交模板,跳过已经通过-m、-F等参数指定提交信息的场景 if [ $# -eq 1 ]; then # 清空原有模板内容,写入和原生完全一致的头部注释 echo "" > "$COMMIT_MSG_FILE" echo "# Please enter the commit message for your changes. Lines starting" >> "$COMMIT_MSG_FILE" echo "# with '#' will be ignored, and an empty message aborts the commit." >> "$COMMIT_MSG_FILE" echo "#" >> "$COMMIT_MSG_FILE" # 写入当前分支信息 git status --branch --short | head -n1 | sed 's/^/# On branch /' >> "$COMMIT_MSG_FILE" echo "#" >> "$COMMIT_MSG_FILE" # 写入最新的已暂存变更列表(包含你pre-commit中新增的构建产物) echo "# Changes to be committed:" >> "$COMMIT_MSG_FILE" git diff --cached --name-only | sed 's/^/#\t/' >> "$COMMIT_MSG_FILE" echo "#" >> "$COMMIT_MSG_FILE" # 可选:写入未暂存的变更列表,和原生模板保持完全一致 echo "# Changes not staged for commit:" >> "$COMMIT_MSG_FILE" git diff --name-only | sed 's/^/#\t/' >> "$COMMIT_MSG_FILE" fi
该钩子会在git生成默认模板后、弹出编辑器前执行,用最新的暂存区状态重写整个提交信息文件,你在编辑器中看到的就是包含新增构建产物的最新变更列表。
内容的提问来源于stack exchange,提问作者CarloDePieri
相关产品推荐
相关产品推荐

