一句话定义:merge 和 rebase 都是把两条分支的改动合到一起的手段,区别在于——merge 保留分叉的真实历史,rebase 把历史改写成一条直线,代价是重写提交。
先打两个比方。
merge(合并)像两条支流汇入主干。河流地图上,你依然能看见两条河道当初是怎么分开、又在哪里碰头的。Git 里对应的动作是生成一个新的 merge commit,它有两个父提交,分别指向两条分支的最新位置。分叉发生过,记录就留在那里,谁也改不了。
rebase(变基)像把一份手写稿重新誊抄一遍。内容还是那些内容,但纸张换了,页码重排了。Git 会把当前分支上独有的提交逐个"剪切"下来,复制成新的提交,依次接到目标分支的最新提交之后。注意,是复制:每个提交的哈希值都会变,原来的提交对象被丢弃。所以 rebase 之后的历史看起来是一条笔直的线,你看不出中间曾经并行过。
和相邻概念的区别。 容易混的是 squash(压缩合并)和 fast-forward。squash 是把多个提交压成一个再合并,改变的是提交的颗粒度;fast-forward 是 merge 的退化情况——当目标分支没有新提交时,指针直接前移,连 merge commit 都不产生。而 rebase 改变的是提交的"身份"(哈希)和它们在时间线上的位置。
| 维度 | merge | rebase |
|---|---|---|
| 历史形状 | 保留分叉,如实记录 | 一条直线,整洁 |
| 是否新增提交 | 是,merge commit | 不新增,但每个提交都被重写 |
| 提交哈希 | 原提交不变 | 全部变化 |
| 冲突处理 | 集中解决一次 | 可能每个被重放的提交都要解决一次 |
| 适用场景 | 公共分支、已推送的分支 | 本地整理、合并前清理自己的分支 |
实际意义。 对写代码的人:一条实用的分工是——在自己本地分支上反复 rebase,让提交记录干净、方便 code review;等要合进主干时用 merge,把"这里有过一段并行开发"的信息留下来。反过来做就会出事:不要 rebase 已经推送到共享分支的提交,因为同事的本地仓库还指着旧哈希,一拉取就会对不上,还得手工修。这是团队协作里最容易踩的坑。
对不写代码的人:这条规则本身值得记——改动别人的共享历史,成本总是落在别人身上。"历史干净"从来不等于"没出过问题",它只说明有人花力气整理过。读一个项目的历史时,git log --graph 画出来的那些分叉和合流,才是真实发生过的协作过程。
