在commit-msg/prepare-commit-msg钩子中修改文件提交不生效的问题
问题原因与解决方案
核心问题:钩子执行时机错误
commit-msg 和 prepare-commit-msg 钩子的执行时机是在 Git 已经生成本次提交的暂存区快照之后,它们的设计目的仅用于修改提交信息。此时修改文件并执行git add,只是更新了暂存区,但本次提交已经基于之前的快照构建,新变更不会被纳入,只能等到下一次提交才生效。
正确钩子选择:pre-commit
要在提交前修改文件并让变更进入本次提交,必须使用pre-commit钩子。它的执行时机是在 Git 准备生成提交快照之前,此时修改文件并完成暂存,变更会被包含到本次提交中。
代码修正要点
- 将脚本移到
.git/hooks/pre-commit路径下,并赋予执行权限:chmod +x .git/hooks/pre-commit - 修复异步执行问题:原代码使用异步的
exec,钩子进程可能在git add操作完成前就退出,导致暂存失效。建议改用同步执行的execSync。
基础修正版代码(无需提交消息场景)
#!/usr/bin/env node const fs = require("node:fs"); const { execSync } = require('child_process'); // 读取目标文件内容 const currentContent = fs.readFileSync("changes.txt", "utf8"); // 示例:添加自定义内容(可根据需求调整) const updatedContent = `${new Date().toISOString()}\n${currentContent}`; // 写入更新后的内容 fs.writeFileSync("changes.txt", updatedContent); // 同步执行暂存操作,确保完成后再退出钩子进程 try { execSync(`git add changes.txt`); process.exit(0); } catch (err) { console.error(err); process.exit(1); }
结合提交消息修改文件的完整方案
如果需要将提交消息写入changes.txt,由于pre-commit钩子无法直接获取提交消息,需要配合两个钩子实现:
- prepare-commit-msg钩子:先将提交消息保存到临时文件
#!/usr/bin/env node const fs = require("node:fs"); const msgPath = process.argv[2]; const commitMsg = fs.readFileSync(msgPath, "utf8"); // 把提交消息写入临时文件 fs.writeFileSync(".tmp-commit-msg", commitMsg); process.exit(0);
- pre-commit钩子:读取临时文件的消息,修改目标文件并暂存
#!/usr/bin/env node const fs = require("node:fs"); const { execSync } = require('child_process'); // 读取临时文件中的提交消息 const commitMsg = fs.readFileSync(".tmp-commit-msg", "utf8"); // 读取目标文件当前内容 const currentContent = fs.readFileSync("changes.txt", "utf8"); // 更新文件内容 const updatedContent = commitMsg + currentContent; fs.writeFileSync("changes.txt", updatedContent); // 同步暂存文件 try { execSync(`git add changes.txt`); // 清理临时文件 fs.unlinkSync(".tmp-commit-msg"); process.exit(0); } catch (err) { console.error(err); process.exit(1); }
内容的提问来源于stack exchange,提问作者vanowm
相关产品推荐
相关产品推荐

