要理解Rebase(变基)的本质,我们可以从字面意思、生活比喻和技术原理三个维度来拆解。
1. 字面意思:重新定义“起点”
- Base:基底、起点、根基。
- Re-base:更换基底,或者说重新寻找出发点。
在 Git 中,您写的每一行代码、每一次 commit,都是基于某一个历史节点(Base)做出来的。
- 当您写代码时,基底是 A。
- 在您写代码的过程中,同事往服务器推送了新代码 B。
- 此时,您的起点(Base)已经落后了。
- Rebase 的本质就是:把您的修改“剪切”下来,等服务器上最新的代码更新完之后,再把您的修改“粘贴”到最新代码的后面。
2. 一个形象的比喻:写书
假设您和同事正在共同写一本书:
- 你们都写到了第二章 (Commit A)。
- 此时,同事在服务器上提交了第三章-优化编译 (Commit B)。
- 而您在本地也写了一个第三章-自己的修改 (Commit C)。
现在面临冲突,有两种解决办法:
办法①:Merge(合并)
把你们两个人的“第三章”强行揉在一起,并自动生成一个叫作“合并了两个第三章”的第四章 (Commit D)。
- 缺点:书的目录会变得混乱,多出了一个无意义的“合并章节”。
办法②:Rebase(变基)
Git 走过来对您说:“您先别急着提交您的第三章。我先把同事写的【第三章-优化编译】拿过来作为新的基础,然后把您的修改当成第四章,重新写在后面。”
- 优点:书的目录变成了极其干净的一条直线:第二章→\rightarrow→同事写的第三章→\rightarrow→您写的第四章。
3. 技术原理:Git 在背后做了什么?
以下是git pull --rebase执行时的真实过程:
状态 1:分叉了
- 服务器(同事提交了 D):
A -> B -> D - 本地(您提交了 C):
A -> B -> C
D (服务器最新) / A -> B \ C (您本地的修改)状态 2:执行 Rebase
- Git 悄悄把您的临时提交
C存到临时缓冲区。 - Git 把您的本地分支,重置到服务器最新的
D节点。此时您本地的历史变成了:A -> B -> D。 - Git 把刚才存起来的
C,尝试“贴”到D的后面。
A -> B -> D -> C' (您的修改被重新贴在了 D 后面)如果在“贴”的过程中(第3步),发现 C 和 D 修改了同一个地方(比如同一个 APK 文件),Git 就会暂停,报出冲突(Conflict),让您决定保留谁。
4. 为什么在 Rebase 冲突时,ours和theirs颠倒了?
这常常让很多人感到困惑,但在理解了 Rebase 的原理后,就很容易解释了:
在普通合并(Merge)中:
--ours(我们的):代表您本地的代码。--theirs(他们的):代表服务器(别人)的代码。
在变基(Rebase)中:
由于 Git 是先把本地分支重置成服务器的代码(作为新基底),然后再把您的修改贴上去。- 当 Git 切换到服务器代码时,Git 认为服务器的代码才是“当前分支(我们的
--ours)”。 - 准备贴上去的您本地的修改,反而变成了“外来的临时补丁(他们的
--theirs)”。
- 当 Git 切换到服务器代码时,Git 认为服务器的代码才是“当前分支(我们的
所以:
--ours= 服务器上的最新代码。--theirs= 您本地写好、准备贴上去的代码。