Git Rebase - 变基操作详解

深入理解 git rebase,学习如何整理提交历史,以及 rebase 与 merge 的区别

⏱️ 25 分钟📊 进阶📅 2024/1/10
rebase变基历史整理

简介

git rebase 是 Git 中最强大但也最容易误用的命令之一。它可以:

  • 📝 整理提交历史
  • 🧹 清理混乱的提交记录
  • 🔀 创建线性的项目历史
  • ✨ 让历史更易读

但要小心使用!

Rebase vs Merge

Merge 的方式

main:    A --- B --- C --- D
              ↑           ↗
feature:      └─ E --- F

合并后:

main:    A --- B --- C --- D --- M
              ↑           ↗     ↗
feature:      └─ E ----- F ----┘

特点:保留完整历史,有合并提交

Rebase 的方式

main:    A --- B --- C --- D
              ↑
feature:      └─ E --- F

Rebase 后:

main:    A --- B --- C --- D
                            ↖
feature:                     E' --- F'

特点:线性历史,没有合并提交

基本 Rebase

将 feature 分支 rebase 到 main

# 在 feature 分支上
git checkout feature
git rebase main

这会:

  1. 找到共同祖先
  2. 取出 feature 的所有提交
  3. 将它们一个个应用到 main 最新提交之后

解决冲突

如果遇到冲突:

# 1. 解决冲突
# 编辑冲突文件

# 2. 标记为已解决
git add conflicted-file.txt

# 3. 继续 rebase
git rebase --continue

放弃 rebase:

git rebase --abort

交互式 Rebase

最强大的功能!可以修改历史提交。

git rebase -i HEAD~3

会打开编辑器:

pick f7f3f6d 提交1
pick 310154e 提交2
pick a5f4a0d 提交3

# Commands:
# p, pick = 使用提交
# r, reword = 使用提交,但修改提交信息
# e, edit = 使用提交,但停下来修改
# s, squash = 使用提交,但合并到前一个提交
# f, fixup = 类似 squash,但丢弃提交信息
# d, drop = 删除提交

常用操作

1. 合并多个提交

pick f7f3f6d 添加功能A
squash 310154e 修复功能A的bug
squash a5f4a0d 完善功能A

三个提交会合并成一个。

2. 修改提交信息

pick f7f3f6d 旧的提交信息
reword 310154e 需要改的提交
pick a5f4a0d 另一个提交

3. 重新排序提交

pick a5f4a0d 提交3
pick f7f3f6d 提交1
pick 310154e 提交2

4. 删除提交

pick f7f3f6d 保留的提交
drop 310154e 要删除的提交
pick a5f4a0d 保留的提交

黄金法则

⚠️ 永远不要 rebase 已经推送到公共分支的提交!

原因

  • Rebase 会改变提交的 SHA-1
  • 其他人的工作会受影响
  • 会导致混乱和冲突

安全使用

  • ✅ 自己的本地分支
  • ✅ 还没推送的提交
  • ✅ 个人的 feature 分支
  • ❌ main/master 分支
  • ❌ 已推送的公共分支
  • ❌ 其他人正在使用的分支

实战场景

场景 1: 整理本地提交

# 你有 5 个混乱的提交
git log --oneline
# a1b2c3d 修复拼写错误
# d4e5f6g 添加功能
# g7h8i9j 又修复了个bug
# j0k1l2m 完善功能
# m3n4o5p WIP

# 交互式 rebase
git rebase -i HEAD~5

# 整理成清晰的提交
pick d4e5f6g 添加功能
squash j0k1l2m 完善功能
drop m3n4o5p WIP
fixup g7h8i9j 又修复了个bug
fixup a1b2c3d 修复拼写错误

场景 2: 让 PR 保持最新

# 你的 feature 分支落后了
git checkout feature
git fetch origin
git rebase origin/main

# 解决冲突(如果有)
# ...

# 强制推送(因为改变了历史)
git push --force-with-lease

--force-with-lease--force 更安全,如果远程有你不知道的提交会拒绝推送。

场景 3: 修改历史中的某个提交

# 找到要修改的提交
git log --oneline

# 交互式 rebase
git rebase -i abc123^

# 标记为 edit
edit abc123 要修改的提交
pick def456 后续提交

# Git 会停在那个提交
# 做你的修改
git add modified-file.txt
git commit --amend

# 继续
git rebase --continue

Rebase vs Merge:何时使用?

使用 Merge

  • ✅ 合并公共分支
  • ✅ 保留完整历史
  • ✅ 团队协作的主分支
  • ✅ 发布分支

使用 Rebase

  • ✅ 整理个人分支
  • ✅ 让历史更清晰
  • ✅ 同步远程更新
  • ✅ 准备 PR 前整理提交

推荐工作流

# 开发过程中,经常 rebase 主分支
git checkout feature
git rebase main

# 开发完成,整理提交
git rebase -i main

# 合并到主分支时用 merge
git checkout main
git merge feature

常见问题

Q1: Rebase 中断了,不知道怎么办?

# 查看状态
git status

# 放弃 rebase
git rebase --abort

# 或解决冲突后继续
git add .
git rebase --continue

Q2: 不小心 rebase 了公共分支?

# 找回原来的提交
git reflog
git reset --hard HEAD@{n}

Q3: Rebase 后推送被拒绝?

# 使用 force-with-lease
git push --force-with-lease

小结

  • Rebase: 重新应用提交,创建线性历史
  • 交互式 Rebase: 整理、合并、修改提交
  • 黄金法则: 不要 rebase 公共分支
  • vs Merge: Rebase 更清晰,Merge 更安全
  • 工作流: 本地用 rebase,公共用 merge

强大但需谨慎使用!

这篇教程有帮助吗?