前言
事情的起因是这样的: 上周我在项目里用
git rebase
整理分支,结果把同事的提交"消失"了,虽然最后救回来了,但大家吓出一身冷汗。 这次事件让我彻底搞清楚了rebase
和merge
的区别,以及它们各自适合的场景。
一、先还原"事故现场"
假设我们有这样一个场景:
- 你在
feature
分支上开发新功能 - 同事在
main
分支上修了一个紧急 bug
提交历史长这样:
text
main: A --- B --- C (bug 修复)
\
feature: D --- E (你的新功能)
你用 git rebase main
bash
git checkout feature
git rebase main
这会变成这样:
text
main: A --- B --- C
\
feature: D' --- E'
看起来很整齐,但如果你本地的 feature
没有先拉同事的最新提交,或者在 rebase
过程里解决冲突时手滑丢掉了同事的改动,push 上去时可能直接覆盖掉远程历史,让同事的代码凭空消失。
这就是我当时踩的坑。
二、rebase 和 merge 到底有什么区别?
1. git merge ------ 历史完整,简单安全
- 会创建一个新的 merge commit
- 不会改动已有提交历史
- 适合多人协作、要保留所有分支的提交轨迹
示例:
bash
git checkout feature
git merge main
结果:
text
A --- B --- C ------ M (merge commit)
\ /
D --- E -----
特点:
- 提交历史可能"分叉"比较多,但安全
- 解决冲突只发生一次
2. git rebase ------ 历史干净,但会改动历史
- 会把你当前分支的提交"搬到"目标分支的最新提交之后
- 会生成新的提交 ID(即使内容相同)
- 适合自己本地分支整理历史,不要在公共分支上随意用
示例:
bash
git checkout feature
git rebase main
结果:
text
A --- B --- C --- D' --- E'
特点:
- 历史像一条直线,干净美观
- 改动的是提交历史,如果已经 push 过且别人基于它开发,容易引发冲突甚至丢代码
三、各自的安全使用场景
场景 | 推荐方式 | 原因 |
---|---|---|
本地分支开发,还没 push 给别人 | rebase | 整理历史,方便以后合并 |
拉取远程更新并保持历史干净 | pull --rebase | 避免多余的 merge commit |
已经 push,且有同事基于它开发 | merge | 避免改写历史导致冲突 |
大型团队的主分支合并 | merge | 保留历史,方便追溯 |
个人项目或短期功能分支 | rebase | 历史整洁,美观 |
四、如何避免 rebase 导致代码丢失?
-
不要在公共分支上 rebase (例如
main
、dev
) -
如果必须 rebase,先确保拉取远程最新代码:
bashgit fetch origin git rebase origin/main
-
解决冲突时仔细检查改动,确保同事的提交没有被覆盖
-
rebase 失败或出错时,可以用:
bashgit rebase --abort
-
养成推送前检查差异的习惯:
bashgit log --oneline --graph --decorate git diff
五、我的经验总结
merge
像是在账本上追加记录,不动旧账,安全可靠rebase
像是改账本,让账单更漂亮,但改错了可能账就乱了- 团队协作中,公共分支用 merge,本地分支用 rebase,基本就能避免大部分事故
结语
写在最后,这次的事故让我明白: Git 是个很宽容的工具,但对历史的操作必须敬畏。 代码丢失不可怕,可怕的是我们连为什么丢都不知道。 理解 merge
和 rebase
的底层行为,才能在团队里安全高效地用好它们。