为拉取请求配置目标分支

Azure DevOps Services

默认情况下,Azure DevOps 建议针对默认分支创建新的拉取请求。 在多个分支用于拉取请求的存储库中,存储库所有者可以配置拉取请求目标分支的列表,以便这些建议选择适当的目标分支。

若要启用此功能,请在存储库的默认分支中创建名称的文件.azuredevops/pull_request_targets.yml。 此 YAML 文件应包含一个列表,标题 pull_request_targets为,其中包含与候选分支匹配的分支名称或前缀。

例如,请考虑以下内容:

pull_request_targets:
  - main
  - release/*
  - feature/*

此潜在目标列表指定 main 为要首先选择的目标分支,但如果从分支开始 release/feature/ 更适合选择分支,则改为选择该分支。

有关更多拉取请求指南和管理注意事项,请参阅关于拉取请求

何时使用此配置?

使用动态目标分支有多个入口点。

  • 拉取请求建议。 当用户将分支推送到 Azure DevOps 时,他们下次访问 Repos 页面可能会建议从该分支创建拉取请求。 此“创建新的拉取请求”按钮动态选择目标分支。

  • 拉取请求 URL。 当用户使用sourceRef参数直接导航到拉取请求创建页但省略targetRef该参数时,Azure DevOps 会基于此动态选择选择目标分支。

客户端工具可以使用此动态选择创建拉取请求,但这些客户端需要添加一个可选信号,表明用户未指定目标分支。 检查所选客户端工具,查看该选项是否已启用。

分支目标的候选项有哪些?

建议候选分支的配置列表仅包含受拉取请求策略保护的分支。 此类分支可能仅通过完成拉取请求进行更改,这可以保证上一分支位置位于提示提交的第一个父历史记录中。 如果使用合并策略,则第二个父级表示通过完成拉取请求向目标分支引入的提交,第一个父级是上一个提示。

Azure DevOps 如何选取分支?

Git 不会跟踪有关创建分支的元数据。 无法确切地确定创建主题分支时使用的分支。 相反,Azure DevOps 使用基于分支的第一个父历史记录的启发式操作。

在可能的目标分支中,Azure DevOps 选择其第一个父级历史记录与源分支的第一个父历史记录相交最多的分支。

示例:无合并提交

请考虑以下分支结构,因为没有合并提交,这比平常简化。 在此示例中,整个历史记录由第一个父历史记录表示。

  ,-E---F <-- release/2024-September
 /
A---B---C---D <--- main
     \
      `-G---H <--- feature/targets
         \
          `-I <--- topic

在此历史记录和之前使用的示例 pull_request_targets 列表中,我们有三个候选目标分支,顺序为优先级:

  • main
  • release/2024-September
  • feature/targets

然后,将源分支 topic与这些分支进行比较。

  • maintopic at B相交,离开 G,Itopic 而不是在 main
  • release/2024-September与离开B,G,ItopictopicA交,而不是在release/2024-September
  • feature/targetstopic at G相交,离开 Itopic 而不是在 feature/targets

因此,在此示例中,选择feature/targets分支作为源分支的拉取请求topic的目标分支。

示例:合并提交

在更复杂的示例中, feature/targets 分支合并 main 并合并 main 到自身中,提交历史记录需要考虑更多情况:

  ,-E---F <-- release/2024-September
 /
A---B---C---D---J---K <--- main
     \    _/     \
      \  /        \
       `G---H---L--\--M <--- feature/targets
         \          \/
          \
           `I <--- topic

此处,提交D表示main合并到main的时间feature/targets。 提交M表示合并到feature/targets的时间main。 提交M之间的链接,以J强调,J这是第二个父级,而它是L第一个父M级。

在这种情况下,当你考虑完整的提交历史记录时,mainfeature/targets者都与 at Gtopic历史记录相交。 但是,第一个父历史记录仍然演示了首选 feature/targets

中断领带

如果两个分支具有相同的第一个父历史记录交集,则 Azure Devops 会选择前面显示在 pull_request_targets 列表中的分支。 如果由于前缀匹配而仍基于 pull_request_targets 列表绑定多个分支,则最早按字母顺序获胜。

创建新候选分支(例如新的功能分支的开始或发布分支分支)时,通常会存在此类关系。

          ,-E---F <-- release/2024-October
         /
A---B---C---D <--- main
     \
      \
       `G <--- topic

在此示例中,release/2024-October分支是在分支关闭maintopic从分支创建的main。 虽然对于人类读取者是直观的,但列表中的类别 main release/* pull_request_targets 顺序表示 Azure DevOps 的首选顺序。

如果 Azure DevOps 选择错误的目标分支,该怎么办?

如果动态选择与预期不匹配,则拉取请求创建页具有用于调整目标分支的选择器。 创建拉取请求后,还可以调整目标分支。

更重要的是,了解启发式选择“错误”目标分支的原因可能很有价值。

这种启发式依赖于一些关于如何创建目标分支和源分支的假设。 下面是启发式不起作用的一些潜在原因:

  • 目标分支不受拉取请求策略的保护。 如果可以任意推送目标分支,则第一个父级历史记录不是该分支先前位置的可靠指示器。

  • 源分支是从候选分支的上一个提示创建的。 如果源分支在历史记录中选择了任意提交,则不能保证它依赖的第一个父历史记录。

  • 源分支是高级用法 git commitgit merge 命令。 命令(例如 git reset --hardgit rebase 可能以不可预知的方式更改分支的历史记录)。

如果不同意此启发式选择的目标分支,请考虑使用 git rebase --onto <new-target> <old-target> <source>更新选择。 该 git rebase 命令重写第一个父级历史记录,使启发式选择新目标。

用户在意识到基于错误的分支时所犯的一个常见错误是用于 git merge 将正确的分支引入其历史记录。 合并不会更改第一个父级历史记录,因此不会更改目标分支的选择。

如何在本地测试此决策?

Azure DevOps 使用的启发式有助于核心 Git 客户端,并在 Git 版本 2.47.0 及更高版本中提供。

若要在自己的存储库中测试此逻辑,请先运行 git fetch origin 以确保具有最新版本的目标分支。 然后运行以下命令, git for-each-ref 根据候选分支列表进行调整:

$ git for-each-ref --format="%(is-base:HEAD) %(refname)" \
           refs/remotes/origin/main \
           "refs/remotes/origin/release/*" \
           "refs/remotes/origin/feature/*"
 refs/remotes/origin/main
 refs/remotes/origin/release/2024-September
(HEAD) refs/remotes/origin/feature/targets

在此命令中 HEAD ,提交用作源,以相同的方式比较目标分支的第一个父级历史记录。 虽然输出中列出了每个候选分支,但字符串 (HEAD) 指示应将哪些分支用作目标分支。

后续步骤