Git-knife:像编辑表格一样修改提交信息、作者和日期

查看原文 HN 讨论

文章摘要

git-knife 的定位很明确:一个用来编辑 git 提交元数据的桌面 GUI,可编辑的字段包括提交信息、作者日期、提交者日期、作者姓名/邮箱和提交者姓名/邮箱,界面呈现为一张可以直接编辑的表格。它的口号是「把你的 git 历史捅成想要的形状」,工具名和刀的比喻贯穿整个项目。

作者对市场空白的判断写得相当清楚:现有的 GUI(GitKraken、Sublime Merge、Fork、lazygit)在改写提交信息和重排提交上做得很好,但它们把提交日期当成事实上不可变的东西,也不暴露任意提交的提交者日期和作者身份;而那些改写这些元数据的工具(git-filter-repogit rebase 的环境变量技巧、git commit-tree)没有 GUI。git-knife 填的就是这个交集:一个能批量、安全地编辑每一个字段的干净 GUI。README 里附了一张详细的对比表格,逐项标注各工具是否支持改写作者日期、提交者日期、作者身份以及批量正则查找替换。

它的实现策略是一个重要卖点:它从不重新实现 git,而是 shell out 调用系统的 git CLI,用 git commit-tree 重建提交,并复用每个提交原本的 tree 对象,因此文件内容可证明地永远不会被改变。技术栈是 Tauri v2 + Rust + Node/pnpm。核心代码组织为:src-tauri/src/git.rs 是唯一 spawn git 的地方;commits.rs 负责 open_repolist_commitsrewrite.rs 提供 preview_editsapply_edits,从最早被编辑的提交一路到 tip 通过 commit-tree 重建链条,然后保存一个备份 ref 并用「对旧 tip 做 compare-and-swap」的方式移动分支;backup.rs 负责列出并恢复备份。

MVP 已实现的功能包括:打开仓库并按 ref 选择任意本地分支来查看/编辑,不需要 checkout,所以工作区完全不受影响;批量查找替换(字面量或正则,带 $1 反向引用),可以选择作用在哪些字段上,典型场景是把所有提交里的旧邮箱换成新邮箱;应用前预览每一处变更;每次改写前自动创建备份 ref 并支持一键恢复;当改写会触及已推送的历史时给出警告;签名感知——给已签名的提交打徽章、警告改写会剥离签名、并可以用你配置的密钥重新签名(如果开启重签但没配密钥,会在动任何 ref 之前安全地失败);支持跨 merge 编辑,重建完整提交图并保留每个 merge 的父节点。尚未实现的是重排、squash、drop,以及暂存区/分支/远端管理。

README 还花了不少篇幅讲改写后的操作规范:编辑一个提交会改变它以及之后每个提交的哈希,本地分支与远端因此分叉,普通 push 会被拒绝,应该用 git push --force-with-lease——它会在远端自上次 fetch 后有变动时拒绝推送,从而避免悄无声息地覆盖同事的提交。改写共享历史后,其他人需要 fetch 加 git reset --hard(会丢弃本地独有提交,需要先协调)。撤销方面,应用内的 Backups 面板可一键恢复改写前的 tip,命令行则可以用 git for-each-ref refs/knife-backup 找到旧 tip 再 reset。

一个有意思的透明性设计:默认情况下 git-knife 会给每个被改写的 tip 提交附上一条公开披露的 note,放在自己专属的 notes ref 上(refs/notes/git-knife),因此不会碰你正常的 notes,在普通 git log 里不可见但完全可发现——你可以用 git notes --ref=git-knife show <commit> 读它,或者用 git for-each-ref refs/notes/git-knife 检查「这个仓库是否被 git-knife 编辑过」。README 强调这里没有隐藏编码,随时可以在界面上关掉,也可以用 git update-ref -d 彻底清除。改写策略本身在 git 层面有一个验证脚本,复现完整的 commit-tree 流程并断言内容 diff 为空。

HN 评论精华

这条帖子拿到 165 分,讨论呈现出三条清晰的主线:一是「谁真的需要改写提交日期和作者」——结果收到了一批相当具体的真实用例;二是围绕签名提交与共享历史的安全性质疑,作者当场发版本响应;三是一场规模不小、与工具本身几乎无关的关于「LLM 写的代码和文档」的争吵。