生成Azure Repos Git 或 TFS Git 存储库

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

Azure Pipelines 可以自动生成并验证每个拉取请求,并提交到 Azure Repos Git 存储库。

选择要部署的存储库

通过首先选择存储库,然后在该存储库中选择一个 YAML 文件来创建新管道。 YAML 文件所在的存储库称为 self 存储库。 默认情况下,这是管道生成的存储库。

稍后可以将管道配置为签出不同的存储库或多个存储库。 若要了解如何执行此操作,请参阅多存储库签出

必须向 Azure Pipelines 授予对存储库的访问权限,以触发其生成并在生成期间提取其代码。 通常,管道有权访问同一项目中的存储库。 但是,如果你希望访问不同项目中的存储库,则需要更新为作业访问令牌授予的权限。

CI 触发器

持续集成 (CI) 触发器会导致管道在将更新推送到指定分支或推送指定的标记时运行。

默认情况下,所有分支上的 YAML 管道都会配置 CI 触发器,除非 Azure DevOps sprint 227 中的“禁用默示的 YAML CI 触发器”已启用。 可以在组织级别或项目级别配置“禁用默示的 YAML CI 触发器”设置。 启用“禁用默示的 YAML CI 触发器”设置后,如果 YAML 管道没有 trigger 部分,则不会启用 YAML 管道的 CI 触发器。 默认情况下,不用启用“禁用默示的 YAML CI 触发器”

分支

可以使用简单的语法控制哪些分支获取 CI 触发器:

trigger:
- main
- releases/*

可以指定分支的全名(例如 main)或通配符(例如 releases/*)。 有关通配符语法的信息,请参阅通配符

注意

不能在触发器中使用变量,因为变量是在运行时评估的(在触发器触发后)。

注意

如果使用模板创作 YAML 文件,则只能在管道的主 YAML 文件中指定触发器。 不能在模板文件中指定触发器。

对于使用 excludebatch 的更复杂的触发器,必须使用完整的语法,如以下示例所示。

# specific branch build
trigger:
  branches:
    include:
    - main
    - releases/*
    exclude:
    - releases/old*

在上面的示例中,如果将更改推送到 main 或推送到任何版本分支,将触发管道。 但是,如果对以 old 开头的版本分支进行更改,则不会触发管道。

如果指定 exclude 子句而不包含 include 子句,则等同于在 include 子句中指定 *

除了在 branches 列表中指定分支名称外,还可以使用以下格式基于标记配置触发器:

trigger:
  branches:
    include:
      - refs/tags/{tagname}
    exclude:
      - refs/tags/{othertagname}

如果未指定任何触发器,并且未启用“禁用默示的 YAML CI 触发器”设置,则默认情况会与你编写以下内容时相同:

trigger:
  branches:
    include:
    - '*'  # must quote since "*" is a YAML reserved character; we want a string

重要

指定触发器时,它将替换默认的隐式触发器,并且只有推送到显式配置为包含的分支才会触发管道。 首先处理包含项,然后从该列表中删除排除项。

批处理 CI 运行

如果有许多团队成员经常上传更改,则可能需要减少启动的运行次数。 如果将 batch 设置为 true,则当管道运行时,系统将等待运行完成,然后启动另一个运行,其中包含尚未生成的所有更改。

# specific branch build with batching
trigger:
  batch: true
  branches:
    include:
    - main

注意

存储库资源触发器不支持 batch

为了阐明此示例,我们假设对 main 的推送 A 导致上述管道运行。 当该管道正在运行时,会向存储库进行额外的推送 BC。 这些更新不会立即启动新的独立运行。 但是,在完成第一次运行后,在该时间点之前的所有推送将一起进行批处理,然后启动新的运行。

注意

如果管道有多个作业和阶段,则通过完成或跳过其所有作业和阶段,第一次运行仍应达到终端状态,然后才能启动第二次运行。 因此,在具有多个阶段或审批的管道中使用此功能时,必须小心谨慎。 如果希望在这种情况下批处理生成,建议将 CI/CD 进程拆分为两个管道 - 一个用于生成(批处理),一个用于部署。

路径

可以指定要包含或排除的文件路径。

# specific path build
trigger:
  branches:
    include:
    - main
    - releases/*
  paths:
    include:
    - docs
    exclude:
    - docs/README.md

指定路径时,如果使用的是 Azure DevOps Server 2019.1 或更低版本,则必须显式指定要触发的分支。 不能触发只有路径筛选器的管道;还必须具有分支筛选器,并且与路径筛选器匹配的已更改文件必须来自与分支筛选器匹配的分支。 如果使用的是 Azure DevOps Server 2020 或更高版本,则可以省略 branches 以结合路径筛选器筛选所有分支。

路径筛选器支持通配符。 例如,可以包含与 src/app/**/myapp* 匹配的所有路径。 指定路径筛选器时,可以使用通配符(***?))。

  • 指定的路径务必是存储库根目录的相对路径。
  • 如果未设置路径筛选器,则默认会隐式包含存储库的根文件夹。
  • 如果排除某个路径,则不能同时包含该路径,除非将其限定为更深一级的文件夹。 例如,如果排除 /tools,则可以包含 /tools/trigger-runs-on-these
  • 路径筛选器的顺序无关紧要。
  • Git 中的路径区分大小写。 请确保使用与真实文件夹相同的大小写。
  • 不能在路径中使用变量,因为变量是在运行时评估的(在触发器触发后)。

Tags

除了按上一部分所述在 branches 列表中指定标记外,还可以直接指定要包含或排除的标记:

# specific tag
trigger:
  tags:
    include:
    - v2.*
    exclude:
    - v2.0

如果未指定任何标记触发器,则默认情况下,标记不会触发管道。

重要

如果结合分支筛选器指定标记,则满足分支筛选器或满足标记筛选器时将触发触发器。 例如,如果推送的标记满足分支筛选器,即使标记筛选器排除了该标记,管道也会触发,因为推送满足分支筛选器。

选择退出 CI

禁用 CI 触发器

可以通过指定 trigger: none 选择完全退出 CI 触发器。

# A pipeline with no CI trigger
trigger: none

重要

将更改推送到分支时,将评估该分支中的 YAML 文件,以确定是否应启动 CI 运行。

跳过单个推送的 CI

还可以告诉 Azure Pipelines 跳过运行推送通常会触发的管道。 仅在属于推送的任何提交的消息中包括 ***NO_CI***,并且 Azure Pipelines 将跳过运行此推送的 CI。

还可以告诉 Azure Pipelines 跳过运行推送通常会触发的管道。 仅在消息或属于推送的任何提交的描述中包括 [skip ci],并且 Azure Pipelines 将跳过运行此推送的 CI。 你也可以使用以下任意变体。

  • [skip ci][ci skip]
  • skip-checks: trueskip-checks:true
  • [skip azurepipelines][azurepipelines skip]
  • [skip azpipelines][azpipelines skip]
  • [skip azp][azp skip]
  • ***NO_CI***

在条件中使用触发器类型

常见方案是在管道中运行不同的步骤、作业或阶段,具体取决于启动运行的触发器类型。 可以使用系统变量 Build.Reason 执行此操作。 例如,将以下条件添加到步骤、作业或阶段,以将其从 PR 验证中排除。

condition: and(succeeded(), ne(variables['Build.Reason'], 'PullRequest'))

创建新分支时的触发器行为

为同一存储库配置多个管道很常见。 例如,你可能有一个管道用于生成应用的文档,另一个管道用于生成源代码。 可以在其中每个管道中使用适当的分支筛选器和路径筛选器配置 CI 触发器。 例如,你可能希望在将更新推送到 docs 文件夹时触发一个管道,在将更新推送到应用程序代码时触发另一个管道。 在这些情况下,需要了解创建新分支时如何触发管道。

下面是将新分支(与分支筛选器匹配)推送到存储库时的行为:

  • 如果管道具有路径筛选器,则仅当新分支更改了与该路径筛选器匹配的文件时,才会触发该管道。
  • 如果管道没有路径筛选器,则即使新分支中没有更改,也会触发该管道。

通配符

指定分支、标记或路径时,可以使用确切的名称或通配符。 通配符模式允许 * 匹配零个或多个字符并允许 ? 匹配单个字符。

  • 如果在 YAML 管道中使用 * 启动模式,则必须用引号将模式括起来,例如 "*-releases"
  • 对于分支和标记:
    • 通配符可能出现在模式中的任意位置。
  • 对于路径:
    • 在 Azure DevOps Server 2022 及更高版本(包括 Azure DevOps Services)中,通配符可能出现在路径模式中的任何位置,你可以使用 *?
    • 在 Azure DevOps Server 2020 及更低版本中,可以包含 * 作为最后一个字符,但它与单独指定目录名称没有任何不同。 不能在路径筛选器的中间包含 *,并且不能使用 ?
trigger:
  branches:
    include:
    - main
    - releases/*
    - feature/*
    exclude:
    - releases/old*
    - feature/*-working
  paths:
    include:
    - docs/*.md

PR 触发器

拉取请求 (PR) 触发器会导致管道在打开拉取请求或推送更改时运行。 在 Azure Repos Git 中,此功能是使用分支策略实现的。 要启用 PR 验证,请导航到所需分支的分支策略,并为该分支配置生成验证策略。 有关详细信息,请参阅配置分支策略

如果有一个打开的 PR 并将更改推送到其源分支,则多个管道可能会运行:

  • 目标分支生成验证策略指定的管道将在合并提交(拉取请求的源分支和目标分支之间的合并代码)上运行,无论是否存在其消息或说明包含 [skip ci](或其任何变体)的推送提交。
  • 如果没有其消息或说明包含 [skip ci](或其任何变体)的推送提交,则管道由对 PR 的源分支的更改触发。 如果至少有一个推送的提交包含 [skip ci],则管道将不会运行。

最后,在合并 PR 之后,Azure 管道将运行由推送到目标分支触发的 CI 管道,即使某些合并提交的消息或描述包含 [skip ci](或其任何变体)。

注意

要配置 Azure Repos Git 存储库的验证生成,你必须是其项目的项目管理员。

注意

即使配置了分支策略,草稿拉取请求也不会触发管道。

验证分叉的贡献

从 Azure Repos 分叉生成拉取请求等同于在同一存储库或项目中生成拉取请求。 只能在项目所属的同一组织中创建分叉。

限制作业授权范围

Azure Pipelines 提供多个安全设置来配置管道运行时采用的作业授权范围。

将作业授权范围限制为当前项目

Azure Pipelines 提供两个“将作业授权范围限制为当前项目”设置:

  • 将作业授权范围限制为非发布管道的当前项目 - 此设置适用于 YAML 管道和经典生成管道。 此设置不适用于经典发布管道。
  • 将作业授权范围限制为发布管道的当前项目 - 此设置仅适用于经典发布管道

除非启用了管道类型的相关设置,否则管道使用集合作用域的访问令牌运行。 通过“限制作业授权范围”设置,可以将所有管道的访问范围缩小到当前项目。 如果访问组织中其他项目中的 Azure Repos Git 存储库,这可能会影响管道。

如果 Azure Repos Git 存储库与管道不在同一个项目中,并且启用了管道类型的“限制作业授权范围”设置,则必须向第二个项目授予管道的生成服务标识权限。 有关详细信息,请参阅管理生成服务帐户权限

Azure Pipelines 提供一个安全设置来配置管道运行时采用的作业授权范围。

  • 将作业授权范围限制为当前项目 - 此设置适用于 YAML 管道和经典生成管道。 此设置不适用于经典发布管道

管道使用集合作用域的访问令牌运行,除非启用了将作业授权作用域限制为当前项目。 此设置允许可缩小当前项目的所有管道的访问范围。 如果访问组织中其他项目中的 Azure Repos Git 存储库,这可能会影响管道。

如果 Azure Repos Git 存储库与管道不在同一个项目中,并且启用了“限制作业授权范围”设置,则必须向第二个项目授予管道的生成服务标识权限。 有关详细信息,请参阅作业授权范围

有关限制作业授权范围的详细信息,请参阅了解作业访问令牌

将作业授权范围限制为所引用的 Azure DevOps 存储库

管道可以访问授权项目中的任何 Azure DevOps 存储库,如上文将作业授权范围限制为当前项目所述,除非启用了“将作业授权范围限制为所引用的 Azure DevOps 存储库”。 启用此选项后,可以将所有管道的访问范围缩小到仅由使用该存储库的管道作业中的 checkout 步骤或 uses 语句显式引用的 Azure DevOps 存储库。

若要配置此设置,请在“组织设置”或“项目设置”中导航到“管道”、“设置”。 如果在组织级别启用,该设置将灰显,在项目设置级别不可用。

启用“将作业授权范围限制为引用的 Azure DevOps 存储库”时,YAML 管道必须显式引用你要在管道中使用的任何 Azure Repos Git 存储库,作为使用该存储库的作业中的签出步骤。 除非首先显式引用该存储库,否则将无法使用脚本任务和 git 命令获取 Azure Repos Git 存储库的代码。

如果启用“将作业授权范围限制为引用的 Azure DevOps 存储库”,在管道中使用 Azure Repos Git 存储库之前,在一些例外情况无需显式引用此类存储库。

  • 如果你的管道中没有明确的签出步骤,则就采取了checkout: self步骤一样,并且 self 存储库将被签出。
  • 如果使用脚本对公共项目中的存储库执行只读操作,则无需在checkout步骤中引用公共项目存储库。
  • 如果使用的脚本为存储库提供自己的身份验证,例如 PAT,则无需在checkout步骤中引用该存储库。

例如,启用“将作业授权范围限制为引用的 Azure DevOps 存储库”时,如果管道位于组织中的 FabrikamProject/Fabrikam 存储库中,并且你想要使用脚本来签出 FabrikamProject/FabrikamTools 存储库,则必须在checkout步骤中引用此存储库,或者使用 uses 语句引用此类存储库。

如果已在管道中使用签出步骤签出 FabrikamTools 存储库,则随后可以使用脚本与该存储库进行交互。

steps:
- checkout: git://FabrikamFiber/FabrikamTools # Azure Repos Git repository in the same organization
- script: # Do something with that repo

# Or you can reference it with a uses statement in the job
uses:
  repositories: # List of referenced repositories
  - FabrikamTools # Repository reference to FabrikamTools

steps:
- script: # Do something with that repo like clone it

注意

对于许多方案,可以利用多存储库签出,而无需使用脚本在管道中签出其他存储库。 有关详细信息,请参阅在管道中签出多个存储库

保护对 YAML 管道中存储库的访问权限

管道可以访问授权项目中的任何 Azure DevOps 存储库,如上文将作业授权范围限制为当前项目所述,除非启用了“保护对 YAML 管道中的存储库的访问”。 启用此选项后,可以将所有管道的访问范围缩小到仅由使用该存储库的管道作业中的 checkout 步骤或 uses 语句显式引用的 Azure DevOps 存储库。

若要配置此设置,请在“组织设置”或“项目设置”中导航到“管道”、“设置”。 如果在组织级别启用,该设置将灰显,在项目设置级别不可用。

重要

默认情况下,将为 2020 年 5 月之后创建的新组织和项目启用“保护对 YAML 管道中的存储库的访问”。 启用“保护对 YAML 管道中的存储库的访问”后,YAML 管道必须显式引用你要在管道中使用的任何 Azure Repos Git 存储库,作为使用该存储库的作业中的签出步骤。 除非首先显式引用该存储库,否则将无法使用脚本任务和 git 命令获取 Azure Repos Git 存储库的代码。

如果启用“保护对 YAML 管道中的存储库的访问”,在管道中使用 Azure Repos Git 存储库之前,在少数几种例外情况下无需显示引用此类存储库。

  • 如果你的管道中没有明确的签出步骤,则就采取了checkout: self步骤一样,并且 self 存储库将被签出。
  • 如果使用脚本对公共项目中的存储库执行只读操作,则无需在checkout步骤中引用公共项目存储库。
  • 如果使用的脚本为存储库提供自己的身份验证,例如 PAT,则无需在checkout步骤中引用该存储库。

例如,启用“保护对 YAML 管道中的存储库的访问”时,如果管道位于组织中的 FabrikamProject/Fabrikam 存储库中,并且你想要使用脚本来签出 FabrikamProject/FabrikamTools 存储库,则必须在 checkout 步骤中引用此存储库,或者使用 uses 语句引用此类存储库。

如果已在管道中使用签出步骤签出 FabrikamTools 存储库,则随后可以使用脚本与该存储库进行交互。

steps:
- checkout: git://FabrikamFiber/FabrikamTools # Azure Repos Git repository in the same organization
- script: # Do something with that repo
# Or you can reference it with a uses statement in the job
uses:
  repositories: # List of referenced repositories
  - FabrikamTools # Repository reference to FabrikamTools
steps:
- script: # Do something with that repo like clone it

注意

对于许多方案,可以利用多存储库签出,而无需使用脚本在管道中签出其他存储库。 有关详细信息,请参阅在管道中签出多个存储库

签出

触发管道时,Azure Pipelines 会从 Azure Repos Git 存储库中拉取源代码。 可以控制该行为的各个方面。

注意

在管道中包含签出步骤时,我们将运行以下命令:git -c fetch --force --tags --prune --prune-tags --progress --no-recurse-submodules origin --depth=1。 如果这不能满足你的需求,则可以选择通过 checkout: none 排除内置签出,然后使用脚本任务执行自己的签出。

Git 的首选版本

Windows 代理包含自己的 Git 副本。 如果想要提供自己的 Git 而不是使用包含的副本,请将 System.PreferGitFromPath 设置为 true。 在非 Windows 代理上,此设置始终为 true。

签出路径

如果要签出单个存储库,默认情况下,源代码将签出到名为 s 的目录中。 对于 YAML 管道,可以通过使用 path 指定 checkout 来更改此设置。 指定的路径是 $(Agent.BuildDirectory) 的相对路径。 例如:如果签出路径值为 mycustompath$(Agent.BuildDirectory)C:\agent\_work\1,则源代码将签出到 C:\agent\_work\1\mycustompath 中。

如果使用多个 checkout 步骤并签出多个存储库,并且未使用 path 显式指定文件夹,则每个存储库都放置在以存储库命名的 s 的子文件夹中。 例如,如果签出两个名为 toolscode 的存储库,则源代码将签出到 C:\agent\_work\1\s\toolsC:\agent\_work\1\s\code 中。

请注意,签出路径值不能设置为高于 $(Agent.BuildDirectory) 的任何目录级别,因此 path\..\anotherpath 将会产生有效的签出路径(即 C:\agent\_work\1\anotherpath),但 ..\invalidpath 这样的值则不会产生有效的签出路径(即 C:\agent\_work\invalidpath)。

可以在管道的签出步骤中配置 path 设置。

steps:
- checkout: self  # self represents the repo where the initial Pipelines YAML file was found
  clean: boolean  # whether to fetch clean each time
  fetchDepth: number  # the depth of commits to ask Git to fetch
  lfs: boolean  # whether to download Git-LFS files
  submodules: true | recursive  # set to 'true' for a single level of submodules or 'recursive' to get submodules of submodules
  path: string  # path to check out source code, relative to the agent's build directory (e.g. \_work\1)
  persistCredentials: boolean  # set to 'true' to leave the OAuth token in the Git config after the initial fetch

子模块

如果要从子模块下载文件,可以在管道的签出步骤中配置 submodules 设置。

steps:
- checkout: self  # self represents the repo where the initial Pipelines YAML file was found
  clean: boolean  # whether to fetch clean each time
  fetchDepth: number  # the depth of commits to ask Git to fetch
  lfs: boolean  # whether to download Git-LFS files
  submodules: true | recursive  # set to 'true' for a single level of submodules or 'recursive' to get submodules of submodules
  path: string  # path to check out source code, relative to the agent's build directory (e.g. \_work\1)
  persistCredentials: boolean  # set to 'true' to leave the OAuth token in the Git config after the initial fetch

生成管道将签出 Git 子模块,只要它们是:

  • 未经身份验证:一个未经身份验证的公共存储库,无需凭据即可克隆或提取。

  • 已经过身份验证:

    • 包含在与上面指定的 Azure Repos Git 存储库相同的项目中。 代理用于从主存储库获取源的凭据也用于获取子模块的源。

    • 通过使用相对于主存储库的 URL 添加。 例如:

      • 将签出以下代码:git submodule add ../../../FabrikamFiberProject/_git/FabrikamFiber FabrikamFiber

        在此示例中,子模块是指在同一 Azure DevOps 组织中但在不同项目 (FabrikamFiberProject) 中的存储库 (FabrikamFiber)。 代理用于从主存储库获取源的凭据也用于获取子模块的源。 这要求作业访问令牌有权访问第二个项目中的存储库。 如果按上述部分所述限制作业访问令牌,则无法执行此操作。 可以通过 (a) 显式授予对第二个项目中的项目生成服务帐户的访问权限,或者 (b) 使用集合作用域内的访问令牌(而不是整个组织的项目作用域内令牌)来允许作业访问令牌访问第二个项目中的存储库。 有关这些选项及其安全隐患的详细信息,请参阅访问存储库、项目和其他资源

      • 不会签出以下代码:git submodule add https://fabrikam-fiber@dev.azure.com/fabrikam-fiber/FabrikamFiberProject/_git/FabrikamFiber FabrikamFiber

使用 Checkout 子模块选项的替代方法

在某些情况下,无法使用“签出子模块”选项。 你可能会遇到这样一种情况:需要一组不同的凭据才能访问子模块。 例如,如果主存储库和子模块存储库不存储在同一 Azure DevOps 组织中,或者作业访问令牌无权访问其他项目中的存储库,则可能会发生这种情况。

如果无法使用“签出子模块”选项,则可以改用自定义脚本步骤来提取子模块。 首先,获取个人访问令牌 (PAT),并添加前缀 pat:。 接下来,对添加前缀后的字符串进行 base64 编码,以创建基本身份验证令牌。 最后,将此脚本添加到管道:

git -c http.https://<url of submodule repository>.extraheader="AUTHORIZATION: Basic <BASE64_ENCODED_STRING>" submodule update --init --recursive

请务必将“<BASE64_ENCODED_STRING>”替换为 Base64 编码的“pat:token”字符串。

在项目或生成管道中使用机密变量来存储生成的基本身份验证令牌。 使用该变量在上述 Git 命令中填充机密。

注意

问:为什么不能在代理上使用 Git 凭据管理器? 答:在专用生成代理上安装的 Git 凭据管理器中存储子模块凭据通常无效,因为每当更新子模块时,凭据管理器可能会提示你重新输入凭据。 当无法进行用户交互时,在自动生成期间,这是不可取的。

同步标记

重要

Azure Repos Git 中支持在 Azure DevOps Server 2022.1 及更高版本中使用同步标记功能。

签出步骤在提取 Git 存储库的内容时使用 --tags 选项。 这会导致服务器提取所有标记以及这些标记所指向的所有对象。 这会增加在管道中运行任务的时间,尤其是在具有大量标记的大型存储库时。 此外,即使启用浅提取选项,签出步骤也会同步标记,因此可能会破坏其用途。 为了减少从 Git 存储库提取或拉取的数据量,Microsoft 添加了一个新签出选项来控制同步标记的行为。 此选项在经典管道和 YAML 管道中都可用。

是否在签出存储库时同步标记可以通过设置 fetchTags 属性在 YAML 中配置,并且通过配置同步标记设置在 UI 中配置。

可以在管道的签出步骤中配置 fetchTags 设置。

若要在 YAML 中配置设置,请设置 fetchTags 属性。

steps:
- checkout: self
  fetchTags: true

还可以使用管道设置 UI 中的“同步标记”选项配置此设置。

  1. 编辑 YAML 管道,然后选择“更多操作”、“触发器”。

    更多触发器菜单的屏幕截图。

  2. 选择“YAML”、“获取源”。

    获取源的屏幕截图。

  3. 配置同步标记设置。

    同步标记设置的屏幕截图。

注意

如果在 checkout 步骤中显式设置 fetchTags,则该设置优先于管道设置 UI 中配置的设置。

默认行为

  • 对于在 2022 年 9 月发布的 Azure DevOps 冲刺 209 之前创建的现有管道,同步标记的默认值与添加“同步标记”选项之前的现有行为相同,即 true
  • 对于在 Azure DevOps 冲刺版本 209 之后创建的新管道,同步标记的默认值为 false

注意

如果在 checkout 步骤中显式设置 fetchTags,则该设置优先于管道设置 UI 中配置的设置。

浅提取

你可能想要限制要下载多远的历史记录。 这实际上会导致 git fetch --depth=n。 如果存储库很大,此选项可能会提高生成管道的效率。 如果存储库已长期使用并且具有相当大的历史记录,则存储库可能很大。 如果添加并随后删除了大型文件,则它也可能很大。

重要

2022 年 9 月 Azure DevOps 冲刺 209 更新后创建的新管道默认启用了浅提取,并配置了深度为 1。 以前默认不是浅提取。 若要检查管道,请在管道设置 UI 中查看浅提取设置,如以下部分所述。

可以在管道的签出步骤中配置 fetchDepth 设置。

steps:
- checkout: self  # self represents the repo where the initial Pipelines YAML file was found
  clean: boolean  # whether to fetch clean each time
  fetchDepth: number  # the depth of commits to ask Git to fetch
  lfs: boolean  # whether to download Git-LFS files
  submodules: true | recursive  # set to 'true' for a single level of submodules or 'recursive' to get submodules of submodules
  path: string  # path to check out source code, relative to the agent's build directory (e.g. \_work\1)
  persistCredentials: boolean  # set to 'true' to leave the OAuth token in the Git config after the initial fetch

还可以通过在管道设置 UI 中设置“浅深度”选项来配置提取深度。

  1. 编辑 YAML 管道,然后选择“更多操作”、“触发器”。

    更多触发器菜单的屏幕截图。

  2. 选择“YAML”、“获取源”。

    获取源的屏幕截图。

  3. 配置浅提取设置。 取消选中“浅提取”以禁用浅提取,或选中框并输入“深度”以启用浅提取。

    选项的屏幕截图。

注意

如果在 checkout 步骤中显式设置 fetchDepth,则该设置优先于管道设置 UI 中配置的设置。 设置 fetchDepth: 0 将提取所有历史记录,并覆盖“浅提取”设置。

在这些情况下,此选项有助于节省网络和存储资源。 它还可以节省时间。 但它并不是一定会节省时间,原因是,在某些情况下,服务器可能需要花时间计算要为指定深度下载的提交。

注意

启动管道时,要生成的分支将解析为提交 ID。 然后,代理提取分支并签出所需的提交。 分支解析为提交 ID 和代理执行签出之间有一小段时间。 如果分支快速更新,并且你为浅提取设置非常小的值,则当代理尝试签出提交时,提交可能不存在。如果发生这种情况,请增加浅提取深度设置。

不同步源

你可能想要跳过提取新提交。 此选项在需要执行以下操作的情况下非常有用:

  • 使用自己的自定义选项进行 Git 初始化、配置和提取。

  • 使用生成管道仅运行不依赖于版本控制中的代码的自动化(例如,某些脚本)。

可以通过设置 checkout: none 在管道的签出步骤中配置“不同步源”设置。

steps:
- checkout: none  # Don't sync sources

注意

使用此选项时,代理还会跳过运行清理存储库的 Git 命令。

清理生成

在生成运行之前,可以对自托管代理的工作目录执行不同形式的清理。

一般情况下,为了提高自托管代理的性能,请不要清理存储库。 在这种情况下,若要获得最佳性能,请确保同时以增量方式生成,方法是禁用用于生成的任务或工具的任何“清理”选项。

如果你确实需要清理存储库(例如,为了避免上次生成残留的文件造成问题),请使用以下选项。

注意

如果使用 Microsoft 托管代理,则清理无效,因为每次都会获得一个新代理。

可以在管道的签出步骤中配置 clean 设置。

steps:
- checkout: self  # self represents the repo where the initial Pipelines YAML file was found
  clean: boolean  # whether to fetch clean each time
  fetchDepth: number  # the depth of commits to ask Git to fetch
  lfs: boolean  # whether to download Git-LFS files
  submodules: true | recursive  # set to 'true' for a single level of submodules or 'recursive' to get submodules of submodules
  path: string  # path to check out source code, relative to the agent's build directory (e.g. \_work\1)
  persistCredentials: boolean  # set to 'true' to leave the OAuth token in the Git config after the initial fetch

clean 设置为 true 时,生成管道将对 $(Build.SourcesDirectory) 中的任何更改执行撤消操作。 更具体地说,以下 Git 命令在提取源之前执行。

git clean -ffdx
git reset --hard HEAD

有关更多选项,可以配置作业workspace 设置。

jobs:
- job: string  # name of the job, A-Z, a-z, 0-9, and underscore
  ...
  workspace:
    clean: outputs | resources | all # what to clean up before the job runs

这提供了以下清理选项。

  • 输出:与上一签出任务中所述的清理设置相同的操作,加上:删除再重新创建 $(Build.BinariesDirectory)。 请注意,始终在每次生成之前删除再重新创建 $(Build.ArtifactStagingDirectory)$(Common.TestResultsDirectory),而不考虑其中的任何设置。

  • 资源:删除再重新创建 $(Build.SourcesDirectory)。 这会导致为每个生成初始化新的本地 Git 存储库。

  • 全部:删除再重新创建 $(Agent.BuildDirectory)。 这会导致为每个生成初始化新的本地 Git 存储库。

标记源

你可能想要标记源代码文件,使团队能够轻松确定每个文件的哪个版本包含在已完成的生成中。 还可以选择指定是应为所有生成标记源代码,还是仅为成功的生成标记源代码。

当前无法在 YAML 中配置此设置,但可以在经典编辑器中配置此设置。 编辑 YAML 管道时,可以通过从 YAML 编辑器菜单中选择任一触发器来访问经典编辑器。

配置 Git 选项“YAML”。

在经典编辑器中,选择“YAML”,选择“获取源”任务,然后在其中配置所需的属性。

从经典编辑器中,选择“YAML”>“获取源”。

标记格式中,可以使用范围为“全部”的用户定义变量和预定义变量。例如:

$(Build.DefinitionName)_$(Build.DefinitionVersion)_$(Build.BuildId)_$(Build.BuildNumber)_$(My.Variable)

前四个变量是预定义变量。 My.Variable 可以是你在“变量”选项卡上定义的变量。

生成管道使用 Git 标记标记源。

某些生成变量可能会生成不是有效标签的值。 例如,$(Build.RequestedFor)$(Build.DefinitionName) 等变量可以包含空格。 如果值包含空格,则不会创建标记。

生成管道标记源后,带有 Git 引用 refs/tags/{tag} 的项目会自动添加到已完成的生成中。 这为团队提供了额外的可跟踪性,并提供更加用户友好的方式来从生成导航到生成的代码。 标记被视为生成项目,因为它是由生成创建的。 手动或通过保留策略删除生成时,也会删除标记。

常见问题解答

与 Azure Repos 集成相关的问题分为三类:

  • 触发器失败:将更新推送到存储库时,管道未触发。
  • 签出失败管道正在触发,但在签出步骤中失败。
  • 版本错误管道运行,但它使用的不是所需的源/YAML 版本。

触发器失败

我刚刚创建了一个包含 CI/PR 触发器的新 YAML 管道,但该管道未触发。

按照以下各步骤对失败的触发器进行故障排除:

  • 你的 YAML CI 或 PR 触发器是否被 UI 中的管道设置替代? 编辑管道时,选择“...”,然后选择“触发器”。

    管道设置 UI。

    针对你的存储库可用的触发器类型(“持续集成”或“拉取请求验证”)选中“从此处替代 YAML 触发器”设置。

    从此处替代 YAML 触发器。

  • 是在 YAML 文件中还是在存储库的分支策略中配置 PR 触发器? 对于 Azure Repos Git 存储库,无法在 YAML 文件中配置 PR 触发器。 需要使用分支策略
  • 管道是否已暂停或禁用? 打开管道的编辑器,然后选择“设置”进行检查。 如果管道已暂停或禁用,则触发器将不起作用。

  • 是否已在正确的分支中更新 YAML 文件? 如果将更新推送到分支,则同一分支中的 YAML 文件将控制 CI 行为。 如果将更新推送到源分支,则因将源分支与目标分支合并而产生的 YAML 文件将控制 PR 行为。 请确保正确分支中的 YAML 文件具有必要的 CI 或 PR 配置。

  • 是否已正确配置触发器? 定义 YAML 触发器时,可以为分支、标记和路径指定 include 和 exclude 子句。 确保 include 子句与提交的详细信息匹配,并且 exclude 子句不会排除它们。 检查触发器的语法,并确保它是正确无误的。

  • 是否在定义触发器或路径时使用了变量? 这不受支持。

  • 是否对 YAML 文件使用了模板? 如果是这样,请确保在主 YAML 文件中定义了触发器。 在模板文件中定义的触发器不受支持。

  • 是否排除了将更改推送到的分支或路径? 通过将更改推送到包含的分支中包含的路径进行测试。 请注意,触发器中的路径区分大小写。 在触发器中指定路径时,请确保使用与真实文件夹相同的大小写。

  • 你刚刚推送了一个新分支吗? 如果是这样,新分支可能不会启动新的运行。 请参阅“创建新分支时的触发器行为”。

我的 CI 或 PR 触发器一直工作正常。 但是,它们现在停止工作了。

首先完成上一个问题中的故障排除步骤。 然后,执行以下附加步骤:

  • PR 中是否有合并冲突? 对于未触发管道的 PR,请将其打开并检查它是否具有合并冲突。 解决合并冲突。

  • 是否在处理推送或 PR 事件时遇到延迟? 通常可以通过查看该问题是特定于单个管道还是项目中全部管道或存储库所共有的,来验证这一点。 如果对任何存储库的推送或 PR 更新都出现此症状,则可能是在处理更新事件时遇到延迟。 在状态页上检查我们是否遇到服务中断。 如果状态页显示问题,则我们的团队必定已开始处理该问题。 经常查看页面以获取有关该问题的更新。

我不希望用户在更新 YAML 文件时覆盖触发器的分支列表。 如何执行此操作?

有权贡献代码的用户可以更新 YAML 文件并包括/排除其他分支。 因此,用户可以在其 YAML 文件中包含自己的功能或用户分支,并将该更新推送到功能或用户分支。 这可能会导致针对该分支的所有更新触发管道。 如果要阻止此行为,可以执行以下步骤:

  1. 在 Azure Pipelines UI 中编辑管道。
  2. 导航到“触发器”菜单。
  3. 选择“从此处覆盖 YAML 持续集成触发器”。
  4. 指定要为触发器包含或排除的分支。

执行这些步骤时,将忽略 YAML 文件中指定的任何 CI 触发器。

我的 YAML 管道中有多个存储库。 如何为每个存储库设置触发器?

请参阅使用多个存储库中的触发器。

签出失败

在签出步骤期间,我在日志文件中看到以下错误。 如何解决问题?

remote: TF401019: The Git repository with name or identifier XYZ does not exist or you do not have permissions for the operation you are attempting.
fatal: repository 'XYZ' not found
##[error] Git fetch failed with exit code: 128

按照以下步骤对失败的签出进行故障排除:

  • 存储库是否仍然存在? 首先,通过在“存储库”页中打开存储库,确保其确实存在。

  • 是否使用脚本访问存储库? 如果是,请选中“将作业授权范围限制为所引用的 Azure DevOps 存储库”设置。 启用“将作业授权范围限制为引用的 Azure DevOps 存储库”时,将无法使用脚本来签出 Azure Repos Git 存储库,除非先在管道中显式引用了此类存储库。

  • 管道的作业授权范围如何?

    • 如果范围是集合:

      • 这可能是间歇性错误。 重新运行管道。
      • 有人可能已移除了对“项目集合生成服务帐户”访问权限。
        • 转到存储库所在的项目的“项目设置”。 选择“存储库”>“存储库”>“特定存储库”,然后选择“安全”。
        • 检查用户列表中是否存在“项目集合生成服务 (集合名)”。
        • 检查该帐户是否具有“创建标记”和“读取”访问权限。
    • 如果范围是项目:

      • 存储库是否与管道位于同一项目中?
        • 正确:
          • 这可能是间歇性错误。 重新运行管道。
          • 有人可能已移除了对“项目生成服务帐户”访问权限。
            • 转到存储库所在的项目的“项目设置”。 选择“存储库”>“存储库”>“特定存储库”,然后选择“安全”。
            • 检查用户列表中是否存在“<项目名> 生成服务 (集合名)”。
            • 检查该帐户是否具有“创建标记”和“读取”访问权限。
        • 错误:

版本错误

管道中使用了错误的 YAML 文件版本。 为什么会这样?

  • 对于 CI 触发器,你所推送的分支中的 YAML 文件将受到评估,以了解是否应运行 CI 生成。
  • 对于 PR 触发器,因合并 PR 的源分支和目标分支而产生的 YAML 文件将受到评估,以了解是否应运行 PR 生成。