Git Rebase 从入门到精通

💡 一句话理解 Rebase

Git Rebase 就是把你的提交”搬家”到另一个分支的最新位置,让提交历史看起来像一条直线。


🤔 Rebase vs Merge:核心区别

Merge 合并

流程说明:

  1. 从 B 创建 feature 分支
  2. feature 分支提交 C、D
  3. main 分支提交 E
  4. 将 feature 合并到 main,产生合并提交 M
  5. main 分支继续提交 F

特点:

  • ✅ 保留完整的历史记录
  • ✅ 能看到分支的合并点
  • ❌ 提交历史呈网状结构
  • ❌ 有额外的 merge commit

Rebase 变基

流程说明:

  1. 原本 feature 分支的 C、D 提交
  2. 被”搬家”到 E 之后,变成 C’、D’
  3. 形成一条线性的提交历史

特点:

  • ✅ 提交历史呈线性结构
  • ✅ 没有额外的 merge commit
  • ✅ 历史更清晰易读
  • ❌ 改变了提交历史(C 和 D 变成了 C’ 和 D’)
  • ⚠️ 不适合已推送到公共分支的提交

对比表格

特性 Merge Rebase
历史结构 网状(保留分支信息) 线性(扁平化)
提交历史 真实的时间顺序 逻辑上的顺序
Merge Commit
冲突解决 一次性解决所有冲突 逐个提交解决冲突
适用场景 公共分支、团队协作 个人分支、整理提交
风险 高(改变历史)

🎯 Rebase 的使用场景

1️⃣ 保持 Feature 分支最新

场景:你在开发功能分支时,main 分支有了新的提交。

流程说明:

  1. main 在 B 时创建 feature 分支
  2. feature 提交了 C、D(你的工作)
  3. main 提交了 E(别人的工作)
  4. 在 feature 上执行 rebase main
  5. 结果:C、D 被重新应用到 E 之后,变成 C’、D’

命令:

1
2
3
# 在 feature 分支上
git checkout feature
git rebase main

2️⃣ 整理本地提交历史

场景:你有很多零碎的提交,想在推送前整理成几个清晰的提交。

命令:

1
2
# 交互式 rebase 最近 5 个提交
git rebase -i HEAD~5

3️⃣ 修改历史提交信息

场景:发现之前的提交信息写错了。

1
2
3
4
5
# 修改最近的提交信息
git commit --amend

# 修改更早的提交信息
git rebase -i HEAD~3

4️⃣ 拆分或合并提交

场景:一个提交做了太多事,想拆成多个;或多个小提交想合并成一个。

1
2
# 交互式 rebase
git rebase -i HEAD~3

🔧 Rebase 基础操作

普通 Rebase

基本语法

1
2
3
4
5
6
# 将当前分支 rebase 到目标分支
git rebase <target-branch>

# 示例:将 feature 分支 rebase 到 main
git checkout feature
git rebase main

完整流程示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 1. 确保 main 是最新的
git checkout main
git pull origin main

# 2. 切换到 feature 分支
git checkout feature

# 3. 执行 rebase
git rebase main

# 4. 如果有冲突,解决后继续
git add .
git rebase --continue

# 5. 推送到远程(需要强制推送)
git push origin feature --force-with-lease

处理 Rebase 冲突

当 rebase 遇到冲突时:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# Git 会暂停并显示冲突文件
# 1. 查看冲突文件
git status

# 2. 手动编辑冲突文件,解决冲突
# <<<<<<< HEAD
# 当前分支的内容
# =======
# 要 rebase 的内容
# >>>>>>> commit-message

# 3. 标记冲突已解决
git add <conflicted-file>

# 4. 继续 rebase
git rebase --continue

# 如果想放弃 rebase
git rebase --abort

# 如果想跳过当前提交
git rebase --skip

Rebase 常用选项

1
2
3
4
5
6
7
8
9
10
11
# 保留 merge commits
git rebase --preserve-merges main

# 使用策略解决冲突
git rebase --strategy=recursive --strategy-option=theirs main

# Rebase 时自动 stash
git rebase --autostash main

# 详细模式
git rebase --verbose main

🎨 交互式 Rebase(Interactive Rebase)

交互式 rebase 是最强大的功能,可以让你完全控制提交历史

启动交互式 Rebase

1
2
3
4
5
6
7
8
# Rebase 最近 N 个提交
git rebase -i HEAD~N

# Rebase 到指定提交
git rebase -i <commit-hash>

# Rebase 到分支
git rebase -i main

交互式 Rebase 命令

当执行 git rebase -i 后,会打开编辑器显示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
pick 1a2b3c4 feat: 添加登录功能
pick 2b3c4d5 fix: 修复登录bug
pick 3c4d5e6 feat: 添加注册功能
pick 4d5e6f7 typo: 修复拼写错误
pick 5e6f7g8 feat: 完善注册功能

# Rebase 指令:
# p, pick = 使用该提交
# r, reword = 使用该提交,但修改提交信息
# e, edit = 使用该提交,但停下来修改
# s, squash = 使用该提交,但合并到前一个提交
# f, fixup = 类似 squash,但丢弃提交信息
# x, exec = 执行 shell 命令
# d, drop = 删除该提交

常用操作示例

1. 合并提交(Squash)

目标:将多个小提交合并成一个

1
2
3
4
5
6
7
8
9
# 修改前
pick 1a2b3c4 feat: 添加登录功能
pick 2b3c4d5 fix: 修复登录bug
pick 3c4d5e6 typo: 修复拼写错误

# 修改后
pick 1a2b3c4 feat: 添加登录功能
squash 2b3c4d5 fix: 修复登录bug
squash 3c4d5e6 typo: 修复拼写错误

保存后,Git 会让你编辑最终的提交信息。

2. 修改提交信息(Reword)

1
2
3
4
5
# 修改前
pick 1a2b3c4 feat: add login

# 修改后
reword 1a2b3c4 feat: add login

保存后,Git 会让你重新编辑提交信息。

3. 删除提交(Drop)

1
2
3
4
5
6
7
8
9
# 修改前
pick 1a2b3c4 feat: 添加登录功能
pick 2b3c4d5 这是一个错误的提交
pick 3c4d5e6 feat: 添加注册功能

# 修改后
pick 1a2b3c4 feat: 添加登录功能
drop 2b3c4d5 这是一个错误的提交
pick 3c4d5e6 feat: 添加注册功能

4. 编辑提交(Edit)

1
2
3
4
# 修改后
pick 1a2b3c4 feat: 添加登录功能
edit 2b3c4d5 需要修改的提交
pick 3c4d5e6 feat: 添加注册功能

Git 会在该提交处停下来,让你修改:

1
2
3
4
5
6
7
8
9
# 修改文件
# ...

# 修改提交
git add .
git commit --amend

# 继续 rebase
git rebase --continue

5. 拆分提交(Split)

1
2
# 标记为 edit
edit 1a2b3c4 需要拆分的大提交

然后:

1
2
3
4
5
6
7
8
9
10
11
12
13
# Git 停在该提交
# 1. 撤销该提交但保留更改
git reset HEAD^

# 2. 分别提交
git add file1.js
git commit -m "feat: 实现功能 A"

git add file2.js
git commit -m "feat: 实现功能 B"

# 3. 继续 rebase
git rebase --continue

6. 调整提交顺序

1
2
3
4
5
6
7
8
9
# 修改前
pick 1a2b3c4 提交 A
pick 2b3c4d5 提交 B
pick 3c4d5e6 提交 C

# 修改后(调换顺序)
pick 3c4d5e6 提交 C
pick 1a2b3c4 提交 A
pick 2b3c4d5 提交 B

⚠️ Rebase 的黄金法则

🚫 永远不要 Rebase 公共分支

黄金法则:不要 rebase 已经推送到公共仓库的提交!

为什么?

问题说明:

  1. 开发者 A 推送提交 [A → B → C] 到远程
  2. 开发者 B 拉取了这些提交
  3. 开发者 A 执行 rebase,改变了历史,变成 [A → B’ → C’]
  4. 开发者 A 强制推送新的历史
  5. 开发者 B 尝试推送时,因为 B 和 B’ 是不同的提交(SHA 不同),导致历史冲突

**后果

  • 😱 其他人的提交历史会混乱
  • 🔥 可能导致代码丢失
  • 💥 团队协作困难

✅ 安全的 Rebase 场景

  1. 个人开发分支(尚未推送)

    1
    2
    3
    # ✅ 安全
    git checkout feature/my-work
    git rebase main
  2. 已推送但只有你在用的分支

    1
    2
    # ✅ 可以,但要用 --force-with-lease
    git push origin feature/my-work --force-with-lease
  3. 本地整理提交后才推送

    1
    2
    3
    # ✅ 推荐
    git rebase -i HEAD~5 # 本地整理
    git push origin feature/new # 首次推送

❌ 危险的 Rebase 场景

  1. Main/Master 分支

    1
    2
    3
    # ❌ 危险!绝对不要这样做
    git checkout main
    git rebase feature
  2. 多人协作的分支

    1
    2
    3
    # ❌ 危险!会影响其他人
    git checkout develop
    git rebase -i HEAD~10
  3. 已经被其他分支合并的提交

    1
    2
    # ❌ 危险!会导致重复的提交
    git rebase main # 如果这个分支已被其他分支引用

🛠️ Rebase 实战技巧

1. 使用 –force-with-lease 而不是 –force

1
2
3
4
5
6
7
8
# ❌ 危险:会覆盖远程的任何更改
git push --force

# ✅ 安全:只有在远程没有新提交时才会推送
git push --force-with-lease

# ✅ 更安全:指定期望的远程状态
git push --force-with-lease=origin/feature:refs/heads/feature

2. 配置默认的 Rebase 行为

1
2
3
4
5
6
7
8
# Pull 时自动使用 rebase 而不是 merge
git config --global pull.rebase true

# 只对当前仓库配置
git config pull.rebase true

# 或者使用 preserve 保留 merge commits
git config --global pull.rebase preserve

3. 自动 Stash 在 Rebase 前

1
2
3
4
5
# 配置自动 stash
git config --global rebase.autoStash true

# 现在 rebase 会自动保存和恢复未提交的更改
git rebase main

4. 使用 Rebase 更新 Feature 分支

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#!/bin/bash
# update-feature.sh - 更新 feature 分支脚本

FEATURE_BRANCH=$(git branch --show-current)
BASE_BRANCH=${1:-main}

echo "🔄 更新 $FEATURE_BRANCH$BASE_BRANCH..."

# 1. 保存当前工作
git stash

# 2. 更新 base 分支
git checkout $BASE_BRANCH
git pull origin $BASE_BRANCH

# 3. 切回 feature 分支并 rebase
git checkout $FEATURE_BRANCH
git rebase $BASE_BRANCH

# 4. 恢复工作
git stash pop

echo "✅ 更新完成!"

使用:

1
2
chmod +x update-feature.sh
./update-feature.sh main

5. 整理提交历史模板

创建一个交互式 rebase 的别名:

1
2
3
4
5
6
7
8
9
10
# 添加到 ~/.gitconfig
[alias]
# 整理最近 N 个提交
cleanup = "!f() { git rebase -i HEAD~${1:-5}; }; f"

# Squash 所有提交到一个
squash-all = "!f() { git reset $(git commit-tree HEAD^{tree} -m \"${1:-Initial commit}\"); }; f"

# 整理 feature 分支
tidy = "!git rebase -i $(git merge-base HEAD main)"

使用:

1
2
3
4
5
6
7
8
# 整理最近 3 个提交
git cleanup 3

# 整理整个 feature 分支
git tidy

# 把所有提交压缩成一个
git squash-all "feat: 实现完整功能"

6. 修复错误的 Rebase

如果 rebase 搞砸了,使用 reflog 恢复:

1
2
3
4
5
6
7
8
9
10
11
12
13
# 1. 查看操作历史
git reflog

# 输出示例:
# a1b2c3d HEAD@{0}: rebase finished
# e4f5g6h HEAD@{1}: rebase: 提交 C
# i7j8k9l HEAD@{2}: checkout: moving from feature to main

# 2. 回到 rebase 前的状态
git reset --hard HEAD@{2}

# 或者回到具体的 commit
git reset --hard e4f5g6h

7. 批量处理提交

使用 exec 命令在每个提交后执行操作:

1
git rebase -i HEAD~5

在编辑器中:

1
2
3
4
5
6
pick 1a2b3c4 提交 1
exec npm test
pick 2b3c4d5 提交 2
exec npm test
pick 3c4d5e6 提交 3
exec npm test

这会在每个提交后运行测试,确保每个提交都是可工作的。


📊 Rebase vs Merge:选择指南

使用 Merge 的场景

✅ 合并到 main/master 分支
✅ 多人协作的 develop 分支
✅ 需要保留完整的分支历史
✅ 重要的功能发布
✅ 开源项目的 PR 合并

使用 Rebase 的场景

✅ 更新个人 feature 分支
✅ 整理本地提交历史
✅ 保持线性的提交历史
✅ 删除/修改错误的提交
✅ 推送前清理提交


🎯 最佳实践

1. 建立团队规范

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# Git Rebase 团队规范

## ✅ 允许 Rebase

- 个人开发的 feature 分支
- 尚未推送的本地提交
- 只有自己在使用的分支

## ❌ 禁止 Rebase

- main/master 分支
- develop 分支
- 已经合并到其他分支的提交
- 其他人正在基于你的分支开发

## 推荐工作流

1. 从 main 创建 feature 分支
2. 本地开发时可以随意提交
3. 推送前使用 `git rebase -i` 整理提交
4. 首次推送到远程
5. 如需更新,rebase main 分支
6. 使用 `--force-with-lease` 推送
7. 最终通过 PR 合并到 main(使用 merge)

2. 提交历史整理 Checklist

推送前检查清单:

  • 是否有无意义的提交信息(如 “wip”, “test”)?
  • 是否有多个提交做了同样的事情?
  • 提交是否符合 Conventional Commits 规范?
  • 每个提交是否是独立且完整的?
  • 是否需要拆分过大的提交?
  • 是否需要调整提交顺序?

3. Rebase 工作流示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
# 完整的 feature 开发流程

# 1. 创建 feature 分支
git checkout -b feature/user-profile main

# 2. 开发过程中随意提交
git commit -m "wip"
git commit -m "add avatar"
git commit -m "fix bug"
git commit -m "add bio"

# 3. 定期从 main 更新
git fetch origin
git rebase origin/main

# 4. 开发完成后,整理提交历史
git rebase -i HEAD~4

# 在编辑器中整理:
# pick xxx add avatar
# squash xxx fix bug
# pick xxx add bio
# drop xxx wip

# 5. 修改提交信息,符合规范
# feat: add user avatar upload
# feat: add user bio section

# 6. 最后一次从 main 更新
git rebase origin/main

# 7. 推送到远程
git push origin feature/user-profile --force-with-lease

# 8. 创建 PR,使用 merge 合并到 main

🐛 常见问题与解决

Q1: Rebase 过程中遇到太多冲突怎么办?

解决方案:

1
2
3
4
5
6
7
8
9
10
11
12
# 方案 1:中止 rebase,使用 merge
git rebase --abort
git merge main

# 方案 2:使用 rerere (reuse recorded resolution)
git config --global rerere.enabled true
# Git 会记住你如何解决冲突,下次自动应用

# 方案 3:减少 rebase 的提交数量
# 先 squash 本地提交,再 rebase
git rebase -i HEAD~10 # 先合并提交
git rebase main # 再更新分支

Q2: 如何撤销已经推送的 Rebase?

1
2
3
4
5
6
7
8
# 1. 找到 rebase 前的提交
git reflog

# 2. 重置到那个提交
git reset --hard HEAD@{n}

# 3. 强制推送(警告:会覆盖远程)
git push origin feature --force-with-lease

Q3: Rebase 后为什么推送失败?

Rebase 改变了提交的 SHA,远程仓库会拒绝:

1
2
3
4
5
6
# ❌ 普通 push 会失败
git push origin feature
# ! [rejected] feature -> feature (non-fast-forward)

# ✅ 使用 force-with-lease
git push origin feature --force-with-lease

Q4: 如何 Rebase 特定的几个提交?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 方案 1:使用 cherry-pick
git cherry-pick <commit1> <commit2> <commit3>

# 方案 2:使用 rebase --onto
# 将 C 到 F 的提交 rebase 到 main
git rebase --onto main C F

# 示例:
# A - B - C - D - E - F (feature)
# \
# G - H (main)
# 结果:
# A - B - C (保持不变)
# \
# G - H - D' - E' - F'

Q5: 团队成员不小心 rebase 了公共分支怎么办?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 1. 找到 rebase 前的提交(使用 reflog 或从其他人那里获取)
git reflog
# 或
git fetch origin
git log origin/feature@{1}

# 2. 创建恢复分支
git branch feature-backup origin/feature@{1}

# 3. 强制重置公共分支
git push origin feature-backup:feature --force

# 4. 通知团队成员重新同步
# 其他人需要:
git fetch origin
git reset --hard origin/feature

📚 延伸阅读


🎓 总结

核心要点

  1. Rebase 的本质:重新应用提交到新的基础上
  2. 主要用途:整理提交历史、保持线性历史
  3. 黄金法则:不要 rebase 公共分支
  4. 安全推送:使用 --force-with-lease 而不是 --force
  5. 交互式 Rebase:整理提交的最强工具

快速参考

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 基本 rebase
git rebase <branch>

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

# 继续/中止
git rebase --continue
git rebase --abort

# 安全推送
git push --force-with-lease

# 恢复错误
git reflog
git reset --hard HEAD@{n}

何时使用

场景 使用 Rebase 使用 Merge
更新个人分支
整理提交历史
合并到 main
多人协作分支
功能发布

记住:Rebase 是一把锋利的刀,用得好能让项目历史清晰优雅,用不好会给团队带来灾难。🔪


Happy Rebasing! 🚀

作者

Ailln

发布于

2025-10-27

更新于

2025-10-29

许可协议

评论