跳至主要内容

Git Merge 教程:详尽指南与示例

通过本分步教程,学习如何在 Git 中高效合并分支。探索不同合并策略、解决冲突,并应用最佳实践以保持清晰的 Git 历史。
· 15分钟 阅读

使用 AI 探索

如果您曾与多位开发者协作过项目(甚至只是自己同时管理多个功能),就会知道分支对于保持有序至关重要。但在某个时间点,这些分支都需要合并回主线——这正是 git merge 大显身手的时候。

在本教程中,我将带您了解 Git 合并的不同类型、它们的工作原理,以及在进展不顺利时如何解决合并冲突。最后,我会分享一些最佳实践,帮助您高效使用 git merge 并避免常见陷阱。

什么是 git merge?

在团队环境中,开发者通常会在不同的分支上分别开发功能、修复缺陷或进行改进。完成工作后,他们会使用 git merge 来集成这些更改。

合并会将一个分支的更改与另一个分支合并,同时保留完整的版本历史。它会把两个分支的提交历史统一起来。

让我们通过一个示例来理解这一流程。

一个共同的基提交分化为两个分支,在合并前形成各自独立的 main 与 feature 提交尖端。图片由作者提供。

在上图中,自从创建 feature 分支后,feature 和 main 分支都产生了新的提交。

feature 分支与 main 分支从共同基点分叉,之后通过一个合并提交汇合。图片由作者提供。

Git merge 会从两个分支的共同基点开始,拿到两个分支上的所有新提交,并把它们合并为一个合并提交。然后,它会更新 head 指针指向这个新的合并提交。

git merge 基本用法

合并并不只是运行一次 git merge 就结束——在此之前有一些关键步骤需要先就绪。本节我们将从准备分支到完成一次成功合并,完整走一遍流程。

步骤 1:为合并做准备

只有已提交的更改才能被合并。因此,请使用 git status 检查未提交的更改,并在合并前使用 git commit 提交它们。

步骤 2:检出目标分支

在运行 git merge 之前,您应切换到目标分支,通常是 main 分支。使用 切换到 main 分支 的命令 git checkout main 或 git switch main。

步骤 3:合并一个分支

确保本地 main 分支与远程仓库保持最新。为此,运行 git pull origin main。

现在,您终于可以把 feature 分支合并进 main 分支了!可以使用如下命令:

git merge feature-branch

步骤 4:解决合并冲突(如有)

Git 会尝试自动解决合并过程中可能出现的冲突。但当它无法独立解决时,就需要手动干预。

例如,如果不同分支修改了同一文件中的同一行,就可能发生合并冲突。

当 Git 检测到冲突时,会暂停合并并提示您解决。在这种情况下:

  • 运行 git status 查看哪些文件存在冲突。
  • 打开这些文件。
  • 审查冲突的代码行,并更新为在两个分支中都保持一致。

步骤 5:提交合并

解决冲突后,使用 git add . 命令暂存修复后的文件。然后通过提交消息完成合并:

git merge -m “resolved conflicts”

在后续章节中,我们将更深入地介绍如何解决合并冲突。

对初学者而言,这里有一份涵盖创建、更新、删除和管理分支等所有基础命令的完整 Git 速查表。

如果您已有一定 Git 经验,需要回顾重要命令,请查看这篇关于常用Git 命令及示例的教程。

Git 中的合并类型

了解 Git 合并类型能帮助您为具体场景选择合适的策略。以下是三种常见的合并方式。

快进(Fast-forward)合并

当自从创建 feature 分支后,基分支没有新的提交时,Git 会使用快进合并。

如果您的新 feature 分支持续更新,而 main 分支保持不变,合并时只需将 main 的 head 指针前移到 feature 分支即可。

不会产生额外的合并提交,从而使提交历史保持干净、线性。

三方合并(Three-way merge)

如果基分支和 feature 分支都有新提交,Git 会找到它们的共同祖先并创建一个新的合并提交。该提交会合并两个分支的历史,同时保留 feature 分支与 main 分支各自的历史。

在下面的示例中,“E” 和 “G” 是在创建 feature 分支之后新增到 main 分支的提交。

      C---D---F (feature-branch)
     /         
A---B---E---G (main) 

会创建一个新的合并提交 “M”,以保留 main 与 feature 两个分支的历史。

       C---D---F
      /         \
 A---B---E---G---M (main)

压缩(Squash)合并

Squash 合并会将 feature 分支的所有更改合并为一个提交,然后并入目标分支。它不会保留 feature 分支的逐条提交历史。

git merge --squash feature_branch_name

压缩合并特别适用于避免由多个小提交造成的混乱,同时仍能在目标分支保留功能的最终状态。

合并多个分支

在大型项目中,您可能需要合并多个分支——可以逐个合并,也可以一次性并入。选择哪种方式取决于您的工作流和变更的复杂度。本节我将介绍这两种方法及其适用场景。

按顺序依次合并多个分支

要逐个合并分支,请对每个 feature 分支依次执行合并命令。

步骤 1: 切换到您希望并入更改的目标分支。

git checkout target_branch_name

步骤 2: 如下所示,合并第一个 feature 分支。

git merge feature_branch_1

步骤 3: 如下所示,合并第二个 feature 分支。

git merge feature_branch_2

重复此过程,直到所有其他分支都已合并。

并行合并多个分支

按以下步骤一次性合并多个 feature 分支。

步骤 1: 切换到您希望并入更改的目标分支。

git checkout target_branch_name

步骤 2: 使用包含多个 feature 分支的以下命令

git merge feature_branch_1 feature_branch_2 feature_branch_3

当 Git 并行合并多个分支时,可能会发生冲突。一旦发生,Git 会提示您手动解决。

处理多次合并中的冲突

合并多个分支并不总是简单——尤其是当某个分支依赖另一个分支时。

例如,先将 feature_x 合并到 main,再合并 feature_y,可能会引入冲突。同样,如果不同分支修改了相同的文件,并行合并也可能导致需要谨慎处理的冲突。

按以下步骤解决合并冲突:

  • 步骤 1:执行 git status 查看哪些文件引发冲突。
  • 步骤 2:打开冲突文件并进行修正。
  • 步骤 3:将更改加入暂存区并提交。

理解合并提交历史

对于复杂的冲突,您可能需要比 git status 提供的更多信息。在这种情况下,可以使用 git log 或 git show 等命令深入查看历史。

  • git log:显示完整的提交历史,包括合并提交。这有助于定位问题出现的具体合并。
  • git show: 如果在上面的命令中发现可疑的合并提交,使用 git show 进行检查。它会详细展示该提交在合并过程中做了哪些变更。它还会输出在特定合并发生前父分支的唯一标识符。
  • git diff:您可以从前面的命令中拿到父分支和合并分支的唯一标识符,然后用 git diff 对比这两个状态之间的变更。

Git 合并最佳实践

当多位开发者在同一代码库上工作时,合并有时会变得混乱。

虽然我们介绍了在冲突发生时如何解决,但最好的方法是在冲突发生之前加以预防。本节将提供一些实用建议,帮助您顺畅完成合并,并保持 Git 历史清晰。

保持分支小而聚焦

庞大的分支会增加编辑重叠的风险,从而带来更多冲突。为尽量减少这种情况,请每个分支只处理一个功能,并保持分支小而聚焦。

频繁拉取并合并

从远程仓库拉取最新更改,在合并前保持基分支为最新。定期将 main 分支的更新拉取到您的 feature 分支以保持同步,这能避免后续出现大型且复杂的冲突。

使用 Git 内置合并工具

与其手动编辑文件,不如使用 Git 内置工具在可视化界面中解决冲突。运行 git mergetool 时,会出现三种选择:

  • LOCAL - 主分支版本。选择该项会保留来自 main 分支的冲突文件内容,并忽略 feature 分支的更改。
  • REMOTE - feature 分支版本。选择该项会将 feature 分支的内容应用到冲突文件。
  • BASE - 将合并两个分支冲突文件中的更改并进行融合。

按依赖顺序合并

在合并多个分支时,合并顺序很重要——特别是当一个功能依赖另一个功能时。如果 feature_x 依赖 feature_y,先合并 feature_x 可能引入冲突。为避免这种情况,请始终按依赖关系的顺序合并分支,以确保流程顺畅并尽量减少冲突。

使用压缩合并

如前所述,压缩合并会将 feature 分支的所有提交整合为一个提交,保持提交历史整洁,并减少潜在的合并冲突。

另一种方法是变基(rebase),它会将 feature 分支的更改直接应用到基分支之上,从而创建线性的历史并避免不必要的合并提交。不过,这两种方法都会重写历史,且不会保留 feature 分支的单独提交。

结语

在本 Git merge 教程中,我们从合并基础到避免冲突的最佳实践都进行了讲解。掌握 git merge 的有效用法,有助于团队无缝协作,保持工作流顺畅、代码历史清晰。

如果您想进一步提升 Git 技能,请查看这门中级 Git 课程,掌握更高级的工作流与技巧!

FAQs

git merge 与 git rebase 有何区别?

两者都能将一个分支的更改集成到另一个分支中,但 git merge 会创建一个新的合并提交,保留两个分支的历史。相对地,git rebase 会将 feature 分支的提交直接应用到目标分支上,从而形成线性的提交历史,但过程中会重写历史。

我可以在 Git 中撤销一次合并吗?

可以,如果您尚未推送本次合并,可以使用:

git reset --hard HEAD~1

这会将您的分支重置到合并前的状态。如果合并已经推送,您需要使用 git revert 来在保留历史的同时安全地撤销更改。

如何将远程分支合并到本地分支?

要将远程分支合并到本地分支,请按以下步骤操作:

git fetch origin

git checkout my-branch

git merge origin/feature-branch

这样可确保您合并的是远程仓库的最新更新。

如何避免不必要的合并冲突?

要尽量减少冲突:

  • 在开始新工作前定期拉取最新更改(git pull)。
  • 若多个分支相互依赖,请按依赖顺序进行合并。
  • 使用功能开关(feature flags)逐步集成代码,而非长期存续的分支。
当我合并一个已经被合并过的分支会发生什么?

如果一个分支已经被合并,再次运行 git merge feature-branch 不会产生任何变化。Git 会识别出两个分支共享共同历史,并确认一切都是最新的。

我可以一次性合并多个分支吗?

不支持。Git 不支持通过单个命令一次性合并多个分支。您需要按顺序逐个合并:

git merge feature-branch-1

git merge feature-branch-2

如有需要,您可以创建一个集成分支,先将多个分支合并到该分支,再将其合并进 main。

我应该使用 git merge --no-ff 还是 git merge --ff?
  • --no-ff(禁用快进合并)会创建一个新的合并提交,便于跟踪分支历史。
  • --ff(快进合并)在可能的情况下直接应用更改,避免额外提交。

对于需要跟踪 feature 分支的项目,建议使用 --no-ff。

Srujana Maddula

作者

Srujana Maddula

Srujana 是一名自由职业技术写作者,拥有计算机科学四年制学位。她擅长撰写各类主题的内容,包括数据科学、云计算、开发、编程、安全等众多领域。她热爱经典文学,也喜欢探索新的旅行目的地。

主题