• 一句总结
git pull --rebase origin main = 先 fetch 更新 origin/main,再把你本地 main还没推送的提交一个一个“摘下来”并重新应用到远程最新的 origin/main 之上(即 rebase),最终使历史变成一条直线。

1 先看一个简单图例(最直观)

假设远程和本地最初一致,都是 AB
你在本地又提交了两个提交 C1C2(还没push):
此时远程有人推送了 D(你还没pull):
执行 git pull --rebase origin main 后发生:
  1. fetch 把远程更新到本地的 origin/main(A-B-D)。
  1. rebase 的意思:把 main 上的独有提交 (C1, C2) 挪到 D 之后。Git的步骤是找到共同的祖先B,然后把本地的提交C1和C2摘下来,临时保存(patch)。然后将HEAD移动到origin/main(目标分支上)(也就是D)把之前摘下来的一个个提交应用到D之后。注意C1’\C2’不是原来的C1C2,而是新的提交对象(新的哈希值),因为它们的父节点变了。原来是基于B,现在是基于D。
结果:

2 rebase 和 merge 的对比(图示)

同样场景,使用 git pull(merge)会产生一个合并提交 M
rebase 则变成直线(没有 M):

3 为什么 rebase 会“改提交”?

因为 rebase 是把每个本地提交“重新应用(replay)”在新的基底之上。重新应用会创建新的提交对象(新的父指向),所以这些提交的哈希会变——这是 重写历史 的行为。

  • git pull --rebase origin main 实际等价于
先:
再(在本地 main 分支上):

4 什么时候应该用 rebase,什么时候不该

推荐用 rebase:
  • 你在本地做了一些未推送的提交,想把它们“接到”远程最新的基础上,保持线性历史(常见于 feature 分支整理历史)。
  • 在把本地改动推到共享仓库前,把本地分支整理干净(例如在合并到主分支前用 rebase 压缩/整理提交)。
不该用 rebase(或要小心):
  • 不要对已经推送到公共远程并被其他人基于此继续开发的提交做 rebase —— 这会重写公共历史,给别人带来麻烦(需要强推 git push --force)。
  • 在多人共享的长期 main 分支上随意重写历史(危险)。
简单记法:可重写私人历史 / 不要重写公共历史

Loading...