Git 合并分支:3 种写法一次讲清,从最小示例讲到边界

你本地在 feature 分支上改完功能,想把代码合回 main,却看到 git merge、git rebase、还有那个"快进"提示,不知道该用哪个。Git 合并分支的三种主流写法是:直接用 git merge 产生合并提交、用 git rebase 把提交挪到目标分支之后、以及快进合并(fast-forward)这种无新提交的特殊情况。选错方式主要带来历史线是否干净、冲突处理时机不同两类后果。本文基于 Git 2.x 验证,从最小示例讲到分支分叉、冲突与版本边界。今天这篇文章,编程狮就把这块讲透。
先看结论
| 你的目标 | 写法 | 结果 |
|---|---|---|
| 保留完整合并痕迹 | git merge |
生成一个合并提交,历史呈网状 |
| 历史线保持直线 | git rebase |
把提交重放到目标分支之后 |
| 目标在源头、无分叉 | 快进合并 | 指针直接前移,不产生新提交 |
一句话:想留痕用 merge,想整洁用 rebase,没分叉时 Git 默认快进;团队约定优先于个人偏好。
一、合并前的最小场景与准备
Git 合并分支的前提是两个分支都已有提交,且当前位于"要合入的目标分支"上。先用 Git 教程 里的基础命令确认状态,避免合错方向。
# 切到目标分支,再执行合并
git switch main
git status
git log --oneline --graph -8
以上命令先切换到 main,再用 git status 检查工作区是否干净,git log --graph 用来观察分支拓扑。预期结果是命令行打印出干净的 working tree 与一条提交线;如果 status 提示有未提交修改,先 git stash 或提交掉,否则合并可能被阻断。这一步属于前置配置,能显著降低后面误操作的概率。补充一点:合并前可用 git branch -v 查看每个分支最后一次提交与跟踪关系,确认 feature 确实领先于 main;若工作区有未提交改动,merge 会拒绝执行并提示 "Please commit your changes",此时先 git stash 暂存或提交即可继续。
二、写法一:git merge 产生合并提交
最稳的 Git 合并分支写法是 git merge 分支名,它会在当前分支上新建一个合并提交,把两条历史连起来。适合需要保留"谁在何时合入"证据的场景,比如多人协作的发布分支。
# 把 feature 合入当前所在的 main
git merge feature
运行后 Git 会尝试自动合并;若两个分支改了同一处,会进入冲突状态,文件里出现 <<<<<<< 标记。此时你需要手动编辑保留正确内容,再 git add 与 git commit 收尾。冲突修复完成后,用 git log --graph 验证能看到一个双亲的合并节点。适用场景是对外发布、需要审计合入记录的仓库。
⚠️ 注意:merge 不会改写已有提交,因此最安全;但长期会让历史出现大量合并节点,阅读成本上升。

三、写法二:git rebase 保持直线历史
git rebase 的思路是"先把我的提交临时摘下,跳到目标分支最新处,再逐个重放"。它让历史变成一条直线,方便 bisect 与回滚。先用 Git Magic 教程 理解变基的心智模型会更容易上手。
# 在 feature 上,把当前分支变基到 main
git rebase main
运行后你的提交会被依次重放到 main 顶端,预期结果是 git log 看到一条直线。但若 feature 与 main 有冲突,rebase 会在第一个冲突处停下,你需要修复、git add、再 git rebase --continue。变基的核心代价是"改写提交哈希",所以已推送到远端的分支不要随便 rebase,否则别人拉取时会冲突。版本边界上,Git 1.7 之后 rebase 默认不处理已合入的提交,行为更加可预期。rebase 还有几个常用变体:git rebase -i HEAD~3 可交互地压缩或重排最近三次提交,适合发布前清理;当某个补丁已被上游合入、rebase 提示 "patch already applied" 时,用 git rebase --skip 跳过该提交即可;若变基到一半想整体放弃,始终可以用 git rebase --abort 回到起点,不会留下半成品。
四、快进合并与三种方式横向对比
当目标分支是你当前分支的直接祖先(没有分叉)时,Git 会执行快进合并:仅仅把指针前移,不产生合并提交。你可以用 --no-ff 强制保留合并节点,用 --ff-only 拒绝非快进。
# 强制生成合并提交(即使能快进)
git merge --no-ff feature
# 只允许快进,否则报错
git merge --ff-only feature
progitch 教程 把这三种方式的取舍讲得更系统。下面的对照帮助你按团队约定选型:
| 方式 | 历史形态 | 适用 | 代价 |
|---|---|---|---|
| git merge | 网状、有合并节点 | 需留痕的协作 | 节点多、阅读成本高 |
| git rebase | 直线 | 追求整洁的个人/特性分支 | 改写哈希、忌动已推送分支 |
| 快进合并 | 直线、无新提交 | 无分叉的小合入 | 丢失合并证据 |
边界上注意:rebase 中途用 git rebase --abort 可整体回退;merge 冲突修复错了可用 git merge --abort 取消本次合并。确认结果时统一用 git log --graph --oneline 检查拓扑是否符合预期。团队约定怎么定?很多团队要求 feature 合入 main 时必须用 --no-ff,以便保留"哪次发布合了哪些功能"的审计线;而个人在本地整理提交、还没推送时,用 rebase 保持直线反而更清爽。关键原则是:已推送、他人可能基于它工作的分支绝不 rebase,本地私有分支则可自由整理。

总结
Git 合并分支有三种主流写法:merge 留痕、rebase 整洁、快进省提交。
- 需要审计合入记录用
git merge,它会生成合并提交; - 想保持历史直线用
git rebase,但别对已经推送的分支做; - 没有分叉时 Git 默认快进,可用
--no-ff/--ff-only控制行为。
下一步想系统学 Git,可以先过一遍 Git 教程,再结合速查手册巩固命令。
延伸学习
想把这块知识系统补齐,可以按这个顺序来:
- 想跟着课程动手练,Git 入门实战课程 是边学边写的形式;
- 看版本控制的整体定位,Git 版本控制利器笔记 从协作角度补充认知;
- 需要更完整的命令参考,Git 书中文版教程 适合随时查阅。
常见问题
Q:rebase 和 merge 到底该选哪个?
A:团队没有强制约定时,个人特性分支用 rebase 保持整洁,需要留痕的发布合入用 merge。已推送到远端、别人可能基于它工作的分支,优先 merge。
Q:快进合并为什么没有合并提交?
A:因为目标分支本就是当前分支的祖先,没有分叉,Git 只需把指针前移,不创造新提交,所以历史里看不到合并节点。
Q:rebase 中途搞乱了怎么撤销?
A:直接运行 git rebase --abort 就能整体回到变基开始前;如果已经完成但想反悔,可用 git reflog 找到变基前的提交哈希再 reset 回去。