「rebase 让历史更干净」只说对了一半。真正需要判断的是:这次合并要不要保留「这些提交是并行开发的」这一事实。答案不同,命令就不同。

git rebase 还是 merge:提交历史、冲突处理与误操作救援 示意图

merge 保留分叉,rebase 重写线性

git switch main
git merge --no-ff feature/cart

--no-ff 强制生成合并提交,即使可以快进。长期分支通常这样合并,因为合并点本身就是「这个需求何时进入 main」的记录。

git switch feature/cart
git rebase main

rebase 的做法是把 feature 上的提交逐个「摘下来」,在 main 的新位置重新提交一遍。内容相同,但 commit hash 全部改变——这一点是所有事故的根源。

冲突处理:merge 一次,rebase 可能多次

merge 的冲突只在合并那一次解决;rebase 因为逐个重放提交,同一个文件的冲突可能在多个提交里反复出现。处理流程固定为三步:

git add src/Cart.php
git rebase --continue

git rebase --abort

如果只是想把分支压成一个提交再合并,交互式 rebase 更省事:git rebase -i main,把除第一条外的 pick 改成 squash,在编辑器里重写提交信息即可。

唯一不能违反的规则

已经被别人拉取过的提交不要 rebase。重写公共历史会让所有人的本地分支与远端分叉,随后的 push 会互相覆盖。

只在自己的功能分支上 rebase 是安全的。判断标准很简单:这条分支只有你在用,就随便改;只要有人基于它开发,就改用 merge。

push 被拒绝时不要用 -f

git push --force
git push --force-with-lease

前者可能覆盖别人刚推上来的提交;后者会检查远端分支是否仍指向上次 fetch 到的提交,别人推过新内容就直接拒绝。养成只用 --force-with-lease 的习惯,能避免绝大多数「同事的代码不见了」。

误操作救援:reflog

rebase 做错、分支被 reset 掉,几乎都能救回来,因为 Git 不会立刻删除提交对象:

git reflog
git switch -c rescue HEAD@{6}

先拉一个新分支再检查内容,确认无误后再决定是否移动原分支,比直接 reset 上去安全得多。默认 90 天后记录才会被清理,短时间内的误操作都还有救。

小结

日常开发用 rebase 同步主干、保持功能分支线性;合并进长期分支时用 merge 留下记录;已经推送过的分支只用 force-with-lease。分支怎么划分,可以配合分支策略选型一起看。