Git 合并分支到底有几种写法?3 种 merge 方式一次讲清

编程狮(w3cschool.cn) 2026-10-06 07:03:49 浏览数 (14)
反馈

Git 合并分支三种方式对比

你和小伙伴各自在 feature 分支上改代码,最后要把两条线的改动合到一起,却分不清该用 merge 还是 rebase?Git 合并分支的核心答案是:最常见的有三种写法——快进合并(fast-forward)、三方合并(--no-ff 保留合并提交)、以及变基合并(rebase 再 fast-forward),选哪个取决于你想不想保留“合并历史”。本文基于 Git 2.4x 验证,把三种写法的命令、提交图变化和适用边界讲透,并附踩坑清单。看完你就能按团队约定选对写法。今天这篇文章,编程狮就把这块讲透。

先看结论

你的目标 该用的写法 一句话命令
不保留合并提交、历史线性 快进合并 git merge 分支名
必须保留合并节点 三方合并 git merge --no-ff 分支名
历史干净、像没分过叉 变基合并 git rebase 主干分支

💡 小提示:很多团队约定“个人分支用 rebase、集成分支用 --no-ff merge”,目的是既保留发布节点又让历史好读。

一、Git 合并分支到底在做什么

Git 合并分支,本质是把两个分支的提交历史连到一处。Git 会先找到“共同祖先提交”,再决定用哪种策略把差异合起来。理解这一点,后面三种写法就只是“连法不同”。

⚠️ 注意:合并前先 git status 确认工作区干净。如果有未提交的改动,Git 可能拒绝合并或触发意料外的冲突处理。

先看最基础的 git merge 命令:

# 切换到要并入的目标分支(通常是主干)
git checkout main

# 把 feature 分支的改动合并进来
git merge feature

上面这段做的是:在 main 分支上执行 git merge,Git 会自动挑选合并策略。如果你还不熟悉分支基础,可以先过一遍 Git 教程,把分支与提交的骨架铺平。

二、方案一:快进合并(fast-forward)

快进合并发生在“目标分支没有新提交、只是落后于待合并分支”时。Git 不做新提交,只是把 main 的指针直接快进到 feature 的末端,历史变成一条直线。

# main 落后于 feature 且中间无分叉时,默认就是快进
git merge feature

# 想强制快进(不行就报错,避免意外产生合并提交)
git merge --ff-only feature

上面这条 git merge --ff-only feature 的优点是历史绝对线性、好回溯;代价是丢失了“曾经分叉合并过”的痕迹。适合个人功能分支合回本地主干的场景。

main 指针从祖先快进到 feature 末端的提交图变化

💡 小提示:常用命令记不住时,Git 速查手册 可以把 merge / rebase 的参数摊开对照着看。

三、方案二:三方合并(--no-ff 保留合并提交)

当目标分支自己也有新提交、两边分了叉,Git 会做“三方合并”:取共同祖先、两边末端三个点,生成一个全新的“合并提交”。加 --no-ff 可以强制即使能快进也要保留这个合并节点。

# 即使能快进也生成一个合并提交,保留分叉痕迹
git merge --no-ff feature -m "合并 feature 分支"

# 查看提交图,合并提交会显示两个父节点
git log --graph --oneline --decorate -n 10

三方合并的代价是多出一个合并提交,但好处明显:发布时你能一眼看到“这一批改动从哪个分支合进来”。这也是很多公司集成分支的强制约定。

四、方案三:变基合并与横向对比

变基合并的思路不同:它先把 feature 的提交“挪到” main 末端之后,再快进,最终结果是完全线性的历史,仿佛从没分过叉。

# 在 feature 分支上,把基底接到 main 最新提交之后
git checkout feature
git rebase main

# 再回到 main 快进合入
git checkout main
git merge feature

上面 rebase 之后 git merge 必然是快进,因为基底已经对齐。注意 rebase 会改写提交哈希,所以“已推送到远程、别人可能基于它工作”的分支禁止 rebase。

把三种写法摆在一起对比:

方案 适用场景 优点 代价
快进合并 目标分支无新提交 历史线性、零噪音 丢失合并痕迹
三方合并 需保留合并节点 发布可追溯 多一个合并提交
变基合并 个人分支追求整洁 历史最干净 改写哈希、不能用于公共分支

快进 / 三方 / 变基三种合并方式对比

五、踩坑清单

把最容易卡住的三点列出来,每条给现象、原因、修复:

  • 现象:合并后历史里找不到“合入”记录。 原因:默认走了快进,没产生合并提交。修复:用 git merge --no-ff 分支名 强制保留节点。
  • 现象:rebase 中途一堆冲突,处理到怀疑人生。 原因:feature 提交太多、和 main 改动重叠。修复:先 git rebase --abort 退出,把大分支拆小,或改用 --no-ff merge。
  • 现象:push 被拒,提示 non-fast-forward。 原因:本地和远程分支分了叉,需要先把远程改动合并进来再推。修复:git pull --rebase 对齐后再 git push。

动手验证清单(照着做)

  • 前置安装:先确认本机已安装 Git,运行 git --version 检查版本;没装先去官网下载安装包,再配置好命令行环境。
  • 配置身份:用 git config --global user.name 和 git config --global user.email 配置提交身份,否则首次提交会直接报错。
  • 操作命令:按上面的方案一或方案二,依次执行对应的 merge 命令。
  • 预期结果(未在本机执行):git log --oneline --graph 能看到两条分支的提交汇合;快进时是一条直线,三方合并会多出一个 merge 提交。
  • 运行验证:git status 检查工作区是否干净,确认没有未提交的改动残留。
  • 失败处理:若出现冲突,按提示打开冲突文件、保留正确内容后 git add 再 git commit 完成合并;想反悔可用 git merge --abort 回到合并前。
  • 修复补丁:提交信息写错就走 amend 改掉,分支选错就 git reset --hard ORIG_HEAD 撤销刚才的合并动作。

总结

Git 合并分支的三种写法对应三种“历史观”:快进合并追求极简线性、三方合并保留可追溯的合并节点、变基合并产出最干净的线性历史。记住一条红线——已经推送到远程的公共分支不要 rebase,因为它会改写提交哈希、影响协作者。按团队约定选:个人分支用 rebase 整理,集成分支用 --no-ff merge 留痕。把这张对比表存好,下次合并分支就不会在 merge 和 rebase 之间纠结。

要点带走:

  • 能快进时默认是快进,想留痕就加 --no-ff;
  • 三方合并生成独立合并提交,适合集成分支;
  • rebase 只用于未公开的本地分支,公共分支禁用。

下一步可以把分支策略与冲突处理系统学一遍。

延伸学习

想把 Git 合并与版本控制系统补齐,可以按这个顺序来:

  1. 遇到撤销与回退场景,翻 Git 版本回退方法 看 reset / revert 的实际用法;
  2. 想搞清最后一次提交怎么撤,Git 撤销提交方法 讲得很细;
  3. 想边学边练,编程课程 里有配套图文微课,适合巩固。

常见问题

Q:fast-forward 和 --no-ff 到底差在哪?

A:fast-forward 只是把指针往前挪,不产生新提交,历史是直线;--no-ff 会额外生成一个合并提交,把“两条线合过”这件事永久记下来。要可追溯就选后者。

Q:rebase 和 merge 该用哪个?

A:个人还没推送的分支用 rebase 让历史更整洁;已经公开、别人基于它工作的分支用 merge,避免改写哈希引发协作混乱。

Q:合并出现分支冲突怎么办?

A:冲突时 Git 会在文件里用 <<<<<<< 标出两边内容。手动改掉冲突标记、保存后执行 git add 文件名 与 git commit 即可完成合并提交。

0 人点赞