Git: rebase vs merge

一、详细解释,什么是merge和rebase

假设你和团队在开发一个项目,主分支叫 main,你新建了一个分支 feature 来加新功能。

你在 feature 分支上写了两个提交:C 和 D。

此时 main 分支上别人也加了一个提交 B。

历史看起来像这样:

复制代码
A --- B (main)
 \
  C --- D (feature)

现在你要main 的最新代码合并到你的 feature 分支 (或者反过来把你的功能合并到 main),Git 提供了两种方式:merge 和 rebase。

1. merge(合并)------ 最常用、最安全的方式

命令:

bash 复制代码
git checkout feature
git merge main

结果:

Git 会创建一个新的"合并提交"(叫 merge commit),把两个分支的代码合在一起。

历史变成:

复制代码
A --- B -------- M (merge commit)  ← 当前在 feature 和 main 上
 \
  C --- D -------/

特点

  • 历史有"分叉"和"汇合",看起来像一棵树(真实反映了并行开发的过程)
  • 多了一个合并提交 M
  • 完全不改动原来的提交(C、D、B 都不变)
  • 超级安全:就算你已经把分支 push 到远程,也随便 merge,不会影响别人

适合场景:团队协作、把完成的特性合并到主分支时用 merge。

2. rebase(变基)------ 让历史变得"一条直线"

命令:

bash 复制代码
git checkout feature
git rebase main

结果:

Git 把你的提交 C 和 D "搬家" ,先放到 main 的最新提交 B 后面,重新生成两个新提交 C' 和 D'(内容一样,但 commit ID 变了)。

历史变成:

复制代码
A --- B --- C' --- D'  ← 现在 feature 和 main 都在这条直线上

特点

  • 历史变成一条干净的直线,看起来就像你是在最新的 main 上直接开发的
  • 没有多余的合并提交
  • 会改写你的提交历史(生成新的 commit ID)
  • 如果你已经 push 过 feature 分支到远程,再 rebase 后必须强制 push(git push --force-with-lease),可能会把别人搞混乱

适合场景:你在自己本地的特性分支还没完成、还没给别人看的时候,用 rebase 把代码更新到最新,并顺便整理提交(让历史更干净)。

二、实际协作开发中的典型使用场景(更清晰可视化说明)

在团队协作开发中,通常有一个公共主分支(常见名为 mainmaster,以下统一用 main),所有稳定代码都最终合并到这里。你想添加新功能时,不会直接在 main 上修改,而是采用以下标准流程。这个流程中,rebase 的作用就是保持你的分支始终基于最新的 main,避免最后合并时出现大量冲突

完整流程步骤 + 更清晰的可视化历史

(1):从最新的 main 开新分支

你先确保本地 main 是最新的,然后新建一个特性分支(feature branch)。

bash 复制代码
git checkout main		#切换到分支main
git pull origin main          # 确保本地 main 是最新的
git checkout -b feature/new-login  # 新建并切换到特性分支

初始历史(可视化)

新分支刚创建时,它和 main 指向完全相同的最新提交(假设当前 main 的最新提交是 X)。

复制代码
... --- W --- X (main)  
              ↑
              feature/new-login(刚创建,还没有任何自己的提交)
(2):你在 feature 分支上开发

你写了几个自己的提交:Y、Z。

历史变成:

复制代码
... --- W --- X (main)
               \
                Y --- Z (feature/new-login)   # 你自己的提交
(3):开发期间,别人往 main 合并了新代码

其他人完成了别的功能,提 PR 并合并到了 main,新增了提交 P 和 Q。

历史变成:

复制代码
... --- W --- X --- P --- Q (main)                 # 别人新增的 P、Q
               \
                Y --- Z (feature/new-login)       # 你的分支还停留在旧的 X 上

问题出现了

你的分支现在基于"旧版本"的 main(停留在 X),而远程 main 已经前进到 Q。

继续开发的话,你的代码缺少别人最新的 P 和 Q,可能导致:

  • 功能冲突(别人改了你也要改的地方)
  • 最后合并时冲突爆炸
(4):用 rebase 把你的修改"移植"到最新的 main 上
bash 复制代码
git fetch origin              # 先拉取远程最新代码
git rebase origin/main        # 把你的 Y、Z 重新应用到最新的 main 上

rebase 的执行过程

  • Git 先把你的 Y、Z "暂时拿走"
  • 把 main 的最新提交(P、Q)放到你的分支下面
  • 然后把你的 Y、Z 一个个"重放"上去,生成新的 Y'、Z'(内容完全一样,只是 commit ID 变了)

结果历史:

复制代码
... --- W --- X --- P --- Q --- Y' --- Z' (feature/new-login)

好处

  • 你的分支现在基于最新的 main,自动包含了别人所有的修改
  • 你可以立刻发现并解决冲突(冲突量通常小得多,因为是逐步解决)
  • 历史变成一条直线,看起来非常整洁

如果中途有冲突,Git 会暂停让你解决,解决完运行 git rebase --continue

(5):开发完成,清理提交
bash 复制代码
git rebase -i origin/main     # 交互式 rebase

你可以把零散的 Y'、Z' 等提交:

  • 合并(squash)成 1~3 个有意义的提交
  • 修改提交消息,让它更清晰、专业

这样提 PR 时,reviewer 看得非常舒服。

(6):推到远程提 PR,并用 merge 合并到 main
bash 复制代码
git push --force-with-lease origin feature/new-login   # 因为 rebase 改了历史,需要强制推送

在 GitHub/GitLab 上提 Pull Request,审核通过后:

  • 用 merge 方式合并到 main(保留合并记录,安全)

最终 main 历史(普通 merge):

复制代码
... --- W --- X --- P --- Q --- Y'' --- Z'' --- M (merge commit)

或者用 "Squash and merge"(更干净):

复制代码
... --- W --- X --- P --- Q --- 新合并提交(包含你所有修改)

三、对比

(1).不做 rebase,直接最后 merge

复制代码
... --- W --- X --- P --- Q (main)
               \
                Y --- Z ---------------- M (大 merge commit)
  • 最后可能一次性解决大量冲突
  • PR 历史很乱(全是你的零散提交)

(2).定期 rebase + 最后 merge

复制代码
... --- W --- X --- P --- Q --- Y' --- Z' (你的分支,干净线性)
                                   \
                                    M (最终合并)
  • 开发过程顺畅,冲突早发现早解决
  • PR 历史清晰,review 友好
  • 主分支历史安全整洁

这就是协作开发中最常见、最推荐的 rebase 使用场景:在你的个人特性分支上,定期 rebase 到最新的 main,保持代码同步并让历史更漂亮

这样既充分发挥了 rebase 的优势,又完全避免了它的风险。

四、其它情况

1. 在提 Pull Request / Merge Request 前清理提交历史

  • 你在个人分支上写了 15 个提交,很多是"fix typo""test""oops 错了"
  • 提 PR 前想让 reviewer 看得舒服

做法

bash 复制代码
git rebase -i origin/main    # 交互式 rebase

在编辑器里你可以:

  • squash(合并)小提交成大提交
  • reword(修改)提交消息,让它更有意义
  • drop(删除)无用提交
  • reorder(重排)提交顺序

结果:PR 历史从 15 个乱提交变成 3~5 个清晰、有逻辑的提交,review 通过率大幅提升。

2. 解决冲突时逐步处理(比大 merge 更友好)

  • rebase 时如果有冲突,Git 会暂停在每个有冲突的提交上,让你一个个解决
  • 比一次性 merge 所有冲突更可控,尤其当主分支变化很大时

5.注意事项

不要对别人可能在开发的分支rebase,这会弄乱别人的提交历史,因为你rebase后前面的commit id会改变,别人继续开发会找不到历史提交。

相关推荐
wangkay882 分钟前
【Java 转运营】Day05:抖音新号起号:对标账号运营全指南
java·新媒体运营
乾元3 分钟前
构建你的个人「网络 AI 实验室」——硬件、模拟器与数据集清单
运维·网络·人工智能·网络协议·架构
情缘晓梦.7 分钟前
Linux指令和权限
linux·运维·服务器
ybdesire7 分钟前
Joern服务器启动后cpgqls-client结合python编程进行扫描
运维·服务器·python
爱码猿11 分钟前
Springboot结合thymeleaf模板生成pdf文件
spring boot·后端·pdf
大飞哥~BigFei16 分钟前
新版chrome浏览器安全限制及解决办法
java·前端·chrome·安全·跨域
中环留念16 分钟前
MySQL 索引全解析:索引类型、聚簇索引、回表与性能优化
sql·mysql·索引·图解
IT_陈寒19 分钟前
SpringBoot 3.2实战:5个性能优化技巧让你的应用提速50%
前端·人工智能·后端
{Hello World}23 分钟前
Java多态:三大条件与实现详解
java·开发语言