2. Git Rebase

简单粗暴地说,git rebase把你的整个特性分支移动到主分支的最新提交之上。它会为原特性分支的每个提交创建全新的提交。

让我们通过实际操作理解 rebase 的工作原理:

git clone https://github.com/yourusername/yourrepo.git
git branch testBranch1
git branch testBranch2

testBranch1 分支创建新文件并提交:

git add .
git commit -m "feat: 添加新功能模块"
git push --set-upstream origin testBranch1
git log

执行后输出如下(示意图):

commit 3a4b5c6d (HEAD -> testBranch1, origin/testBranch1)
Author: Your Name <youremail@example.com>
Date:   Mon May 16 10:00:00 2022 +0800

    feat: 添加新功能模块

现在尝试将此分支 rebase 到 main 分支:

git rebase main

由于 main 分支没有新提交,输出如下:

Current branch testBranch1 is up to date.

接下来将特性分支合并到主分支:

git checkout main
git merge testBranch1
git push
git log

输出显示特性分支的提交 ID 保持不变(类似快进合并):

commit 3a4b5c6d (HEAD -> main, origin/main, origin/testBranch1, testBranch1)
Author: Your Name <youremail@example.com>
Date:   Mon May 16 10:00:00 2022 +0800

    feat: 添加新功能模块

现在处理 testBranch2 分支(它缺少 testBranch1 的提交):

git checkout testBranch2
git add .
git commit -m "fix: 修复登录问题"
git push --set-upstream origin testBranch2
git log

输出:

commit 7e8f9a0b (HEAD -> testBranch2, origin/testBranch2)
Author: Your Name <youremail@example.com>
Date:   Mon May 16 11:00:00 2022 +0800

    fix: 修复登录问题

执行 rebase 操作:

git rebase main

由于 main 已有新提交,输出变为:

Successfully rebased and updated refs/heads/testBranch2.

现在合并到主分支,注意rebase 前后提交 ID 会改变

git checkout main
git merge testBranch2
git push
git log

输出显示新提交 ID:

commit c1d2e3f4 (HEAD -> main, origin/main)
Author: Your Name <youremail@example.com>
Date:   Mon May 16 11:00:00 2022 +0800

    fix: 修复登录问题

查看线性提交历史:

git log --graph --oneline

输出(示意图):

* c1d2e3f4 (HEAD -> main, origin/main) fix: 修复登录问题
* 3a4b5c6d feat: 添加新功能模块
* 1a2b3c4d (origin/main) init: 初始提交

3. Git Merge

git merge找到两个分支的共同基提交,然后将两个分支的提交序列应用到基提交上完成合并。

创建新仓库和特性分支:

git clone https://github.com/yourusername/yourrepo.git
git branch testBranch1
git branch testBranch2

testBranch1 创建文件并提交:

git add .
git commit -m "feat: 添加用户管理"
git push --set-upstream origin testBranch1
git log

输出:

commit 5f6g7h8i (HEAD -> testBranch1, origin/testBranch1)
Author: Your Name <youremail@example.com>
Date:   Mon May 16 12:00:00 2022 +0800

    feat: 添加用户管理

合并到主分支:

git checkout main
git merge testBranch1
git push
git log

输出(HEAD 指向 main):

commit 5f6g7h8i (HEAD -> main, origin/main, origin/testBranch1, testBranch1)
Author: Your Name <youremail@example.com>
Date:   Mon May 16 12:00:00 2022 +0800

    feat: 添加用户管理

现在处理 testBranch2(主分支已有新提交):

git checkout testBranch2
git add .
git commit -m "docs: 更新API文档"
git push --set-upstream origin testBranch2
git log

输出:

commit 9j0k1l2m (HEAD -> testBranch2, origin/testBranch2)
Author: Your Name <youremail@example.com>
Date:   Mon May 16 13:00:00 2022 +0800

    docs: 更新API文档

合并到主分支:

git checkout main
git merge testBranch2
git log

输出显示新增合并提交:

commit n3o4p5q6 (HEAD -> main, origin/main)
Merge: 5f6g7h8i 9j0k1l2m
Author: Your Name <youremail@example.com>
Date:   Mon May 16 13:30:00 2022 +0800

    Merge branch 'testBranch2'

commit 9j0k1l2m (origin/testBranch2, testBranch2)
Author: Your Name <youremail@example.com>
Date:   Mon May 16 13:00:00 2022 +0800

    docs: 更新API文档

commit 5f6g7h8i
Author: Your Name <youremail@example.com>
Date:   Mon May 16 12:00:00 2022 +0800

    feat: 添加用户管理

查看分支图:

git log --graph --oneline

输出(示意图):

*   n3o4p5q6 (HEAD -> main, origin/main) Merge branch 'testBranch2'
|\  
| * 9j0k1l2m (testBranch2, origin/testBranch2) docs: 更新API文档
* | 5f6g7h8i feat: 添加用户管理
|/  
* 1a2b3c4d init: 初始提交

4. 使用场景对比

选择 rebase 还是 merge 取决于具体需求:

  • 需要线性历史时:使用 rebase(适合个人分支或特性开发)
  • 多人协作时:谨慎使用 rebase,特别是已推送到公共仓库的提交
  • 保留完整合并信息时:使用 merge(适合团队协作和代码审查)

⚠️ 踩坑警告:对公共仓库的已推送提交执行 rebase 会导致提交 ID 改变,可能造成其他开发者的分支与你的分支产生分歧,引发合并冲突。

5. 总结

本文深入对比了 Git 中两个核心分支整合操作:

  • Rebase:重写提交历史,创建线性提交链
  • Merge:保留真实提交历史,生成合并提交

作为有经验的开发者,理解这两种操作的本质差异能帮你:

  1. 根据项目需求选择合适的分支策略
  2. 避免团队协作中的历史污染问题
  3. 更高效地管理代码变更流程

记住:没有绝对的好坏,只有场景的适配。在私有分支大胆 rebase,在公共分支谨慎 merge。


原始标题:Difference Between git merge and rebase