YAML Pipelines
If you're using a YAML-based pipeline, you can use the Checks + Approval Gates feature to add a branch policy check.
- Create an Environment for each deployment environment
- Structure your YAML pipeline to use a Deployment Job that specifies the Environment
stages:
- stage: build
- stage: dev
- stage: test
- stage: preprod
- stage: prod
You can put conditions on the stages to ensure the branch conditions are met.
- stage: production
dependsOn: preprod
condition: |
and(
succeeded('preprod'),
or(
eq(variables['Build.SourceBranch'], 'refs/heads/main'),
startsWith(variables['Build.SourceBranch'], 'refs/heads/release/'),
startsWith(variables['Build.SourceBranch'], 'refs/heads/hotfix/')
)
)
- Ensure each stage that performs the deployment activities has a Deployment Job:
- deployment: deploy
displayName: 'Deploy'
environment: 'Production'
strategy:
runonce:
deploy:
steps:
- pwsh: Write-Host 'Deployment Steps go here!'
In your Production Environment, add the Branch Control check:

Classic Release Pipelines
If you're using a Classic Release pipeline, you can add artifact filters to prevent the pipeline from being queued, but these do not enforce that the Stage cannot be run manually or override these filters.
If you truly want to prevent the release, even if someone manually overrides the artifact filter, you could fail the build by checking that it is the correct branch in a script.
$currentBranch = "$(Release.Artifacts.MyAlias.SourceBranch)"
if ( $currentBranch -ne "refs/heads/main" )
{
Write-Host "##vso[task.logissue type=error]This release must originate from the main branch. Current branch: $currentBranch"
Exit 1
}
