合并或归并 — 是在 Git 中将两个分支合并的操作,将更改从一个分支合并到另一个分支。在现代开发中,合并是将功能分支集成到项目主分支的标准方式。根据 GitHub Octoverse 2024,每天执行超过 1500 万次合并。合并 — 协作工作的关键机制,能够将多名开发者的工作合并到一个产品中。
要点
Git 中的合并 — 是将两个或多个开发历史合并为一个的操作。当开发者合并分支时,Git 自动查找共同祖先(基础提交)并创建一个新的合并提交,包含来自两个分支的更改。三方合并 — 比较三种状态的标准算法:共同祖先、第一个分支和第二个分支。
合并过程从 git merge 命令开始。Git 确定分支的分歧点,并顺序地将更改从源分支应用到目标分支。如果更改没有冲突,Git 根据设置执行快进合并或创建合并提交。快进合并 — 目标分支直接移动到源分支的提交的场景。
# 切换到目标分支并合并
git checkout main
git merge feature/payment-module
# 使用显式禁止快进合并
git merge --no-ff feature/payment-module
# 如果冲突过于复杂则中止合并
git merge --abort
--no-ff(禁止快进)标志强制创建合并提交,即使快进是可能的。这保留了更改是在单独分支中完成的信息。许多团队更喜欢这种方法,以明确保留历史分支信息。
在 Git 中有三种主要的分支合并策略,每种适用于特定场景。策略的选择取决于团队文化和对项目历史清晰度的要求。
| 策略 | 结果 | 何时使用 |
|---|---|---|
| 标准合并 | 合并提交 + 完整历史 | 重视完整历史的团队 |
| 压缩合并 | 一个提交,历史压缩 | 包含许多小提交的功能分支 |
| 变基合并 | 线性历史,无合并提交 | 个人功能分支,在创建 PR 之前 |
标准合并创建具有两个父提交的合并提交。完整历史被保留,但分支图变得更加复杂。压缩合并将功能分支的所有提交合并为一个并应用到目标分支 — 历史变得线性且清晰,但丢失了中间阶段的信息。
变基虽然不是完整的合并,但达到相同的结果 — 更改从一个分支转移到另一个分支。区别在于历史被重写:功能分支的提交在目标分支的最后一个提交之上重新创建。这提供了理想的线性历史,但在推送时需要强制推送。
合并时的冲突发生在两个分支中修改了文件的相同行时。Git 无法自动确定保留哪个版本,需要开发者的干预。冲突在文件中以特殊标记的形式显示:<<<<<<<、=======、>>>>>>>。
解决冲突的过程包括几个步骤。首先,开发者打开冲突文件并手动选择所需的更改。重要的是不仅要选择一个版本,还要理解两个更改的逻辑并做出正确的决定。编辑文件后,冲突标记被删除,更改通过 git add 添加到暂存区。
# 查看冲突文件列表
git status
# 启动合并工具(例如 VS Code、IntelliJ)
git mergetool
# 解决所有冲突后
git add .
git merge --continue
# 或完全中止合并
git merge --abort
使用可视化合并工具可以显著加快冲突解决速度。VS Code、IntelliJ IDEA 和 GitKraken 提供三个面板的界面:当前分支、传入分支和结果。Git mergetool 工具自动为每个冲突文件打开已配置的编辑器。
避免复杂冲突的最佳方法是定期将功能分支与主分支同步。如果开发者每天将主分支合并到自己的分支一次,冲突将会很小且易于解决。一周内的更改累积会导致复杂冲突和高错误风险。
变基和合并 — 两种组合更改的方式,它们之间的选择经常在团队中引起争论。变基将提交从一个分支移动到另一个分支,重写历史。合并创建新的合并提交,保留分支历史。每种方法都有其优点和局限性。
变基适用于开发者在自己的本地功能分支上工作,并希望在创建拉取请求之前获得清晰的线性历史。变基后,所有提交顺序排列,没有不必要的合并提交。然而,变基需要强制推送,不适用于多人同时工作的分支。
Git 的黄金规则:不要对已推送到共享仓库的提交使用变基。这保证了公共分支中的历史保持不变,其他开发者不会遇到重复或丢失的提交。要将功能分支集成到主分支,请通过拉取请求使用合并。
正确的合并过程 — 稳定开发的基础。在现代团队工作中,合并不通过控制台执行,而是通过 GitHub 上的拉取请求或 GitLab 上的合并请求执行。PR 经过代码审查、自动 CI 检查,然后才合并到主分支。
第一实践 — 仅在通过所有检查后合并。CI 管道必须构建项目、运行测试并检查代码质量。如果至少一个检查未通过,合并被阻止。现代平台(GitHub、GitLab)具有内置保护:分支保护规则在 CI 失败时自动阻止合并。
第二实践 — 绝不合并损坏的代码。在合并之前,开发者必须确保其更改不会破坏构建或回归现有功能。自动测试和代码审查用于此目的。
第三实践 — 合并后清理功能分支。已经合并的分支必须被删除。这可以防止混乱和仓库的杂乱。GitHub 在 PR 合并后自动建议删除分支,仓库设置可以配置为自动删除。
常见问题
合并 — 将两个 Git 分支合并为一个。更改通过三方合并从一个分支转移到另一个分支。结果记录在一个新的合并提交中,该提交有两个父提交。合并提交保留了哪些分支被合并的信息。
合并创建新的合并提交,保留分支历史。变基通过将提交移动到另一个分支之上来重写历史,不创建合并提交。变基提供线性历史,但需要强制推送。合并对于公共分支更安全,变基更适合个人分支。
打开冲突文件,找到 <<<<<<<、======= 和 >>>>>>> 标记,选择所需的更改并删除标记。通过 git add 添加文件,然后使用 git merge --continue 完成合并。在 VS Code 或 IntelliJ IDEA 中使用 git mergetool 进行可视化解决。
拉取请求(或合并请求)在将功能分支合并到项目主分支时是必需的。PR 经过同事的代码审查和自动 CI 检查。这是现代开发的标准。大多数项目禁止直接推送到主分支。
压缩合并在合并前将功能分支的所有提交合并为一个。这使主分支的历史清晰,没有中间工作提交。当功能分支包含许多服务提交(wip、fixes)且不需要在历史中保留所有中间步骤时,使用压缩合并。
总结
我们将开发一款交钥匙移动应用程序
IT Sectr自2017年以来为初创企业和企业打造iOS和Android应用程序。我们将为您提供咨询并提出最佳解决方案。