Hacker News Best

The git history command

8.5内容质量

TL;DR · AI 摘要

git history命令通过fixup、reword和split子命令,提供更安全的提交修改方式,无需切换工具。

核心要点

  • git history fixup可自动更新所有包含目标提交的分支
  • 与jj相比,git history保持原子操作避免半成品状态
  • 54和2.55版本新增reword和split子命令

结构提纲

按章节快速跳转。

  1. 当前git多分支协作存在操作风险和复杂性问题。

  2. §git history简介

    git history是git 2.54/2.55版本引入的实验性命令。

  3. ·fixup子命令

    自动修复提交并同步所有相关分支的变更。

  4. ·reword子命令

    提供更安全的提交信息修改方式。

  5. ·jj的对比

    保持git原生体验的同时实现类似jj的功能。

思维导图

用一张图看清主题之间的关系。

查看大纲文本(无障碍 / 无 JS 友好)
  • git history命令
    • fixup子命令
      • 自动分支更新
      • 原子操作
    • reword子命令
      • 提交信息修改
    • 与jj对比
      • 无需切换工具
      • 功能局限性

金句 / Highlights

值得收藏与分享的关键句。

#git#版本控制#命令行工具
打开原文

git history 命令值得更多关注 - Lalit Maganti

git history 命令值得更多关注

2026年7月13日

·

随笔

在 git 上并行处理大量更改可能会令人痛苦。你最终会在多个分支和提交之间来回切换,运行令人胆战心惊的 rebase -i 命令,稍有不慎(比如打个喷嚏)就可能让你的代码树处于半损坏状态。

最近 jj(git 的替代工具)经常被讨论(1, 2, 3, 4),并常被宣传为解决方案。虽然我对 jj 所要解决的问题非常认同,但它的实现方式并没有真正打动我。过去1.5年里,每3个月我都会尝试使用它几天,努力将其融入工作流程,但最终还是放弃并回到 git。1

这就是 git history 命令的用武之地。这是一个实验性命令,分两个版本发布:2.54(4月,重写和拆分子命令)和 2.55(6月,fixup 子命令)。每次发布时都曾引发大量关注,但据我所知,此后社区讨论几乎停滞。这很遗憾,因为在我看来,它已经提供了许多人推崇 jj 的诸多优势,而无需彻底改变工作流程。更棒的是,它是 git 核心发行版的一部分,无需安装任何东西即可尝试。

该命令包含三个子命令:fixup、reword 和 split

fixup

git history fixup 用于修复包含错误的旧提交,然后自动将所有分支变基为匹配状态。

你像平常一样使用 git add 阶段化修改,然后运行 git history fixup <commit> 将这些已暂存的更改合并到目标提交中。这类似于 git commit --fixup 加上自动变基,但额外的魔法在于它还会更新包含该提交的任何其他分支。

这部分功能比 git rebase --update-refs 更强大,后者仅移动你正在变基的范围内的引用。git history 则会查找并重写所有源自该提交的本地分支(同时提供限制仅当前分支的选项)。但另一方面,在存在合并提交的情况下它无法工作,这可能对某些 git 使用场景来说是个致命缺陷。

实际操作示例如下:

在修复 B 提交前:

执行 git history fixup B 后:

B* 是已合并修复的 B。重写提交会生成新哈希,因此 C 和 D 会自动重建为 C* 和 D*,feat-1 和 feat-2 分支尖端也会随之移动。

这三个命令最重要的特性是原子性:它永远不会让代码树处于半损坏状态。它通过拒绝任何可能导致冲突的操作来实现这一点。

需要明确的是,这比 jj 的能力要弱。jj 将冲突视为一等公民,可以在变基过程中携带冲突状态并让你稍后解决。git history 目前尚未实现此功能,但文档留有余地:

“此限制是设计使然,因为历史重写不打算作为有状态的操作。如果 Git 学会了如何处理一等冲突,这一限制可以解除。”

基本上,这一限制未来可能会改变,期待看到是否真的实现!

reword

git history reword 用于更新旧提交的提交信息,并自动将所有后续提交变基。当你在迭代过程中设计发生变更需要回溯修改提交信息时,这个功能非常有用。

git history reword <commit> 会用该提交现有的提交信息打开你的编辑器。你编辑后保存,其余提交栈会重新构建在顶部,分支也会随之更新。这与 fixup 的作用类似,区别在于 reword 用于修改提交信息而非提交内容。

由于它仅修改信息,reword(与之后的 split 类似)完全不会触碰索引或工作区;它纯粹基于提交图进行操作。因此两者都能在不干扰当前工作内容的情况下,重写未被检出分支上的提交。

执行前:

执行 git history reword B 后:

仅 B 的提交信息发生变化,但这也导致它获得新的哈希值,因此 C 会被重新构建为 C*,feat-1 分支也会随之更新。

拆分

git history split 会将一个提交拆分为两个,交互式地选择每个提交中需要保留的内容。这相当于 git add -p,但无需进行复杂的 git rebase 操作。我发现这是三个功能中最专用的,但在需要时却非常有价值。

具体来说,git history split <commit> 会进入该提交的 diff 的逐块提示界面。你保留的块组成第一个提交,其余内容会形成第二个提交。

执行前,B 提交包含两个无关更改:

执行 git history split B 后:

B 拆分为 B1 和 B2,C 会基于这两个提交重新构建为 C*。

结论

根据使用 jj 的人数来看,我认为仍存在一些关键的思维转变尚未实现。需要明确的是,git history 并未完全弥补 jj 的所有功能:jj 仍然提供易于撤销的操作日志,将工作副本建模为提交,并能在变基过程中处理冲突,这些都不是 git history 的目标。

但目前来看,git history 在采纳吸引人们使用 jj 的诸多特性方面迈出了重要一步,它已经集成在我每天使用的工具中。文档的编写方式也让我对后续版本的改进充满期待!

如果你喜欢这篇文章,可以订阅我的通讯或通过 RSS 关注。你也可以在 Hacker News 或 Lobsters 上分享这篇文章。

#

19:40

/

#git

  • 如果有兴趣,我很乐意写一篇关于我使用体验的文章。 ↩︎