Git rebase -i 的化腐朽为神奇

让每个人都认为你第一次就写出了完美的代码(并让你的补丁更容易审查和合并)。
227 位读者喜欢这篇文章。
hands programming

WOCinTech Chat 提供。Opensource.com 修改。CC BY-SA 4.0

软件开发是混乱的。 这么多的错误转弯,需要修复的拼写错误,稍后需要更正的快速破解和蹩脚代码,以及在过程后期才发现的差一错误。 通过版本控制,您可以获得创建“完美”最终产品(准备好提交给上游的补丁)过程中所做的每一个错误转弯和更正的原始记录。 就像电影的删减片段一样,它们有点令人尴尬,有时也很有趣。

如果您可以使用版本控制来定期保存您的工作,然后在您准备好提交以供审核的内容时,您可以隐藏所有这些私人草稿工作,而只提交一个完美的补丁,那岂不是很棒? 认识一下 git rebase -i,这是重写历史并让每个人都认为你第一次就生成了完美代码的完美方法!

git rebase 是做什么的?

如果您不熟悉 Git 的复杂性,这里有一个简要概述。 在底层,Git 将项目的不同版本与唯一的标识符相关联,该标识符由父节点唯一标识符的哈希值以及新版本与其父节点之间的差异组成。 这会创建一个修订树,每个检出项目的人都会获得自己的副本。不同的人可以沿不同的方向采用该项目,每个人都可能从不同的分支点开始。

Master branch vs. private branch

左侧“origin”仓库中的 master 分支和右侧您个人副本中的私有分支。

有两种方法可以将您的工作集成回原始仓库中的 master 分支:一种是使用 git merge,另一种是使用 git rebase。它们的工作方式截然不同。

当您使用 git merge 时,将在 master 分支上创建一个新提交,其中包含来自 origin 的所有更改以及您的所有本地更改。 如果存在任何冲突(例如,其他人也更改了您正在使用的文件),这些冲突将被标记,并且您有机会在将此合并提交提交到本地仓库之前解决这些冲突。 当您将更改推送回父仓库时,您的所有本地工作将显示为 Git 仓库其他用户的分支。

但是 git rebase 的工作方式不同。它会回滚您的提交,然后从 master 分支的顶端重新执行这些提交。 这会导致两个主要变化。 首先,由于您的提交现在从不同的父节点分支,因此它们的哈希值将被重新计算,并且任何克隆了您的仓库的人现在都可能拥有已损坏的仓库副本。 其次,您没有合并提交,因此任何合并冲突都会在您的更改重新执行到 master 分支上时被识别,您需要在继续 rebase 之前修复它们。 现在当您推送更改时,您的工作不会出现在分支上,并且看起来好像您在对 master 分支的最新提交中编写了所有更改。

Merge commits preserve history, and rebase rewrites history.

合并提交(左)保留历史记录,而 rebase(右)重写历史记录。

但是,这两种选择都有一个缺点:每个人都可以看到您在准备好共享代码之前在本地解决问题时所做的所有涂鸦和编辑。 这就是 git rebase--interactive(或简写 -i)标志发挥作用的地方。

介绍 git rebase -i

git rebase 的最大优势在于它可以重写历史记录。 但为什么只停留在假装从后面的点分支出来呢? 有一种方法可以更进一步并重写您如何到达准备提出的代码:git rebase -i,一种交互式的 git rebase

此功能是 Git 中的“魔法时间机器”功能。 该标志允许您在执行 rebase 时对修订历史记录进行复杂的更改。 您可以隐藏您的错误! 将许多小的更改合并为一个原始的功能补丁! 重新排序事物在修订历史记录中的显示方式!

output of git rebase -i

当您运行 git rebase -i 时,您将获得一个编辑器会话,其中列出了正在重新设置基准的所有提交,以及您可以对它们执行的许多选项。 默认选项是 pick

  • Pick 在您的历史记录中维护提交。
  • Reword 允许您更改提交消息,例如修复拼写错误或添加其他评论。
  • Edit 允许您在重播分支的过程中对提交进行更改。
  • Squash 将多个提交合并为一个。
  • 您可以通过在文件中移动提交来重新排序提交。

完成后,只需保存最终结果,rebase 将执行。 在您选择修改提交的每个阶段(无论是使用 rewordeditsquash,还是在发生冲突时),rebase 都会停止并允许您在继续之前进行适当的更改。

上面的示例导致“One-liner bug fix”和“Integrate new header everywhere”合并为一个提交,而“New header for docs website”和“D'oh - typo. Fixed”合并为另一个提交。 就像变魔术一样,其他提交中包含的工作仍然存在于您的分支上,但相关的提交已从您的历史记录中消失!

这使得使用 git send-email 向上游项目提交干净的补丁或通过针对父仓库创建包含您新整理的补丁集的拉取请求变得容易。 这有很多优点,包括使您的代码更容易审查、更容易接受和更容易合并。

接下来要阅读的内容
标签
User profile image.
Dave Neary 是 Red Hat 开源和标准团队的成员,帮助使对 Red Hat 重要的开源项目取得成功。 自 1999 年向 GIMP 发送他的第一个补丁以来,Dave 一直在自由和开源软件世界中,扮演着许多不同的角色。

5 条评论

?我习惯手动执行此操作。 我工作,然后在提交之前暂存我的更改,然后检出 master,git pull,创建新分支,应用我的暂存,提交并推送。

这行得通,但我发现 rebase -i 非常适合平衡常规同步点和干净的 PR。 谢谢您的反馈!

回复 作者 Rodrigo Graça (未验证)

我喜欢你用小便利贴来做插图?

谢谢! 我尝试在 Inkscape 中进行操作,但最终在便利贴上涂鸦更快 :-)

回复 作者 Knusper (未验证)

我喜欢我的代码历史,并且重视拥有它。

此外,如果您不向 master 展示历史记录,某些服务可能无法识别您的实际提交。

我更喜欢在 master 分支上:`git merge -s recursive -X theirs 3.3.x`

Creative Commons License本作品根据 Creative Commons Attribution-Share Alike 4.0 International License 许可。
© 2025 open-source.net.cn. All rights reserved.