在 Git 中,合并(Merge) 是将一个分支的更改合并到另一个分支的过程。合并通常用于整合不同分支的开发成果,使代码保持最新并同步。本章将介绍合并的基本操作、如何处理合并冲突、不同的合并策略,以及 Git 对合并的处理方式。
10.1 合并的例子
10.1.1 为合并做准备
在合并之前,通常需要先更新目标分支,确保合并不会引入不必要的冲突。例如,要合并 feature
分支到 main
,先切换到 main
并拉取最新代码:
git checkout main
git pull origin main
10.1.2 合并两个分支
执行合并操作,将 feature
分支合并到 main
:
git merge feature
如果 feature
分支和 main
没有分叉(即 main
直接可以“快进”到 feature
),Git 会执行快进合并(Fast-forward Merge),不会生成新的合并提交。
10.1.3 有冲突的合并
如果 main
和 feature
之间有不同的修改,Git 会创建一个新的合并提交(Merge Commit)。如果发生冲突,Git 会提示:
CONFLICT (content): Merge conflict in file.txt
此时需要手动解决冲突,编辑冲突的文件后执行:
git add file.txt
git commit -m "解决合并冲突"
10.2 处理合并冲突
当 Git 无法自动合并文件时,就会发生合并冲突(Merge Conflict)。
10.2.1 确定冲突的文件
执行合并后,使用 git status
查看冲突文件:
git status
输出示例:
both modified: file.txt
表示 file.txt
在两个分支中都有修改,需要手动解决。
10.2.2 检查冲突
打开冲突文件,会看到类似的标记:
<<<<<<< HEAD
这里是 main 分支的内容
=======
这里是 feature 分支的内容
>>>>>>> feature
HEAD
代表当前分支(main
)的代码=======
分隔两个版本的代码>>>>>>>
之后的是feature
分支的代码
10.2.3 Git 是如何追踪冲突的
Git 通过 三方合并(Three-way Merge) 追踪冲突:
main
的最新提交feature
的最新提交- 两者的共同祖先
通过这些信息,Git 确定冲突区域,并要求用户手动解决。
10.2.4 结束解决冲突
- 编辑冲突文件,删除冲突标记,保留正确的代码。
添加解决后的文件:
git add file.txt
提交合并:
git commit -m "解决合并冲突"
10.2.5 中止或重新启动合并
如果决定放弃合并,可以使用 git merge --abort
取消合并:
git merge --abort
如果合并过程中出现错误,可使用 git reset --hard
回滚到合并前的状态(谨慎使用!):
git reset --hard HEAD
10.3 合并策略
Git 提供不同的合并策略,以应对不同的场景。
10.3.1 退化合并(Fast-forward Merge)
如果 feature
是 main
的直接后继版本,Git 会执行快进合并:
git merge --ff feature
这种方式不会创建额外的合并提交,但如果想保留合并记录,可以使用 --no-ff
:
git merge --no-ff feature
10.3.2 常规合并(Three-way Merge)
如果 feature
和 main
发生了分叉,Git 会创建一个新的合并提交:
git merge feature
10.3.3 特殊提交(Squash Merge)
git merge --squash
允许合并多个提交为一个提交,不会生成合并历史:
git merge --squash feature
git commit -m "合并 feature 分支的所有更改"
10.3.4 应用合并策略
不同场景适用于不同的合并方式,例如:
- 短期分支 → 使用
--squash
- 长期维护分支 → 使用
--no-ff
- 合并多个开发分支 → 使用
rebase
(下一章介绍)
10.3.5 合并和重新排序
如果希望在合并前重新整理提交记录,可以使用 git rebase
代替 git merge
,详情见下一章。
10.4 Git 怎么看待合并
Git 在合并时,实际上是在操作 Git 对象模型(Git Object Model),主要涉及 提交(Commit)、树(Tree)和合并提交(Merge Commit)。
10.4.1 合并和 Git 的对象模型
在 Git 内部,合并实际上是创建了一个新的提交,该提交有两个父提交。例如:
* a1b2c3d (HEAD -> main) 合并 feature 分支
|\
| * f4e5g6h (feature) 新功能
|/
* 9d8e7f6 (main) 之前的提交
合并提交 a1b2c3d
具有两个父提交 9d8e7f6
和 f4e5g6h
。
10.4.2 压制合并
如果不想保留分支的历史记录,可以使用 git rebase
代替 git merge
,这将在下一章介绍。
结论
本章介绍了 Git 的合并操作,包括如何合并分支、解决合并冲突,以及不同的合并策略。合并是 Git 版本控制中最常用的操作之一,掌握合并技巧能够提高代码管理的效率。