- 原文地址:Don’t Fear The Rebase
- 原文做者:本文已获原做者 Jared Ready 受权,转载请注明出处。
- 译文出自:掘金翻译计划
- 本文永久连接:github.com/xitu/gold-m…
- 译者:根号三
- 校对者:Tina92、Starrier
Git 的 rebase
命令是 Git 用户感到惧怕和迷惑的一个常见缘由,特别是那些来自可能更集中的版本控制系统的用户。这很正常。Rebase 是一个难以想象又充满魔力的怪兽,一上来无论三七二十一就改变历史。前端
Rebase 有点像指针。它是这样一个使人困惑的结构:每一个人都在谈论它,可是你并不清楚为何会有人使用它,而后忽然一切都“啪嗒”一下,整个想法都变得显而易见和难以置信的简单。android
在这篇文章中我会迫使你“啪嗒”一下,这样你就能够回到工做中并传播 git rebase
的神奇。ios
Git Rebase 是一个很简单的工具,用来取出一些在某个地方建立的提交,并伪装它们一直是在另外一个地方建立的。git
好的,我知道了。但是这意味着什么呢?github
让咱们来看一个例子。咱们在这个仓库中有两个分支:master
和 feature/foo
。feature/foo
是基于 master
分离出去的分支,而且在 feature/foo
分支上产生了一些提交。master
也发生了移动,就像世界不会由于少了你的关注而停滞不前。后端
这是目前的状态工具
咱们想将一些更改从 master
整合进 feature/foo
中,可是咱们不想每次执行这个整合时都处理一次使人讨厌的合并提交。区块链
Rebase 就是一个让你有能力整合发生在源分支上的更改而不须要执行合并(merge)从而不会产生合并提交的工具。人工智能
这是 rebase 以后的状况。(fast-forward 版本)翻译
D 和 F 两个提交已经被从新放在了 master
的顶部,即当前指向的 G 提交。你可能会注意到这两个提交实际上已经被重命名为了 D* 和 *F
,而且提交的 SHA-1 值也不同。这是为何呢?
一个提交具备一些与之相关的属性:一个父提交、一个时间戳、提交时仓库的快照(提交不只仅是变动集)。这些值是 Git 在计算标识一个提交的 SHA-1 时所用到的。
因为提交是不可变的,而且一个 SHA-1 应该惟一标识一个提交,所以 Git 须要建立一个新的提交来包含原始提交中相同的仓库快照,可是每一个提交都有一个不一样的父提交和时间戳。
这致使新的提交看起来与原始提交相同,可是具备不一样的 SHA-1。
当咱们从 feature/foo
分支上运行 git rebase master
时,Git 怎么知道哪些提交须要移动呢?
让咱们先看看每一个分支上的提交的文氏图(Venn diagram)。
从上图中咱们能够看到每个分支都有 A、B 和 C 这几个提交。master
分支还拥有 E 和 G 提交可是 feature/foo
分支没有。feature/foo
拥有 F 和 D 提交可是 master
分支没有。
Git 会作一个减法:{commits on feature/foo} — {commits on master}
,来找出正确的提交。这个结果就是 D 和 F。
固然,一个简单方式是使用 git log
来看咱们从这组减法中获得的确切提交。
git log master..feature/foo
会 向咱们展现 bc1f36b
和 640e713
提交。
若是你在 .. 后省略了一个分支,那么会默认为是当前分支。
看起来不错。让咱们来看看更普遍的视角以确保我不是在糊弄。
这些 sha-1 看起来很熟悉。
这里并无 76f5fd1 和 22033eb,由于咱们是从 master 分支的 7559a0b 提交开始分离的。
若是咱们如今执行一个 rebase
到 master
,咱们会当即看到 76f5fd1
和 22033eb
出如今咱们在 feature/foo
分支上建立出的提交的前面。
Git 正在像咱们指望中的那样从新应用提交。
看起来熟悉吗?
咱们以前见过这个了。
咱们如今有一个很好的线性历史。你应该可以想到在此刻 fast-forward 的合并会如何发生。
rebase 策略还有一个已知的额外好处,就是若是你的 CI 管道(CI pipeline)在功能分支上经过了,那么在合并后的主分支上它也会经过。若是是一个非线性的合并策略,你就不能保证这一点。
若是 feature/foo
分支已经被推送过(push),而且在 rebase 以后尝试进行另外一个推送,Git 会很委婉地拒绝推送。这是为何呢?
Git 会尽其所能来防止意外覆盖历史,这是一件好事。
咱们来看一下 Git 所认为的 feature/foo
分支在远程仓库中是什么样的?
如今咱们来看一下咱们告诉 Git 要作的事情。
从 Git 的角度来看,提交 D 和 F 即将丢弃。Git 会给你这样一行友好的信息:Updates were rejected because the tip of your current branch is behind
。
你或许会说,“可是我能够在你这个很棒的图片中清晰地看到,feature/foo
分支比以前更进一步了啊。” 这是一个很好的观察结果,可是 Git 只会看到远程仓库中的 feature/foo
包含 bc1f36b
和 640e713
,可是你本地的 feature/foo
不包含这些提交。所以为了避免丢失这些提交,Git 会委婉地拒绝一个正常的 git push
,并要求你执行 git push --force
。
若是你从这篇文章中带走一件东西,那么请记住,rebase 只是简单的查找出在某个分支上建立的提交,而后使用相同的内容可是新的父提交或基础提交(base commit)来建立新的提交。
若是你喜欢个人文章,请为我点赞。
关注 Hackernoon 和 Jared Ready 来获取更多高质量的软件工程相关的内容吧。
掘金翻译计划 是一个翻译优质互联网技术文章的社区,文章来源为 掘金 上的英文分享文章。内容覆盖 Android、iOS、前端、后端、区块链、产品、设计、人工智能等领域,想要查看更多优质译文请持续关注 掘金翻译计划、官方微博、知乎专栏。