有些开发问题吧,说复杂不复杂,但真落到项目里,那就是分分钟能把人绕晕的类型。比如:到底是用 git rebase 还是 git merge?这两个小东西,听着像“你吃饭还是吃面”,看起来随便选,实际上选错了,可能就等着你的 commit 历史变成一锅炖。 作为一个搬砖型选手,我自己是经历过从“啥是 rebase 啊?”到“哎别急,先别 merge,我 rebase 一下”的转变过程,今天咱就来聊聊这个事儿。 一、merge 和 rebase 到底是啥? 简单说,它们干的事其实是一回事:把分支合并起来,只是方式不同。 👨🔧 git merge:平行世界的你,和你相遇了 我们先来看 merge,这个大家可能更熟一点:
git checkout feature
git merge main
这会把 main 的变更合并进 feature,同时生成一个新的合并 commit。假如 main 上已经更新了几个提交,feature 上你也写了一堆代码,那这时候 Git 会帮你合并两边的改动,解决冲突,搞定了就创建一个新的“我们俩终于在一起啦”的 commit。 🔍 优点: • 保留了分支历史,谁干了啥清清楚楚。 • 冲突一次性处理完,不改历史,适合团队协作。 🧨 缺点: • 历史看着乱糟糟,尤其合并太频繁,git log 像树杈一样分不清。 • 每次合并都多一个 commit,强迫症表示压力大。 🧙 git rebase:时空穿越者的最爱 然后是 rebase,有点像时光机。 git checkout feature
git rebase main
意思是,把 feature 分支的所有提交“搬运”到 main 最新的基础上,重新 replay 一遍。说白了,就是让你的提交看起来像是在 main 的最新版本上写的一样,好像你一直是跟在主线后面更新的,井井有条。 🔍 优点: • 历史清爽,提交线性,git log 清清爽爽。 • 看起来就像一个人干的,便于 review 和 debug。 🧨 缺点: • 会改历史记录,尤其你 rebase 的分支已经 push 给别人了,那就可能炸锅了。 • 冲突可能分好几轮处理,每个 commit 都得 resolve 一次。 二、什么时候用 merge?什么时候用 rebase? 我以前是 merge 派的,谁让我手稳怕误操作。但后来经历了一次代码审查地狱之后,我就明白了——用 merge 的 commit log,简直是史书未删节版,五花八门:
commit 9f8e3c9 (HEAD -> feature)
Merge branch 'main' into feature
commit e1b2a78
Add feature X
commit 11a9ac3
Fix typo in feature X
commit 7623aa2
Refactor code
领导看到都问我:“你这是在写小说还是在写代码?”😅 所以,我的策略如下: 场景 推荐操作 本地开发,还没 push 给别人 ✅ git rebase 已 push,跟团队协作 ✅ git merge 提交历史混乱,需要清理 ✅ git rebase -i(交互式) 发布前,把 feature 合到主线 看团队规范,偏好不同 三、代码示例 说这么多,不如上代码。我本地写了个 feature/login 的功能分支,结果后面 main 上更新了注册功能。 我先看下日志: git log --oneline --graph --all
结果像下面这样:
* c3a2b71 (main) Add register page
|\
| * 90c5d0d (feature/login) Add login validation
| * a91a9c0 Create login page
* | 8fe6c13 Fix UI bug
|/
* 3d95c77 Initial commit
🌲 树杈太多,看得我头大。 我想让提交清爽,怎么办? git checkout feature/login
git rebase main
然后处理一下冲突(如果有的话): # 编辑冲突文件
git add .
git rebase --continue
搞定后,git log --oneline 看起来就像你一直在 main 后面写代码一样,非常清晰。 四、团队协作怎么整?别让 rebase 炸了项目! 我曾经在团队里看见有人在公共分支上 rebase,结果所有人都:“我怎么 push 不上了?!” 原来他直接对已经共享的分支做了 rebase 然后 --force push。 这操作,相当于在大伙面前把地基挖了重铺……服务器都懵了🤯。 所以总结一句:对公共分支用 merge,对本地分支用 rebase。 如果你真的想对已经 push 的分支 rebase,一定要提前告诉团队,让大家停下来等你搞完。 之前有同事 push 上来一大串 commit:
commit 1: Try fix bug
commit 2: Try fix bug again
commit 3: Forgot a semicolon
commit 4: Finally fixed it
commit 5: Add log
commit 6: Remove log
commit 7: Add log again
我:???你这提交历史是调戏我呢还是调试自己? 于是我们规定每个人提交代码前都要: git rebase -i HEAD~N # N 是你最近提交的个数
这样你可以 squish 掉这些“调戏”历史,留下一个有尊严的提交,比如: commit: Fix login validation issue
这才是对 reviewer 最基本的尊重🥹。 最理想的方式是:
- 个人开发时用 rebase,保持线性历史;
- . 团队协作时用 merge,避免历史被改乱;
- 发布前可用 rebase 清理垃圾提交,但一定要再三确认是否已被共享;
- 代码审查前 rebase -i 整理一下,别让 reviewer 猜你的心理活动轨迹。
说到底,git merge 像是把两个部门合并,领导出来剪个彩,大家都知道谁是谁;
而 git rebase 像是你伪装成主线的员工,假装一切从未分开。 用得好,它们都是宝;用得不对,就容易变成互相甩锅的源头。 所以,咱程序员吧,不光得会写代码,还得会整理“人类文明史”——也就是 commit log 。