如何在Git pre-push钩子中执行commit --amend并成功推送?
解决pre-push钩子中执行推送导致的哈希不匹配问题
你遇到的报错本质是:pre-push钩子是Git原生推送流程的前置环节,你在钩子内修改了提交哈希(commit --amend)并自行执行了推送,而原有的Git推送流程仍会继续用旧哈希尝试推送,导致远程分支哈希与本地新哈希不匹配,触发锁冲突。
以下是两种可行的解决方案:
方案1:在pre-push钩子内完成操作后终止原推送流程
直接在钩子内完成配置文件的提交、拉取、推送,最后返回非0值阻止原生推送流程执行,避免两次推送的冲突。
示例脚本:
#!/bin/bash # 获取项目根目录 PROJECT_ROOT="$(git rev-parse --show-toplevel)" JEST_CONFIG="${PROJECT_ROOT}/jest.config.js" CURRENT_BRANCH="$(git rev-parse --abbrev-ref HEAD)" # 检查jest.config.js是否存在未提交的变更 if git diff --name-only --cached HEAD | grep -q "^$(basename "$JEST_CONFIG")$" || git diff --name-only HEAD | grep -q "^$(basename "$JEST_CONFIG")$"; then # 暂存配置文件并修正当前提交(保留原提交信息) git add "$JEST_CONFIG" git commit --amend -C HEAD --no-edit # 拉取远程最新代码(用rebase避免冗余合并提交) if ! git pull --rebase origin "$CURRENT_BRANCH"; then echo "拉取代码时发生冲突,请手动解决后重新推送" exit 1 fi # 推送修改后的提交(--no-verify跳过钩子,避免循环触发) git push --no-verify origin "$CURRENT_BRANCH" # 返回非0值,阻止原生推送流程继续执行 exit 1 fi # 无配置文件变更时,正常放行原生推送 exit 0
方案2:提前在提交阶段处理配置文件变更(更推荐)
把配置文件的变更处理从push阶段提前到commit阶段,避免在push时修改提交哈希,从根源上消除冲突。可以使用prepare-commit-msg钩子实现:
示例脚本:
#!/bin/bash PROJECT_ROOT="$(git rev-parse --show-toplevel)" JEST_CONFIG="${PROJECT_ROOT}/jest.config.js" # 仅在常规提交(非合并、回滚等操作)时处理 if [ "$2" = "commit" ]; then # 检查jest.config.js是否有未暂存的变更 if git diff --name-only HEAD | grep -q "^$(basename "$JEST_CONFIG")$"; then git add "$JEST_CONFIG" git update-index --refresh fi fi exit 0
这个钩子会在用户执行git commit时自动把jest.config.js的变更加入当前提交,后续推送时无需修改提交哈希,自然不会触发冲突。
注意事项
- 使用
git pull --rebase时,如果出现冲突需要手动解决,脚本中建议添加错误判断,避免强制推送错误代码。 commit --amend会改写提交历史,如果分支有其他协作者,需提前沟通避免他人基于旧提交哈希工作。
内容的提问来源于stack exchange,提问作者Thanh-Quy Nguyen
相关产品推荐
相关产品推荐

