Created on

Azure Devops – Managed Branch Policies – Default Branch


When working with large Azure DevOps projects containing many repositories, setting up consistent branch policies across all default branches can be a challenge—especially when targeting dynamically named default branches (like mainmaster, etc.).

The Problem

Azure DevOps branch policies are typically set per branch (e.g., refs/heads/main), which means hardcoding values that may not be consistent across repositories.

The Solution

Instead of hardcoding branch names, you can use the DefaultBranch match kind when configuring branch policies via the REST API. This approach ensures the policy always applies to each repository’s default branch—no matter what it’s named.

Understanding the Key Setting

In the REST API, the "matchKind": "DefaultBranch" setting within the scope array makes the policy apply to whatever the default branch is for each repository.

"scope": [
  {
    "repositoryId": null,
    "refName": null,
    "matchKind": "DefaultBranch"
  }
]

This is powerful because:

  • repositoryId = null → Applies to all repositories.
  • refName = null → Applies to all branches.
  • matchKind = "DefaultBranch" → Filters the scope to only the default branch of each repository.

Example PowerShell Code

Here’s a PowerShell snippet using the Azure DevOps REST API to apply a merge strategy policy to default branches across all repositories:

$MergeStrategyId = "fa4e907d-c16b-4a4c-9dfa-4916e5d171ab" # Policy Type: Merge Strategy
$MergeStrategyBody = @{
    isEnabled  = $true
    isBlocking = $true
    type       = @{
        id = $MergeStrategyId
    }
    settings   = @{
        allowNoFastForward = $false
        allowSquash        = $true
        allowRebase        = $false
        allowRebaseMerge   = $false
        creatorVoteCounts  = $false
        scope              = @(
            @{
                repositoryId = $null
                refName      = $null
                matchKind    = "DefaultBranch"  # Applies to the default branch of each repo
            }
        )
    }
} | ConvertTo-Json -Depth 10

Don’t forget to authenticate your request using a personal access token (PAT) or service connection.

Then post the policy with something like:

$Project = "your-project-name"
$Org = "https://dev.azure.com/your-org"
$Uri = "$Org/$Project/_apis/policy/configurations?api-version=7.0"

Invoke-RestMethod -Uri $Uri -Method Post -Body $MergeStrategyBody -ContentType "application/json" -Headers @{ Authorization = "Basic $base64AuthInfo" }

Final Tips

  • You can retrieve existing policies via the REST API to reverse-engineer the correct settings (GET _apis/policy/configurations).
  • Replace "fa4e907d-c16b-4a4c-9dfa-4916e5d171ab" with other policy type IDs depending on your policy goals (e.g., reviewer count, build validation).
  • Always test on a test project or repo first to ensure the policy behaves as expected.
  • Use Get to get list of policies and then Put if any existing policy is already present that you want to update, because you need the policy Id to Put (update)