git rebase -i 改变人生的魔力

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

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

软件开发是混乱的。 如此多的错误转向,需要修复的错别字,稍后要纠正的快速技巧和临时解决方案,以及在过程后期发现的差一错误。 通过版本控制,你可以完美地记录在创建“完美”最终产品(准备向上游提交的补丁)过程中所犯的每一个错误转向和更正。 就像电影的NG片段一样,它们有点尴尬,有时也很有趣。

如果你可以使用版本控制定期在航点保存你的工作,然后在你准备好提交审查时,你可以隐藏所有私有草稿工作,只提交一个完美的补丁,那岂不是太棒了? 来认识一下 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 分支时,会识别出任何合并冲突,你需要先解决它们,然后才能继续进行变基。 当你现在推送你的更改时,你的工作不会显示在分支上,看起来好像你在 master 分支的最新提交中编写了所有更改。

Merge commits preserve history, and rebase rewrites history.

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

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

介绍 git rebase -i

**git rebase** 的最大优势在于它可以重写历史记录。 但是,为什么要止步于仅仅假装你从稍后的点分支出来呢? 有一种方法可以更进一步,并重写你如何获得准备提交的代码:**git rebase -i**,一个交互式 **git rebase**。

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

output of git rebase -i

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

  • **Pick** 在你的历史记录中保留提交。
  • **Reword** 允许你更改提交消息,可能是为了修复错别字或添加其他注释。
  • **Edit** 允许你在重播分支的过程中对提交进行更改。
  • **Squash** 将多个提交合并为一个。
  • 你可以通过在文件中移动提交来重新排序它们。

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

上面的示例导致“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本作品根据知识共享署名-相同方式共享 4.0 国际许可协议获得许可。
© . All rights reserved.