Git + Gerrit 第五课:rebase 变基与提交历史整理

本节目标

这一节学习 Git 中非常重要、但新手容易害怕的命令:rebase

你要理解这些问题:

复制代码
什么是 rebase?
rebase 和 merge 有什么区别?
为什么 Gerrit 工作流里经常使用 rebase?
rebase 冲突怎么解决?
什么时候可以 rebase,什么时候不要 rebase?

本节重点命令:

复制代码
git fetch
git rebase
git rebase --continue
git rebase --abort
git rebase --skip
git log --oneline --graph --all

1. rebase 是什么

rebase 中文常翻译为:

复制代码
变基

这个名字听起来复杂,但它的核心思想很简单:

复制代码
把你的提交移动到另一个分支的最新提交后面。

假设一开始主分支是:

复制代码
A --- B --- C    main

你从 C 创建了功能分支:

复制代码
A --- B --- C    main
           \
            D --- E    feature/login

后来别人往 main 合入了新提交:

复制代码
A --- B --- C --- F --- G    main
           \
            D --- E          feature/login

这时你的功能分支已经落后于 main

如果执行:

复制代码
git switch feature/login
git rebase main

结果会变成:

复制代码
A --- B --- C --- F --- G    main
                     \
                      D' --- E'    feature/login

注意这里变成了 D'E'

这表示:

复制代码
Git 把你的 D、E 两个提交重新放到了 main 最新提交 G 的后面。

2. rebase 的直观理解

可以把 rebase 理解成:

复制代码
我先把自己的改动临时拿下来。
然后把分支更新到目标分支最新位置。
最后再把自己的改动一个一个重新放上去。

过程像这样:

复制代码
1. 找到你和目标分支的共同祖先
2. 暂时取下你自己的提交
3. 把当前分支移动到目标分支最新提交
4. 重新应用你自己的每一个提交

所以 rebase 之后,提交历史会更像一条直线。

3. merge 和 rebase 的区别

假设现在历史是:

复制代码
A --- B --- C --- F --- G    main
           \
            D --- E          feature/login

3.1 使用 merge

执行:

复制代码
git switch feature/login
git merge main

结果可能是:

复制代码
A --- B --- C --- F --- G
           \           \
            D --- E --- M    feature/login

这里会产生一个合并提交 M

特点:

复制代码
保留真实分支历史。
会多一个 merge commit。
历史图可能更复杂。

3.2 使用 rebase

执行:

复制代码
git switch feature/login
git rebase main

结果可能是:

复制代码
A --- B --- C --- F --- G --- D' --- E'    feature/login

特点:

复制代码
提交历史更直线。
不会产生额外 merge commit。
会重写你本地分支上的提交。

4. 为什么 Gerrit 经常使用 rebase

Gerrit 很重视每一个 Change 的评审质量。

很多 Gerrit 团队希望提交历史像这样:

复制代码
A --- B --- C --- D --- E --- F

而不是这样:

复制代码
A --- B --- C --- M --- N
     \       \     /
      D --- E ----

原因是:

  • 历史更清楚

  • 每个 commit 更容易评审

  • 不容易产生无意义的 merge commit

  • 一个 Change 对应一个清晰的修改

  • Gerrit 页面上的 Patch Set 更容易理解

所以在 Gerrit 中,经常会看到这种流程:

复制代码
git fetch origin
git switch feature/login
git rebase origin/master
git push origin HEAD:refs/for/master

如果目标分支是 develop

复制代码
git fetch origin
git switch feature/login
git rebase origin/develop
git push origin HEAD:refs/for/develop

5. git fetch 是什么

在 rebase 前,经常先执行:

复制代码
git fetch origin

它的作用是:

复制代码
从远程仓库获取最新提交信息,但不自动合并到当前分支。

git pull 的区别:

复制代码
git fetch = 只下载远程更新,不动当前工作区
git pull  = fetch + merge 或 fetch + rebase

新手阶段建议多用:

复制代码
git fetch

再明确决定:

复制代码
git merge origin/master

或者:

复制代码
git rebase origin/master

这样你更清楚 Git 正在做什么。

6. rebase 的标准流程

假设你在 feature/login 分支开发,目标分支是 master

标准流程:

复制代码
git status
git fetch origin
git switch feature/login
git rebase origin/master

如果没有冲突,rebase 会直接完成。

然后你可以查看历史:

复制代码
git log --oneline --graph --all

最后推送到 Gerrit:

复制代码
git push origin HEAD:refs/for/master

7. rebase 时发生冲突怎么办

rebase 本质上是把你的提交一个一个重新应用到目标分支后面。

如果某个提交和目标分支冲突,Git 会停下来,让你解决。

你可能看到:

复制代码
CONFLICT (content): Merge conflict in readme.md
error: could not apply abc1234... 修改登录说明

意思是:

复制代码
Git 正在重新应用某个提交时发生冲突。
你需要解决冲突后继续 rebase。

标准流程:

复制代码
git status

# 手动修改冲突文件

git add readme.md
git rebase --continue

注意:

复制代码
rebase 冲突解决后,不是 git commit。
而是 git rebase --continue。

这是 rebase 和 merge 冲突处理的重要区别。

8. rebase 冲突解决流程

完整流程:

复制代码
git rebase origin/master

# 如果出现冲突
git status

# 打开冲突文件,删除冲突标记,整理成最终正确内容

git add 冲突文件
git rebase --continue

如果后面还有其他提交冲突,Git 可能会再次停下来。

你继续重复:

复制代码
git status
# 解决冲突
git add 冲突文件
git rebase --continue

直到 rebase 完成。

9. 放弃 rebase

如果 rebase 过程中发现问题太复杂,想回到 rebase 前的状态,可以执行:

复制代码
git rebase --abort

它的作用是:

复制代码
取消当前 rebase,回到 rebase 开始之前。

适合这些场景:

  • rebase 了错误的目标分支

  • 冲突太多,想重新整理

  • 不确定怎么解决

  • 想先备份当前分支

新手遇到不确定情况时,git rebase --abort 是一个很重要的安全按钮。

10. 跳过当前提交

rebase 过程中还有一个命令:

复制代码
git rebase --skip

它的作用是:

复制代码
跳过当前正在应用的提交。

注意:

复制代码
这个命令可能会丢掉当前提交的修改。
新手不要随便使用。

只有当你非常确定这个提交已经不需要了,才使用 --skip

11. rebase 会重写提交历史

这是 rebase 最重要的风险点。

rebase 后,原来的提交:

复制代码
D --- E

会变成:

复制代码
D' --- E'

虽然代码内容可能一样,但 commit id 已经变了。

原因是 commit id 和这些信息有关:

  • 提交内容

  • 父提交

  • 作者信息

  • 时间信息

  • commit message

rebase 改变了提交的父节点,所以 commit id 会变化。

所以要记住:

复制代码
rebase 会重写提交历史。

12. 什么时候可以 rebase

通常可以 rebase 的情况:

复制代码
你的本地功能分支
还没有被别人基于它继续开发
还没有作为公共分支给别人使用
你只是想把自己的提交更新到目标分支最新位置

例如:

复制代码
git switch feature/login
git rebase origin/master

这是常见且合理的。

13. 什么时候不要随便 rebase

不要随便 rebase 这些分支:

复制代码
main
master
develop
release
多人共享分支
已经推送并被别人基于其开发的分支

原因是:

复制代码
rebase 会改变提交历史。
如果别人已经基于旧历史开发,你重写历史会让别人很痛苦。

简单记忆:

复制代码
自己的本地分支可以 rebase。
公共共享分支不要随便 rebase。

14. Gerrit 中的 rebase 和 Patch Set

在 Gerrit 中,一个 Change 通常依靠 Change-Id 识别。

如果你 rebase 后重新推送:

复制代码
git push origin HEAD:refs/for/master

只要 commit message 里的 Change-Id 没变,Gerrit 通常会把它识别为同一个 Change 的新 Patch Set。

例如:

复制代码
实现登录功能

Change-Id: Iabc1234567890abcdef1234567890abcdef1234

rebase 后仍然保留这个 Change-Id,推送后会生成新的 Patch Set,而不是新的 Change。

15. rebase 后推送失败怎么办

如果你 rebase 过一个已经推送到普通远程分支的分支,再执行:

复制代码
git push

可能会失败。

因为远程分支历史和你本地历史不一致。

普通 Git 平台有时需要:

复制代码
git push --force-with-lease

但注意:

复制代码
不要随便 force push。
尤其不要对 main/master 使用 force push。

在 Gerrit 工作流里,你通常不是推送到普通分支,而是推送到:

复制代码
git push origin HEAD:refs/for/master

所以很多时候不需要直接 force push 到目标分支。

16. merge 与 rebase 怎么选择

可以这样理解:

场景 推荐
想保留完整分支合并历史 merge
想让提交历史更线性 rebase
本地个人功能分支同步主分支 rebase 常见
公共共享分支整合功能 merge 常见
Gerrit 单 Change 更新目标分支 rebase 常见

简单记忆:

复制代码
merge:把别人的历史合进来。
rebase:把自己的提交搬到别人最新历史后面。

17. 实战练习:体验 rebase

创建练习仓库:

复制代码
mkdir git-rebase-demo
cd git-rebase-demo
git init

创建初始提交:

复制代码
echo "base" > readme.txt
git add readme.txt
git commit -m "添加基础文件"

创建功能分支:

复制代码
git switch -c feature/login
echo "login feature" > login.txt
git add login.txt
git commit -m "添加登录功能"

切回主分支:

复制代码
git switch main

如果你的主分支叫 master

复制代码
git switch master

在主分支添加新提交:

复制代码
echo "main update" >> readme.txt
git add readme.txt
git commit -m "更新主分支说明"

查看历史:

复制代码
git log --oneline --graph --all

切回功能分支并 rebase:

复制代码
git switch feature/login
git rebase main

如果主分支叫 master

复制代码
git rebase master

再次查看历史:

复制代码
git log --oneline --graph --all

你会看到功能分支的提交被移动到了主分支最新提交后面。

18. 实战练习:制造 rebase 冲突

创建练习仓库:

复制代码
mkdir git-rebase-conflict-demo
cd git-rebase-conflict-demo
git init

创建初始文件:

复制代码
echo "version: base" > config.txt
git add config.txt
git commit -m "添加基础配置"

创建功能分支:

复制代码
git switch -c feature/login
echo "version: login feature" > config.txt
git add config.txt
git commit -m "修改登录配置"

切回主分支:

复制代码
git switch main

如果你的主分支叫 master

复制代码
git switch master

主分支也修改同一行:

复制代码
echo "version: main update" > config.txt
git add config.txt
git commit -m "修改主分支配置"

切回功能分支:

复制代码
git switch feature/login

执行 rebase:

复制代码
git rebase main

如果主分支叫 master

复制代码
git rebase master

这时应该会出现冲突。

19. 实战练习:解决 rebase 冲突

查看状态:

复制代码
git status

打开 config.txt,可能看到:

复制代码
<<<<<<< HEAD
version: main update
=======
version: login feature
>>>>>>> 修改登录配置

手动改成最终正确内容,例如:

复制代码
version: main update with login feature

然后执行:

复制代码
git add config.txt
git rebase --continue

如果还有冲突,继续解决。

如果完成,查看历史:

复制代码
git log --oneline --graph --all

20. rebase 和 amend 的关系

Gerrit 中常见组合是:

复制代码
git rebase origin/master
git commit --amend
git push origin HEAD:refs/for/master

但顺序要根据场景判断。

如果只是根据评审意见修改当前 Change:

复制代码
git add .
git commit --amend
git push origin HEAD:refs/for/master

如果目标分支已经更新,你需要先同步:

复制代码
git fetch origin
git rebase origin/master
git push origin HEAD:refs/for/master

如果 rebase 后还要修改提交信息或整理代码,再使用:

复制代码
git commit --amend

核心原则:

复制代码
保持 Change-Id 不变。
保持提交内容清晰。
不要制造无意义的 merge commit。

21. 常见错误

错误一:在公共分支上 rebase

不要随便对这些分支做 rebase:

复制代码
main
master
develop
release

尤其不要 rebase 后强推公共分支。

错误二:rebase 冲突后执行 git commit

rebase 冲突解决后应该执行:

复制代码
git rebase --continue

不是:

复制代码
git commit

错误三:不确定时乱用 --skip

git rebase --skip 可能丢掉当前提交。

新手不要随便用。

错误四:rebase 后 Change-Id 丢失

Gerrit 依赖 Change-Id 判断是否是同一个 Change。

如果 Change-Id 丢了,可能会生成新的 Change。

错误五:rebase 前工作区不干净

rebase 前先看:

复制代码
git status

最好保证:

复制代码
nothing to commit, working tree clean

22. 本节必须记住的命令

复制代码
git fetch origin
git rebase origin/master
git rebase --continue
git rebase --abort
git rebase --skip
git log --oneline --graph --all

对应含义:

复制代码
git fetch origin                  获取远程最新信息
git rebase origin/master          把当前分支提交搬到 origin/master 后面
git rebase --continue             解决冲突后继续 rebase
git rebase --abort                放弃本次 rebase
git rebase --skip                 跳过当前提交
git log --oneline --graph --all   查看提交历史图

23. 本节总结

这一节你学习了 rebase

  • rebase 是把你的提交重新放到目标分支最新提交后面

  • rebase 可以让提交历史更直线

  • merge 会保留合并历史,rebase 会重写本地提交

  • Gerrit 中经常使用 rebase 来保持 Change 清晰

  • rebase 冲突解决后要用 git rebase --continue

  • 不确定时可以用 git rebase --abort

  • 不要随便 rebase 公共分支

  • 不要随便 force push 公共分支

最重要的一句话:

复制代码
自己的本地功能分支可以 rebase,公共共享分支不要随便 rebase。

下一节建议学习:

复制代码
Git commit --amend、Gerrit Patch Set 与 Change-Id:如何根据评审意见更新同一个 Change。
相关推荐
大大大大晴天7 小时前
每天认识一个组件:数据治理Apache Atlas
大数据
数字新视界7 小时前
2026模块化机房选型指南:行业市场发展趋势、占有率与竞争梯队分析报告解析
大数据·人工智能·物联网·数据中心·微模块机房·模块化机房·冷通道
姜穆澜10 小时前
OneID 从 0 到 1 完整生产案例(四)
大数据
OsDepK10 小时前
项目快速Git至仓库(完整版)
大数据·git·elasticsearch·搜索引擎
合米AI SOP系统11 小时前
传统产线如何快速上马落地 AI 防错?合米科技 AI SOP 7天即可上线。
大数据·人工智能·科技
思录Echo11 小时前
什么决定具身智能的最终走向?多技术路线与落地现实辨析
大数据·人工智能
xiaohaiAIgeo11 小时前
【2026年】AI监控加行为分析守护实验室安全
大数据·人工智能·科普知识
林墨聊AIGC12 小时前
动漫AI视频创作工具在哪找到的?2026年最新动漫AI视频平台与软件指南
大数据·人工智能·ai作画·aigc·音视频
故七月13 小时前
告别 AI 时代品牌 “隐身”:万域智瞰 AI‑GEO,构建品牌大模型时代营销新基建
大数据·人工智能
数字孪生视频孪生14 小时前
三维实时重构异构底座 核工危化无感定位跨境轨迹一屏统揽
大数据·运维·人工智能·重构·架构