合并策略和 Squash 合并

Azure DevOps Services | Azure DevOps Server 2022 - Azure DevOps Server 2019

完成拉取请求后,会将主题分支合并到默认分支(通常为 main)中。 此合并会将主题分支的提交添加到主分支,并创建合并提交以调和默认分支和主题分支之间的任何冲突。 拉取请求中的注释和讨论提供了有关主题分支中所做更改的进一步上下文。

拉取请求中常规合并的示例。

由于存在相关的主题分支历史记录,main 分支(或其他默认分支)上的提交历史记录不完全是线性的。 随着项目规模越来越大,同时处理的主题分支的数量也随之增加,使得与默认分支历史记录的一致性越来越难以实现。

默认分支是每个主题分支历史记录的准确表示形式,但很难用于回答有关项目开发的更广泛的问题。

压缩合并

压缩合并是一个合并选项,可用于在完成拉取请求时压缩主题分支的 Git 历史记录。 压缩合并不是将主题分支上的每个提交添加到默认分支的历史记录中,而是将所有文件更改添加到默认分支上的单个新提交中。 压缩合并提交不会引用主题分支,它会生成一个新提交,其中包含来自主题分支的所有更改。 此外,建议删除主题分支以防止发生混淆。

图中显示了 Azure Repos 中拉取请求中的压缩合并。

可以简单理解为,压缩合并只提供文件更改,而常规合并则提供文件更改和提交历史记录。

压缩合并有什么作用?

压缩合并可保持默认分支历史记录简洁且易于遵循,而无需更改团队的工作流程。 主题分支的参与者在主题分支中可按自己需要的方式工作,默认分支则通过使用压缩合并来保持线性的历史记录。 使用压缩合并更新的 main 分支的提交历史记录针对每个合并分支都有一个提交。 可以逐步查看此历史记录,确切地了解工作完成时间。

压缩合并注意事项

压缩合并会压缩默认分支中的更改历史记录,因此一定要与团队协作确定应在何时执行压缩合并、何时保留主题分支的完整提交历史记录。 压缩合并时,最好删除源分支。 删除源分支可防止混淆,因为主题分支本身并没有一个将其合并到默认分支的提交。

使用压缩合并完成拉取请求

在 Azure Repos 中完成拉取请求时,可以选择压缩合并。

在“完成拉取请求”对话框中选择“合并类型”下的“压缩提交”,对主题分支执行压缩合并。

屏幕截图展示在 Azure Repos 中使用压缩合并关闭拉取请求。

多个合并基

拉取请求中的“文件”选项卡通过三方比较来检测差异。 该算法将考虑目标分支中的最后一个提交、源分支中的最后一个提交及其公共合并基(即最佳共同祖先)。 该算法是用于检测更改的快速、经济高效且可靠的方法。 但在某些情况下,真正的基不止一个。 在大多数存储库中,这种情况很少见,但在有许多活动用户的大型存储库中,这种情况可能会比较常见。 可以手动检查分支之间是否存在多个合并库。 为此,请运行 git merge-base --all feature master 命令。 Azure DevOps 检测到每个 PR 存在多个合并库。 检测到这些内容后,Azure DevOps 会显示消息“检测到多个合并库。 显示的提交列表可能不完整”(对于 PR)。 虽然 Azure DevOps 正在运行多个合并库的检测,但不会检查潜在的合并库是否已合并。 这种检查将由 git merge-base 完成。 这就是为什么即使 git merge-base 仅报告一个合并库,Azure DevOps 也会显示消息。

注意

如果您在 PR 审查期间丢失了更改,请确保多个合并库不是根本原因。

Azure DevOps 检测到以下方案作为多个库(合并库由数字 1 和 2 指示):

  • 不同分支之间的交叉合并(也称为十字交叉)(由 Azure DevOps 以及 git merge-base 报告)
---1---o---A
    \ /
     X
    / \
---2---o---o---B
  • 将一个分支合并到其他两个分支(由 Azure DevOps 报告,而非由消除合并库 2 的 git merge-base 报告)
---1---o---o---o---A
    \         /
     \-------2
      \       \
       \---o---o---o---B
  • 处理主分支还原的后果,例如修改合并提交
*   42bb2d2 (HEAD, A) Amended merge commit
|\  
| | *   67c9bb8 (other) Merge branch 'A' into B
| | |\  
| |/ /  
|/| /   
| |/    
| * fa78e32 add second commit
* | 15845c9 add first commit
|/  
* 6a52130 add init
  • 主动重用功能分支
  • 其他涉及还原、最优选择和合并的非直观且复杂的操作

多个合并基检测是安全防范的一部分。 如果有多个合并基,用户界面的文件差异算法可能无法正确检测文件更改,具体取决于它选择的合并基。 如果拉取请求中的文件在合并基之间有不同的版本,就会出现警告,提示有多个合并库。

有关更多详细信息,请查看官方 git 文档

从多个基中合并的潜在安全风险

  • 可能会有恶意用户滥用 UI 算法来提交 PR 中不存在的恶意更改。
  • 如果目标分支中已有 PR 中建议的更改,这些更改会显示在“文件”选项卡中,但可能不会触发映射到文件夹更改的分支策略。
  • PR 中可能不会存在来自多个合并基的对同一文件的两组更改。 这种情况可能会产生有风险的逻辑差异。

如何解决多个合并基的问题

多个合并基并不一定不好,但应该检查确认一切运行正常。 如果想消除多个合并基,可将分支绑定到单个通用上级,方法是在目标上重新设定分支的基,或将目标合并到分支中。 这些操作可消除警告消息,并帮助检查实际更改是否没问题。

一种方法是在重定基或合并之前软重置和储藏进度。 然后可以创建新分支或重新设置空分支的基,并从一个清楚的节点应用更改。 如果更改已存在,此过程可能需要强制进行远程推送。

如何避免多个合并基问题

下面是避免多个合并基问题的一般技巧:

  • 准备拉取请求时,从最新版本的主分支或发布分支创建功能分支。
  • 非必要情况应避免创建任何非直接源自存储库稳定分支的分支。

如果多个合并基问题再次出现,该怎么办

在有许多活跃参与者的大型存储库中,此问题可能会造成很大不便。 即使通过合并来避免多个基,这种情况也可能会再次出现。 如果有人关闭了长期拉取请求,就可能重现这种情况。 即使运行生成策略和测试,也没办法完成拉取请求。 重置和启动新分支可能会有帮助。 如果未发生任何变化,则即使这种情况重现,提交的更改也很可能是清楚明确的。

后续步骤