这几年在团队里带项目,有一件事我几乎每次都会遇到:git merge,看起来是个再普通不过的命令,但真正操作的时候,几乎每个新人都卡在同一个地方——不是不会敲 git merge,而是不知道 merge 到底在干什么、冲突是怎么来的、出了问题怎么救。
这篇文章不是复述文档,是我这些年实际用 Git 做分支合并时沉淀下来的一份操作笔记。从 merge 的底层逻辑、常用命令、冲突解决,到回滚自救和团队协作里的细节,都会讲到。适合刚接触分支管理的同学,也适合已经用了一阵子但总在 merge 上翻车的开发者。
1. 要玩明白merge,先弄懂它到底在合并什么
1.1 merge不是"复制粘贴",而是三方对比
我先捅破一层窗户纸:merge 做的事不是把某个分支的代码"覆盖"到另一个分支。它是把两个分支各自相对于"共同祖先"的改动,做一次三方对比之后合到一起。
这里有三个关键角色:
- Base(共同祖先):两个分支在分叉之前,最后一次共同的提交状态。
- Ours(当前所在分支):你正在操作的分支,
HEAD指向它。 - Theirs(要合并进来的分支):比如
git merge feature/login里的feature/login。
Git 会把这三份内容放在一起比。如果两边改动的是不同的地方,Git 会自动合并;如果两边改动了同一块区域,Git 不知道该听谁的,就产生了冲突(conflict)。这就是为什么我说"merge 不是复制粘贴"——真正的 merge 是需要"开会讨论"的,不是单方面覆盖。
我见过不少新手犯的一个错:合并完看代码不对,就直接 git checkout --ours 或者 git checkout --theirs 把整个文件覆盖掉了。这个操作在紧急情况下能保命,但它已经完全跳过了"三方合并"的逻辑,等于手动放弃了一边的改动,用的时候得非常小心。
1.2 fast-forward 与真正的 merge commit
很多第一次看到 git merge 命令的人会产生一个困惑:为什么有时候 merge 完 git log 只有一条直线,有时候会多出一个有"两个父节点"的提交?
这个差异在 Git 里分得很清楚:
Fast-forward(快进合并)
当当前分支在合并之前,已经包含了目标分支的全部历史,也就是说你当前分支的 HEAD,正好是目标分支历史路径上的一个节点。此时 Git 不需要创建新的提交节点,直接把当前分支的指针往前移动就完成了合并。git log 看起来是线性的。
举个例子:
bash复制# 从 main 切出 feature
git checkout -b feature/login
# 在 feature/login 上提交了两次
git commit -m "feat: add login form"
git commit -m "feat: add login api"
# 切回 main
git checkout main
# 此时 main 没有任何新提交,直接合并 feature/login
git merge feature/login
这里 feature/login 的所有提交都建立在 main 的最新提交之上,所以 git merge 默认会选择 fast-forward,main 直接指向 feature/login 的最新提交,不会多出 merge commit。
真正的 merge commit
如果 main 在分支分叉之后也有了新提交,Git 就无法直接快进了,于是会创建一个专门的 merge commit,把两条历史的差异合并进来。这个 merge commit 有两个父提交,git log --graph 看到的是一条分支交汇线。
这两个概念并不是纯理论。它直接决定了你团队仓库的历史整洁度。如果团队追求线性历史(比如你要做 git bisect 定位问题,或者希望每个 commit message 都清晰可查),合并策略就要倾向 fast-forward;如果希望完整保留"开发了哪些功能、最终合并到哪"的过程,就要倾向 --no-ff 强制生成 merge commit。
1.3 merge 是"保留双方历史"的操作
还有一点需要理解:merge 不会改写历史。它最多产生一个新的 merge commit,但原有的所有 commit、提交人、提交时间都不会变。
这个概念在做 git revert 回滚合并时尤其重要。后面我会专门说怎么回滚 merge commit,这里先记住一个结论:
merge 是"加法"操作,它不删历史,只加历史。想撤销一个已经推送到远程的 merge,不能用
git reset,要用git revert -m。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 日常开发中最顺手的merge操作流程
2.1 合并前检查:状态确认与分支更新
我见过太多人直接在 git merge 之前不做任何检查,结果合并到一半发现自己还在别的分支上,或者本地 main 早就过期了。所以我一直强调,merge 之前至少要做这几步:
第一步:确认当前工作目录是干净的
bash复制git status
如果输出里有未提交的修改,先处理掉。可以 git stash 暂存,也可以提交,但不能带着一堆修改直接合并——否则新增的文件、改到一半的代码有可能和合并进来的代码冲突,到时候你根本分不清这是冲突还是自己没写完。
第二步:确认自己在目标分支上
bash复制git branch
合并的方向是"把目标分支合并到当前分支"。很多人一激动就 git merge main,结果发现自己坐在 feature 分支上——这倒也没问题,只要你的意图确实是把 main 的最新改动同步到 feature。但要先说清楚:你 merge 进来的是哪个分支,就会改变当前分支的内容。
第三步:把本地目标分支更新到最新
bash复制git checkout main
git pull
这一步的目的是减少合并冲突。本地 main 如果落后远程 main 太多,merge 进来的内容可能是过时的,合并完又要想办法处理
