1. 概述

在使用 Git 时,选择合适的合并策略有时会变得很困难,尤其是在代码库快速膨胀、多人协作频繁的项目中。不同分支上的变更很可能产生冲突,这就要求我们有一套高效的合并机制。

了解不同合并策略的适用场景至关重要。每种策略处理变更的方式不同,选择的策略不仅影响冲突的解决方式,也影响项目历史的可读性和流程的清晰度。

本文将介绍 Git 中常见的合并策略,帮助你根据项目实际情况做出更合理的选择。

2. 理解 Git 合并策略

在深入各种策略之前,先回顾一下 Git 中的“合并”概念。

2.1. Git 中的合并是什么?

Git 中的合并是将一个分支的修改整合到另一个分支的过程。通常发生在我们完成某个功能或修复 bug 的分支开发后,需要将其变更合并到主分支中。

Git 会找到两个分支的共同祖先提交,比较差异后生成一个新的提交,这个提交就称为“合并提交(merge commit)”。

Git 支持两种基本的合并类型:

  • Fast-forward(快进合并)
  • Non-fast-forward(非快进合并)

下面分别介绍。

2.2. 快进合并(Fast-forward Merge)

当目标分支(如 main)没有新提交,而源分支(如 feature-branch)是在目标分支基础上继续开发的,Git 会直接将目标分支的指针移动到源分支的最新提交,不生成新的合并提交。

✅ 优点:快速简洁
❌ 缺点:不保留合并痕迹,历史看起来更“扁平”

示例操作:

$ git checkout main
$ git merge feature-branch

输出:

Updating 40a1e54..63a3543
Fast-forward
 file.txt | 1 +
 1 file changed, 1 insertion(+)

查看提交历史:

$ git log --oneline

输出:

63a3543 (HEAD -> main, feature-branch) Add feature content
40a1e54 Initial commit

2.3. 非快进合并(Non-fast-forward Merge)

当两个分支都有独立的新提交时,Git 会创建一个新的合并提交,保留两个分支的变更历史。

✅ 优点:保留完整合并记录,适合团队协作
❌ 缺点:历史更复杂,可能增加维护成本

示例操作:

$ git checkout main
$ git merge feature-branch

Git 会弹出编辑器让你输入合并提交信息。

查看合并后的提交历史:

$ git log --graph --oneline

输出:

*   314066a (HEAD -> main) Merge branch 'feature-branch'
|\
| * 42717db (feature-branch) Add feature content
* | 00a4df1 Add main-specific content
|/
* e8fffdb Initial commit

3. Git 常见合并策略

Git 提供多种合并策略,每种适用于不同的场景。

3.1. resolve 策略

使用三向合并(three-way merge),适合简单冲突场景,不支持文件重命名或合并多个头节点。

使用方式:

$ git merge -s resolve feature-branch

✅ 优点:简单快速
❌ 缺点:不支持重命名、多头合并

3.2. recursive 策略(默认)

Git 默认使用的合并策略,能处理重命名、复杂历史差异,并支持冲突解决策略如 -X ours-X theirs

使用方式:

$ git merge develop

或指定冲突解决策略:

$ git merge -X ours develop

✅ 优点:功能全面,支持冲突处理
❌ 缺点:在大型仓库中效率较低

3.3. octopus 策略

支持一次合并多个分支(如多个 feature 分支),但不擅长处理冲突。

使用方式:

$ git merge -s octopus feature-1 feature-2 feature-3

✅ 优点:支持多分支合并
❌ 缺点:无法处理复杂冲突

3.4. ours / theirs 策略

合并时忽略对方分支的变更,保留当前分支(或对方分支)的内容。

使用方式:

$ git merge -s ours feature-xyz

✅ 优点:用于覆盖性合并
❌ 缺点:可能丢失对方分支的变更

3.5. subtree 策略

用于将外部仓库作为子目录合并进当前项目,保留其目录结构。

使用方式:

$ git remote add repo-xyz https://github.com/username/repo-xyz.git
$ git fetch repo-xyz
$ git merge -s subtree --allow-unrelated-histories repo-xyz/main

✅ 优点:整合外部项目结构
❌ 缺点:合并后结构复杂

4. 新一代合并策略:merge-ort

Git 2.34 引入了新的默认合并策略 merge-ort,替代了原来的 recursive 策略。

✅ 优点:

  • 更快的合并速度
  • 更低的内存占用
  • 支持大规模仓库和复杂历史

⚠️ merge-ort 使用内存处理所有变更,避免了逐文件处理的开销,尤其适合大型项目。

5. 如何选择合适的合并策略?

考量因素 推荐策略
项目复杂度低 resolve
有重命名或复杂历史 recursivemerge-ort
多个分支合并 octopus
强制保留当前分支内容 ours
集成外部项目 subtree

6. Git 合并最佳实践

  • ✅ 使用清晰的分支命名,如 feature/login-systembugfix/typo-fix
  • ✅ 合并前先 rebase,减少冲突
  • ✅ 定期合并主分支到 feature 分支,保持同步
  • ✅ 使用结构化工作流(如 Git Flow 或 trunk-based)
  • ✅ 在 CI/CD 中自动化合并流程,确保质量

7. 高级合并技巧

可以使用一些高级参数优化合并行为:

  • git merge -X patience:优先匹配长段文本,适用于代码格式化差异较大的场景
  • git merge -X diff-algorithm=histogram:使用更智能的 diff 算法,适合处理大文件

自动化合并示例(CI/CD 中):

# GitHub Actions 示例
jobs:
  merge:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout main
        run: git checkout main
      - name: Merge feature branch
        run: git merge -X recursive feature-branch

8. 总结

Git 提供了多种合并策略,每种都有其适用场景:

  • 快进合并适合简单变更,保留线性历史
  • 非快进合并适合多人协作,保留完整合并记录
  • recursivemerge-ort 是处理复杂历史的主力
  • octopussubtree 满足特殊场景需求
  • ourstheirs 用于强制保留某一方变更

合理选择合并策略,不仅能提升协作效率,还能保持项目历史的清晰与可维护性。在实际开发中,结合团队协作方式、项目结构和 CI/CD 流程,灵活运用这些策略,才能真正发挥 Git 的强大功能。


原始标题:Merge Strategies in Git