AI Code Review

Feb 27, 2026

Branch Policies in Azure DevOps: Every Setting, CLI Command, and Configuration Guide

Amartya | CodeAnt AI Code Review Platform
Sonali Sood

Founding GTM, CodeAnt AI

Every engineering team eventually asks the same question:

“How do we stop risky code from reaching the main branch?”

In Azure DevOps, the answer is branch policies.

Branch policies are the enforcement layer of your pull request workflow. They define exactly what must happen before code can merge into a protected branch like main, develop, or release/*.

Instead of relying on developers to follow best practices manually, Azure DevOps can enforce rules such as:

  • minimum number of reviewers

  • successful CI builds

  • resolved review comments

  • linked work items

  • restricted merge strategies

  • required status checks from security tools

Once these policies are enabled, Azure DevOps blocks merge automatically until every condition passes.

This guide explains everything you need to configure branch protection correctly, including:

  • every branch policy setting and what it does

  • recommended configurations for different team sizes

  • CLI commands to automate policy setup

  • best practices used by enterprise teams

  • common policy conflicts and how to fix them

By the end, you’ll know exactly how to enforce safe, auditable pull request workflows in Azure DevOps.

What Are Branch Policies in Azure DevOps?

Branch policies are server-side rules that Azure DevOps enforces on pull requests targeting a specific branch. When a policy is enabled on a branch, Azure DevOps blocks direct pushes to that branch and requires all changes to go through a pull request that satisfies every configured policy before it can be completed.

Branch policies answer the question: “What conditions must be met before code can merge into this branch?” They are the enforcement layer, they don’t suggest or recommend; they block. A PR cannot be completed until every required policy shows a passing status, regardless of how many reviewers have approved.

Policies are configured per branch (or per branch pattern like release/*) and per repository. You can have strict policies on main, lighter policies on develop, and different policies on release branches, all within the same repository.

For a full overview of how policies fit into the code review workflow, see the complete Azure DevOps code review guide. For who can configure and bypass policies, see the permissions guide.

Complete Policy Settings Reference

Navigate to: Project Settings → Repos → Repositories → [Select repo] → Policies → [Select branch]

1. Require Minimum Number of Reviewers

This policy blocks merge until a minimum number of reviewers have approved the PR.

Setting

Options

Recommended

What It Does

Minimum number of reviewers

1–10

1 (small teams), 2 (6+ devs)

The number of unique approvers required before merge

Allow requestors to approve their own changes

Checked / Unchecked

Unchecked

If checked, the PR author’s approval counts toward the minimum. Uncheck to enforce independent review.

Prohibit the most recent pusher from approving their own changes

Checked / Unchecked

Checked

Prevents the person who pushed the latest commit from being one of the approvers. Closes the loophole where a reviewer pushes a “minor fix” and then approves their own push.

Allow completion even if some reviewers vote “Wait for author” or “Reject”

Checked / Unchecked

Unchecked

If checked, the minimum count of approvals is sufficient even if other reviewers voted negatively. Unchecked means any Reject or Wait blocks completion.

When new changes are pushed

Reset all approval votes / Reset approval votes of the person pushing / Do not reset

Reset all approval votes

Controls whether existing approvals remain valid after the author pushes new commits. “Reset all” forces re-review after every push — the strictest option. “Reset approval votes of the person pushing” is a middle ground.

CLI command:

az repos policy approver-count create \\
  --allow-downvotes false \\
  --blocking true \\
  --branch main \\
  --creator-vote-counts false \\
  --enabled true \\
  --minimum-approver-count 2 \\
  --repository-id <REPO_ID> \\
  --reset-on-source-push true
az repos policy approver-count create \\
  --allow-downvotes false \\
  --blocking true \\
  --branch main \\
  --creator-vote-counts false \\
  --enabled true \\
  --minimum-approver-count 2 \\
  --repository-id <REPO_ID> \\
  --reset-on-source-push true

Common mistake: Setting minimum reviewers to 2 on a team of 3 developers means PRs block until 2/3 of the team reviews. On small teams, start with 1 required reviewer to avoid bottlenecks.

2. Check for Linked Work Items

Requires the PR to be linked to at least one Azure Boards work item (task, bug, user story, etc.).

Setting

Options

Recommended

What It Does

Requirement

Required / Optional

Required

“Required” blocks merge if no work item is linked. “Optional” shows a warning but doesn’t block.

CLI command:

az repos policy work-item-linking create \\
  --blocking true \\
  --branch main \\
  --enabled true \\
  --repository-id

az repos policy work-item-linking create \\
  --blocking true \\
  --branch main \\
  --enabled true \\
  --repository-id

Why it matters: Work item linking creates traceability — every code change maps to a tracked piece of work. This is essential for audits, compliance, and understanding why a change was made six months later.

3. Check for Comment Resolution

Blocks merge until all PR comments are resolved.

Setting

Options

Recommended

What It Does

Requirement

Required / Optional

Required

“Required” blocks merge if any active (unresolved) comment exists on the PR. “Optional” shows a warning but allows merge.

CLI command:

az repos policy comment-required create \\
  --blocking true \\
  --branch main \\
  --enabled true \\
  --repository-id

az repos policy comment-required create \\
  --blocking true \\
  --branch main \\
  --enabled true \\
  --repository-id

How resolution works: A comment can be resolved by anyone with “Contribute to pull requests” permission — the author, the reviewer who left it, or any other reviewer. Reviewers can also mark comments as “Won’t Fix” which counts as resolved. This prevents PRs from being stuck on a single unresponsive reviewer’s comment.

4. Limit Merge Types

Restricts which merge strategies are available when completing a PR targeting this branch.

Setting

Options

Recommended

What It Does

Basic merge (no fast-forward)

Allowed / Not allowed

Branch-dependent

Standard merge commit. Best for develop→main where you want merge points visible.

Squash merge

Allowed / Not allowed

Branch-dependent

Collapses all PR commits into one. Best for feature→develop to keep history clean.

Rebase and fast-forward

Allowed / Not allowed

Branch-dependent

Replays commits on top of target. Produces linear history but rewrites commit hashes.

Semi-linear merge

Allowed / Not allowed

Branch-dependent

Rebases first, then creates merge commit. Linear + merge points. Strictest, requires no conflicts before merge.

CLI command:

az repos policy merge-strategy create \\
  --blocking true \\
  --branch main \\
  --enabled true \\
  --repository-id <REPO_ID> \\
  --allow-no-fast-forward true \\
  --allow-squash true \\
  --allow-rebase false \\
  --allow-rebase-merge false
az repos policy merge-strategy create \\
  --blocking true \\
  --branch main \\
  --enabled true \\
  --repository-id <REPO_ID> \\
  --allow-no-fast-forward true \\
  --allow-squash true \\
  --allow-rebase false \\
  --allow-rebase-merge false

Recommended per branch:

Branch

Allowed Strategies

Rationale

main

Merge commit only

Preserve merge points for release tracking

develop

Squash only

Clean history, one commit per feature

release/*

Merge commit only

Preserve full history for hotfix traceability

feature/*

No policy needed

Feature branches are typically short-lived

For a deep dive on each strategy with visual history diagrams, see the merge strategies guide.

5. Build Validation

Runs an Azure Pipeline and requires it to pass before merge. This is how you enforce automated tests, linting, security scans, and build verification on every PR.

Setting

Options

Recommended

What It Does

Build pipeline

Select from available pipelines

Your CI pipeline

Which pipeline to trigger when the PR is created or updated

Trigger

Automatic / Manual

Automatic

“Automatic” triggers the build on every PR create/update. “Manual” requires someone to queue it.

Policy requirement

Required / Optional

Required

“Required” blocks merge if the build fails. “Optional” shows status but doesn’t block.

Build expiration

Immediately / After N hours / Never

After 12 hours or Immediately when target branch updates

Controls when a passing build becomes stale and needs re-running. “Immediately” re-triggers when the target branch changes. “After N hours” expires after the set period.

Display name

Free text

Descriptive (e.g., “CI Build + Tests”)

Shown on the PR status — use clear names so developers know what failed

Path filter (optional)

Include/exclude paths

Use when pipelines are path-specific

Trigger build only when files in specific paths change. Useful for monorepos with separate pipelines per service.

CLI command:

az repos policy build create \\
  --blocking true \\
  --branch main \\
  --build-definition-id <PIPELINE_ID> \\
  --display-name "CI Build + Tests" \\
  --enabled true \\
  --manual-queue-only false \\
  --queue-on-source-update-only true \\
  --repository-id <REPO_ID> \\
  --valid-duration 720
az repos policy build create \\
  --blocking true \\
  --branch main \\
  --build-definition-id <PIPELINE_ID> \\
  --display-name "CI Build + Tests" \\
  --enabled true \\
  --manual-queue-only false \\
  --queue-on-source-update-only true \\
  --repository-id <REPO_ID> \\
  --valid-duration 720

The --valid-duration is in minutes. 720 = 12 hours. Set to 0 for “Immediately when target branch updates.”

Multiple build validations: You can add more than one build validation policy to the same branch. For example, add your CI pipeline and a separate security scan pipeline. Both must pass before merge. Each one is configured independently.

6. Status Checks (External Services)

Blocks merge until an external service posts a “succeeded” status on the PR. This is how external tools like AI code reviewers, third-party SAST scanners, and coverage analyzers integrate with Azure DevOps branch policies.

Setting

Options

Recommended

What It Does

Status to check

Select from posted statuses

Tool-specific (e.g., codeantai/review)

The status key that the external tool posts. You’ll see available statuses after the tool has posted at least once.

Policy requirement

Required / Optional

Required for security tools

“Required” blocks merge until the status is “succeeded.”

Authorized account

Any / Specific account

Specific account

Restricts who can post this status. Set to the service account or PAT identity used by the tool — prevents anyone from spoofing a passing status.

Reset status

When source branch changes / Never

When source branch changes

Controls whether the status resets (requires re-check) when the author pushes new commits.

CLI command:

az repos policy status create \\
  --blocking true \\
  --branch main \\
  --enabled true \\
  --repository-id <REPO_ID> \\
  --status "codeantai/review" \\
  --status-genre "codeantai"
az repos policy status create \\
  --blocking true \\
  --branch main \\
  --enabled true \\
  --repository-id <REPO_ID> \\
  --status "codeantai/review" \\
  --status-genre "codeantai"

How external tools post status: External tools use the Azure DevOps REST API (POST /_apis/git/repositories/{id}/pullRequests/{id}/statuses) to post a status with a state (succeeded, failed, pending, error) and a target URL. Once a matching status check policy is configured, Azure DevOps blocks merge until the tool posts succeeded.

7. Automatically Included Reviewers

Auto-assigns specific reviewers when a PR modifies files matching a path filter. This is Azure DevOps’s equivalent of GitHub CODEOWNERS.

Setting

Options

Recommended

What It Does

Reviewers

Users or groups

Use groups

Who to auto-add. Use groups so the team isn’t blocked when one person is unavailable.

Path filter (optional)

File path patterns

Scope to sensitive paths

Which file changes trigger this reviewer. Example: /src/api/*, *.sql, /infrastructure/*. Leave empty to trigger on all files.

Policy requirement

Required / Optional

Required for sensitive paths

“Required” means this reviewer must approve before merge. “Optional” means they’re added but don’t block.

Allow requestors to approve their own changes

Checked / Unchecked

Unchecked

If the PR author is the auto-included reviewer (e.g., they’re in the security group), can they approve their own PR? Usually no.

If the source branch involves a merge with the target

Checked / Unchecked

Unchecked

Technical edge case — whether merge commits from the target branch count as file changes for path filtering.

CLI command:

az repos policy required-reviewer create \\
  --blocking true \\
  --branch main \\
  --enabled true \\
  --repository-id <REPO_ID> \\
  --required-reviewer-ids "<USER_OR_GROUP_ID>" \\
  --path-filter "/src/security/*" \\
  --message "Security team review required for changes to security modules"
az repos policy required-reviewer create \\
  --blocking true \\
  --branch main \\
  --enabled true \\
  --repository-id <REPO_ID> \\
  --required-reviewer-ids "<USER_OR_GROUP_ID>" \\
  --path-filter "/src/security/*" \\
  --message "Security team review required for changes to security modules"

Example configuration for a typical enterprise:

Path Filter

Reviewer Group

Required?

Use Case

/src/api/*

Backend Team

Required

API changes need backend review

/src/frontend/*

Frontend Team

Required

UI changes need frontend review

/infrastructure/*

DevOps Team

Required

Infra changes need ops review

*.sql, /migrations/*

DBA Team

Required

Schema changes need DBA review

/src/auth/*, /src/security/*

Security Team

Required

Auth/security changes need security review

/docs/*

Tech Writers

Optional

Doc changes benefit from but don’t require writer review

For a detailed comparison between GitHub CODEOWNERS and Azure DevOps auto-reviewers, including a migration guide, see the permissions guide.

Step-by-Step: Configure Branch Policies via the Web UI

Protecting the main Branch (From Zero to Production-Ready)

Step 1: Navigate to branch policies

Go to Project Settings → Repos → Repositories → [Select your repo] → Policies. Select the branch you want to protect (e.g., main).

If your branch doesn’t appear in the list, click Add branch protection and type the branch name or pattern.

Step 2: Enable minimum reviewers

Toggle Require a minimum number of reviewers to ON. Set the count to 1 (small teams) or 2 (teams of 6+). Uncheck “Allow requestors to approve their own changes.” Set “When new changes are pushed” to “Reset all approval votes.”

From this moment, no one can push directly to main. All changes must go through a PR with at least one independent approval.

Step 3: Require linked work items

Toggle Check for linked work items to ON. Set to Required. Every PR must now link to at least one Azure Boards work item.

Step 4: Require comment resolution

Toggle Check for comment resolution to ON. Set to Required. PRs cannot be merged until all review comments are resolved.

Step 5: Add build validation

Under Build Validation, click + Add build policy. Select your CI pipeline. Set trigger to Automatic, requirement to Required, and build expiration to 12 hours or Immediately when target branch is updated. Give it a clear display name like “CI Build + Unit Tests.”

Step 6: Restrict merge types

Under Limit merge types, check only the strategies your team uses. For main, a common choice is merge commit only (preserves merge points) or squash only (clean one-commit-per-PR history).

Step 7: Add external status checks (optional)

Under Status checks, click + Add status policy. Select the status posted by your external tools (e.g., CodeAnt AI). Set to Required and configure the authorized account.

Step 8: Add auto-included reviewers (optional)

Under Automatically included reviewers, click + Add. Add groups for sensitive file paths — security team for /src/auth/*, DBA team for *.sql, etc.

Result: Your main branch now requires:

  • At least N independent approvals (no self-approval)

  • Linked work item

  • All comments resolved

  • Passing CI build

  • Passing external status checks (if configured)

  • Specific reviewers for sensitive file paths (if configured)

  • Only allowed merge strategies

Step-by-Step: Configure All Policies via CLI

The CLI is essential when managing policies across multiple repositories. Every policy type has a create, update, list, and delete command.

List All Existing Policies

# List all policies on a branch
az repos policy list \\
  --repository-id <REPO_ID> \\
  --branch main \\
  --output table

# Get a specific policy's full configuration
az repos policy show --id

# List all policies on a branch
az repos policy list \\
  --repository-id <REPO_ID> \\
  --branch main \\
  --output table

# Get a specific policy's full configuration
az repos policy show --id

Complete CLI Command Reference

# ──────────────────────────────────────────────
# 1. Minimum reviewers
# ──────────────────────────────────────────────
az repos policy approver-count create \\
  --allow-downvotes false \\
  --blocking true \\
  --branch main \\
  --creator-vote-counts false \\
  --enabled true \\
  --minimum-approver-count 2 \\
  --repository-id <REPO_ID> \\
  --reset-on-source-push true

# ──────────────────────────────────────────────
# 2. Linked work items
# ──────────────────────────────────────────────
az repos policy work-item-linking create \\
  --blocking true \\
  --branch main \\
  --enabled true \\
  --repository-id <REPO_ID>

# ──────────────────────────────────────────────
# 3. Comment resolution
# ──────────────────────────────────────────────
az repos policy comment-required create \\
  --blocking true \\
  --branch main \\
  --enabled true \\
  --repository-id <REPO_ID>

# ──────────────────────────────────────────────
# 4. Merge strategy
# ──────────────────────────────────────────────
az repos policy merge-strategy create \\
  --blocking true \\
  --branch main \\
  --enabled true \\
  --repository-id <REPO_ID> \\
  --allow-no-fast-forward true \\
  --allow-squash true \\
  --allow-rebase false \\
  --allow-rebase-merge false

# ──────────────────────────────────────────────
# 5. Build validation
# ──────────────────────────────────────────────
az repos policy build create \\
  --blocking true \\
  --branch main \\
  --build-definition-id <PIPELINE_ID> \\
  --display-name "CI Build + Tests" \\
  --enabled true \\
  --manual-queue-only false \\
  --queue-on-source-update-only true \\
  --repository-id <REPO_ID> \\
  --valid-duration 720

# ──────────────────────────────────────────────
# 6. Required reviewers (auto-included)
# ──────────────────────────────────────────────
az repos policy required-reviewer create \\
  --blocking true \\
  --branch main \\
  --enabled true \\
  --repository-id <REPO_ID> \\
  --required-reviewer-ids "<USER_OR_GROUP_ID>" \\
  --path-filter "/src/security/*" \\
  --message "Security team review required"

# ──────────────────────────────────────────────
# 7. Status check (external tools)
# ──────────────────────────────────────────────
az repos policy status create \\
  --blocking true \\
  --branch main \\
  --enabled true \\
  --repository-id <REPO_ID> \\
  --status "codeantai/review" \\
  --status-genre "codeantai"
# ──────────────────────────────────────────────
# 1. Minimum reviewers
# ──────────────────────────────────────────────
az repos policy approver-count create \\
  --allow-downvotes false \\
  --blocking true \\
  --branch main \\
  --creator-vote-counts false \\
  --enabled true \\
  --minimum-approver-count 2 \\
  --repository-id <REPO_ID> \\
  --reset-on-source-push true

# ──────────────────────────────────────────────
# 2. Linked work items
# ──────────────────────────────────────────────
az repos policy work-item-linking create \\
  --blocking true \\
  --branch main \\
  --enabled true \\
  --repository-id <REPO_ID>

# ──────────────────────────────────────────────
# 3. Comment resolution
# ──────────────────────────────────────────────
az repos policy comment-required create \\
  --blocking true \\
  --branch main \\
  --enabled true \\
  --repository-id <REPO_ID>

# ──────────────────────────────────────────────
# 4. Merge strategy
# ──────────────────────────────────────────────
az repos policy merge-strategy create \\
  --blocking true \\
  --branch main \\
  --enabled true \\
  --repository-id <REPO_ID> \\
  --allow-no-fast-forward true \\
  --allow-squash true \\
  --allow-rebase false \\
  --allow-rebase-merge false

# ──────────────────────────────────────────────
# 5. Build validation
# ──────────────────────────────────────────────
az repos policy build create \\
  --blocking true \\
  --branch main \\
  --build-definition-id <PIPELINE_ID> \\
  --display-name "CI Build + Tests" \\
  --enabled true \\
  --manual-queue-only false \\
  --queue-on-source-update-only true \\
  --repository-id <REPO_ID> \\
  --valid-duration 720

# ──────────────────────────────────────────────
# 6. Required reviewers (auto-included)
# ──────────────────────────────────────────────
az repos policy required-reviewer create \\
  --blocking true \\
  --branch main \\
  --enabled true \\
  --repository-id <REPO_ID> \\
  --required-reviewer-ids "<USER_OR_GROUP_ID>" \\
  --path-filter "/src/security/*" \\
  --message "Security team review required"

# ──────────────────────────────────────────────
# 7. Status check (external tools)
# ──────────────────────────────────────────────
az repos policy status create \\
  --blocking true \\
  --branch main \\
  --enabled true \\
  --repository-id <REPO_ID> \\
  --status "codeantai/review" \\
  --status-genre "codeantai"

Update and Delete Policies

# Update an existing policy (get policy ID from 'az repos policy list')
az repos policy approver-count update \\
  --id <POLICY_ID> \\
  --minimum-approver-count 3

# Delete a policy
az repos policy delete --id <POLICY_ID> --yes
# Update an existing policy (get policy ID from 'az repos policy list')
az repos policy approver-count update \\
  --id <POLICY_ID> \\
  --minimum-approver-count 3

# Delete a policy
az repos policy delete --id <POLICY_ID> --yes

Recommended Policies by Team Maturity

Tier 1: Startup / Small Team (2–5 Developers)

Priority: Don’t block velocity. Catch the worst mistakes.

Policy

Setting

Why

Minimum reviewers

1

Every change gets a second pair of eyes, but don’t bottleneck on multiple reviewers

Linked work items

Optional

Encourage traceability without blocking quick fixes during early development

Comment resolution

Required

Feedback shouldn’t be ignored, this is low-friction

Build validation

Required (CI pipeline with build + unit tests)

Prevents broken builds from reaching main

Merge type

Squash only

Keeps history clean while the team is moving fast

Auto-reviewers

Not needed yet

Team is small enough that everyone sees every PR

Status checks

Not configured yet

Add when you introduce security scanning tools

Tier 2: Growth Team (6–20 Developers)

Priority: Enforce process without micromanaging. Teams are specializing.

Policy

Setting

Why

Minimum reviewers

2

Two independent reviews catch more issues and reduce bus factor

Linked work items

Required

Non-negotiable — every change maps to tracked work

Comment resolution

Required

Same as Tier 1

Build validation

Required (CI + integration tests + linting)

Expand the CI pipeline as the codebase grows

Merge type

Squash for develop, merge commit for main

Different strategies per branch — clean feature history, visible release points

Auto-reviewers

Required for sensitive paths

Backend team reviews API, DBA reviews SQL, security reviews auth

Vote reset

Reset all votes on new pushes

Prevents stale approvals — critical when PRs are larger and reviews take longer

Status checks

Required (SAST / AI code review)

Add external quality and security checks

Tier 3: Enterprise (20+ Developers, Compliance Requirements)

Priority: Auditability, compliance, zero unreviewed code reaching production.

Policy

Setting

Why

Minimum reviewers

2–3 (branch-dependent)

2 for develop, 3 for main and release branches

Linked work items

Required

Audit requirement — every change traceable to a work item

Comment resolution

Required

Same as Tier 1–2

Build validation

Required (CI + integration + security + compliance checks)

Multiple build validations: unit tests, integration tests, security scans, license compliance

Merge type

Locked per branch

Squash for feature→develop, merge commit for develop→main, merge commit for hotfix→release

Auto-reviewers

Required for all sensitive paths + optional for all others

Security, infrastructure, database, API, and compliance paths all have mandatory reviewers

Vote reset

Reset all votes on new pushes

Non-negotiable for compliance — ensures every commit is reviewed

Status checks

Required (SAST + SCA + AI code review + coverage)

Multiple external checks: CodeAnt AI for code review, security scanning, coverage thresholds

Self-approval

Disabled everywhere

No developer can approve their own changes

Bypass permissions

Restricted to a dedicated “Hotfix Approvers” group

Bypass is audited and available only to senior engineers for emergencies

Policies at Scale: Cross-Repo Scripts

Enterprise teams with dozens or hundreds of repositories need to apply consistent policies without clicking through the UI for each repo. The Azure CLI combined with shell scripting handles this.

Apply Standard Policies to All Repositories

#!/bin/bash
# apply-standard-policies.sh
# Applies minimum viable policies to all repos in a project

ORG="<https://dev.azure.com/your-org>"
PROJECT="your-project"
BRANCH="main"
PIPELINE_ID="<YOUR_CI_PIPELINE_ID>"

# Get all repository IDs
REPO_IDS=$(az repos list \\
  --org "$ORG" \\
  --project "$PROJECT" \\
  --query "[].id" \\
  --output tsv)

for REPO_ID in $REPO_IDS; do
  REPO_NAME=$(az repos show --id "$REPO_ID" --org "$ORG" --project "$PROJECT" --query "name" --output tsv)
  echo "Configuring policies for:$REPO_NAME ($REPO_ID)"

  # 1. Minimum 2 reviewers
  az repos policy approver-count create \\
    --allow-downvotes false \\
    --blocking true \\
    --branch "$BRANCH" \\
    --creator-vote-counts false \\
    --enabled true \\
    --minimum-approver-count 2 \\
    --repository-id "$REPO_ID" \\
    --reset-on-source-push true \\
    --org "$ORG" \\
    --project "$PROJECT" \\
    2>/dev/null && echo "  ✓ Reviewer policy created" || echo "  ⚠ Reviewer policy already exists or failed"

  # 2. Require linked work items
  az repos policy work-item-linking create \\
    --blocking true \\
    --branch "$BRANCH" \\
    --enabled true \\
    --repository-id "$REPO_ID" \\
    --org "$ORG" \\
    --project "$PROJECT" \\
    2>/dev/null && echo "  ✓ Work item policy created" || echo "  ⚠ Work item policy already exists or failed"

  # 3. Require comment resolution
  az repos policy comment-required create \\
    --blocking true \\
    --branch "$BRANCH" \\
    --enabled true \\
    --repository-id "$REPO_ID" \\
    --org "$ORG" \\
    --project "$PROJECT" \\
    2>/dev/null && echo "  ✓ Comment policy created" || echo "  ⚠ Comment policy already exists or failed"

  # 4. Build validation (if pipeline exists for this repo)
  az repos policy build create \\
    --blocking true \\
    --branch "$BRANCH" \\
    --build-definition-id "$PIPELINE_ID" \\
    --display-name "CI Build + Tests" \\
    --enabled true \\
    --manual-queue-only false \\
    --queue-on-source-update-only true \\
    --repository-id "$REPO_ID" \\
    --valid-duration 720 \\
    --org "$ORG" \\
    --project "$PROJECT" \\
    2>/dev/null && echo "  ✓ Build policy created" || echo "  ⚠ Build policy already exists or failed"

  echo "---"
done

echo "Done. Policies applied to all repositories."
#!/bin/bash
# apply-standard-policies.sh
# Applies minimum viable policies to all repos in a project

ORG="<https://dev.azure.com/your-org>"
PROJECT="your-project"
BRANCH="main"
PIPELINE_ID="<YOUR_CI_PIPELINE_ID>"

# Get all repository IDs
REPO_IDS=$(az repos list \\
  --org "$ORG" \\
  --project "$PROJECT" \\
  --query "[].id" \\
  --output tsv)

for REPO_ID in $REPO_IDS; do
  REPO_NAME=$(az repos show --id "$REPO_ID" --org "$ORG" --project "$PROJECT" --query "name" --output tsv)
  echo "Configuring policies for:$REPO_NAME ($REPO_ID)"

  # 1. Minimum 2 reviewers
  az repos policy approver-count create \\
    --allow-downvotes false \\
    --blocking true \\
    --branch "$BRANCH" \\
    --creator-vote-counts false \\
    --enabled true \\
    --minimum-approver-count 2 \\
    --repository-id "$REPO_ID" \\
    --reset-on-source-push true \\
    --org "$ORG" \\
    --project "$PROJECT" \\
    2>/dev/null && echo "  ✓ Reviewer policy created" || echo "  ⚠ Reviewer policy already exists or failed"

  # 2. Require linked work items
  az repos policy work-item-linking create \\
    --blocking true \\
    --branch "$BRANCH" \\
    --enabled true \\
    --repository-id "$REPO_ID" \\
    --org "$ORG" \\
    --project "$PROJECT" \\
    2>/dev/null && echo "  ✓ Work item policy created" || echo "  ⚠ Work item policy already exists or failed"

  # 3. Require comment resolution
  az repos policy comment-required create \\
    --blocking true \\
    --branch "$BRANCH" \\
    --enabled true \\
    --repository-id "$REPO_ID" \\
    --org "$ORG" \\
    --project "$PROJECT" \\
    2>/dev/null && echo "  ✓ Comment policy created" || echo "  ⚠ Comment policy already exists or failed"

  # 4. Build validation (if pipeline exists for this repo)
  az repos policy build create \\
    --blocking true \\
    --branch "$BRANCH" \\
    --build-definition-id "$PIPELINE_ID" \\
    --display-name "CI Build + Tests" \\
    --enabled true \\
    --manual-queue-only false \\
    --queue-on-source-update-only true \\
    --repository-id "$REPO_ID" \\
    --valid-duration 720 \\
    --org "$ORG" \\
    --project "$PROJECT" \\
    2>/dev/null && echo "  ✓ Build policy created" || echo "  ⚠ Build policy already exists or failed"

  echo "---"
done

echo "Done. Policies applied to all repositories."

Audit Policies Across All Repositories

#!/bin/bash
# audit-policies.sh
# Reports which repos have policies and which don't

ORG="<https://dev.azure.com/your-org>"
PROJECT="your-project"
BRANCH="main"

echo "=== Policy Audit:$PROJECT ==="
echo ""

REPO_IDS=$(az repos list \\
  --org "$ORG" \\
  --project "$PROJECT" \\
  --query "[].{id:id, name:name}" \\
  --output json)

echo "$REPO_IDS" | jq -r '.[] | "\\(.id) \\(.name)"' | while read REPO_ID REPO_NAME; do
  POLICY_COUNT=$(az repos policy list \\
    --repository-id "$REPO_ID" \\
    --branch "$BRANCH" \\
    --org "$ORG" \\
    --project "$PROJECT" \\
    --query "length(@)" \\
    --output tsv 2>/dev/null)

  if [ "$POLICY_COUNT" -gt 0 ] 2>/dev/null; then
    echo "✅$REPO_NAME$POLICY_COUNT policies on$BRANCH"
  else
    echo "❌$REPO_NAME — NO policies on$BRANCH"
  fi
done
#!/bin/bash
# audit-policies.sh
# Reports which repos have policies and which don't

ORG="<https://dev.azure.com/your-org>"
PROJECT="your-project"
BRANCH="main"

echo "=== Policy Audit:$PROJECT ==="
echo ""

REPO_IDS=$(az repos list \\
  --org "$ORG" \\
  --project "$PROJECT" \\
  --query "[].{id:id, name:name}" \\
  --output json)

echo "$REPO_IDS" | jq -r '.[] | "\\(.id) \\(.name)"' | while read REPO_ID REPO_NAME; do
  POLICY_COUNT=$(az repos policy list \\
    --repository-id "$REPO_ID" \\
    --branch "$BRANCH" \\
    --org "$ORG" \\
    --project "$PROJECT" \\
    --query "length(@)" \\
    --output tsv 2>/dev/null)

  if [ "$POLICY_COUNT" -gt 0 ] 2>/dev/null; then
    echo "✅$REPO_NAME$POLICY_COUNT policies on$BRANCH"
  else
    echo "❌$REPO_NAME — NO policies on$BRANCH"
  fi
done

Branch Pattern Policies

Instead of protecting individual branches, protect all branches matching a pattern. This is useful for release branches:

# Protect all release/* branches with 2 reviewers + build validation
az repos policy approver-count create \\
  --allow-downvotes false \\
  --blocking true \\
  --branch "release/*" \\
  --creator-vote-counts false \\
  --enabled true \\
  --minimum-approver-count 2 \\
  --repository-id <REPO_ID> \\
  --reset-on-source-push true
# Protect all release/* branches with 2 reviewers + build validation
az repos policy approver-count create \\
  --allow-downvotes false \\
  --blocking true \\
  --branch "release/*" \\
  --creator-vote-counts false \\
  --enabled true \\
  --minimum-approver-count 2 \\
  --repository-id <REPO_ID> \\
  --reset-on-source-push true

Branch patterns use glob matching: release/* matches release/1.0, release/2.0, etc. This means newly created release branches automatically inherit the policy — no manual configuration needed.

Troubleshooting: Common Policy Conflicts and Issues

“All policies pass, but the Complete button is grayed out”

Cause 1: A required reviewer hasn’t voted yet. Even if minimum reviewer count is met (e.g., 2 of 3 required reviewers approved), an auto-included required reviewer who hasn’t voted blocks completion.

Fix: Check the “Reviewers” section on the PR. Look for reviewers marked as “Required” (has a lock icon) who haven’t voted. They must vote “Approve” before the PR can be completed.

Cause 2: Build validation expired. If build expiration is set and the build passed more than N hours ago, it’s considered stale and needs re-running.

Fix: Click “Queue build” to re-trigger the validation pipeline, or ask the PR author to push a new commit (which triggers automatic re-build if configured).

“Build validation keeps re-triggering on every push”

This is expected behavior when “Trigger” is set to “Automatic” and “Queue on source update only” is enabled. Every push to the source branch triggers a new build.

If builds are queueing too frequently: Set “Queue on source update only” to true (ignores target branch updates) and increase the build expiration window. This means the build only re-runs when the PR author pushes new commits, not when someone else merges into main.

“Required reviewer can’t be removed from the PR”

Auto-included reviewers (from “Automatically included reviewers” policy) cannot be removed from the PR manually. They’re added by the policy and will remain for the lifetime of the PR.

Workaround: If the required reviewer is unavailable (on leave, left the company), a Project Administrator can temporarily disable the auto-included reviewer policy, complete the PR, and re-enable it. Alternatively, use groups instead of individuals so that any group member can satisfy the requirement.

“PR shows merge conflicts but I can’t resolve them”

Branch policies block the merge button when there are conflicts, but Azure DevOps doesn’t provide an in-browser conflict resolution tool for all merge types.

Fix: Resolve conflicts locally: pull the target branch into your feature branch (git merge main), resolve conflicts, commit, and push. The PR will update and the conflict status will clear.

“Status check is stuck on ‘Pending’”

An external tool (e.g., AI code reviewer, SAST scanner) hasn’t posted its status yet, or it posted but with a different status key than what the policy expects.

Fix: Check if the tool ran successfully (check the tool’s dashboard or logs). Verify the status key matches exactly — the policy checks for an exact string match on the status name. If the tool uses codeantai/pr-review but the policy expects codeantai/review, it won’t match.

“Policy was configured but it’s not being enforced”

Possible causes:

  1. Policy is on the wrong branch. Policies are per-branch. A policy on main doesn’t apply to PRs targeting develop.

  2. Policy is disabled. Check if the policy is toggled to “Enabled” in the settings.

  3. User has Bypass permission. Users with “Bypass policies when completing pull requests” can merge without satisfying policies. Check the permissions guide for who has this permission.

  4. The policy applies to a branch pattern that doesn’t match. Verify the branch pattern (e.g., release/*) matches the actual branch name.

“Different team members see different merge type options”

This is correct behavior. The merge type dropdown on the Complete dialog only shows strategies allowed by the “Limit merge types” policy. If only squash is allowed, developers only see the squash option.

If a developer sees all merge types, the “Limit merge types” policy may not be enabled on the target branch, or the developer has bypass permissions.

“I want different policies for different file paths, not just different branches”

Azure DevOps branch policies apply per-branch, not per-file-path — with one exception: “Automatically included reviewers” supports path filters. For everything else (build validation, minimum reviewers, merge types), the policy applies to the entire PR regardless of which files changed.

Workaround for build validation: Use path filters in the build validation policy. When you add a build policy, you can set path filters so the build only triggers when specific paths change. This lets you run different pipelines for /src/api/* vs /src/frontend/*.

Add AI Quality Gates with CodeAnt AI

Branch policies enforce process, minimum reviewers, linked work items, passing builds. But they don’t analyze the actual code. A PR can satisfy every policy and still contain security vulnerabilities, logic errors, or performance problems that human reviewers missed.

AI code review fills this gap by adding an intelligent code quality gate that evaluates every line of code, not just whether process was followed.

CodeAnt AI, used by Fortune 500 development teams on Azure DevOps and reviewed on Gartner Peer Insights, integrates as a status check in branch policies. When configured:

  1. A PR is created or updated → Azure DevOps fires a webhook → CodeAnt AI analyzes the full diff

  2. CodeAnt AI posts inline comments for quality and security findings, with one-click fixes developers can apply directly from the PR

  3. CodeAnt AI posts a status check (succeeded or failed) based on the quality gate threshold

  4. The branch policy blocks merge until the status check passes, just like build validation

This means critical security vulnerabilities and code quality issues block the merge, regardless of whether human reviewers caught them. Developers learn from every fix, and leadership dashboards give engineering leaders visibility into code health, review velocity, and security posture across the organization.

To add CodeAnt AI as a required status check:

  1. Install and configure CodeAnt AI (cloud setup guide | self-hosted setup guide)

  2. Create a test PR so CodeAnt AI posts its first status

  3. Go to Project Settings → Repos → Policies → [branch] → Status checks

  4. Add a new status check, select the CodeAnt AI status, and set it to Required

The quality gate now enforces automatically on every PR targeting this branch, no manual intervention needed. If you face any doubt or need help, book your 1:1 with our experts here.

Every engineering team eventually asks the same question:

“How do we stop risky code from reaching the main branch?”

In Azure DevOps, the answer is branch policies.

Branch policies are the enforcement layer of your pull request workflow. They define exactly what must happen before code can merge into a protected branch like main, develop, or release/*.

Instead of relying on developers to follow best practices manually, Azure DevOps can enforce rules such as:

  • minimum number of reviewers

  • successful CI builds

  • resolved review comments

  • linked work items

  • restricted merge strategies

  • required status checks from security tools

Once these policies are enabled, Azure DevOps blocks merge automatically until every condition passes.

This guide explains everything you need to configure branch protection correctly, including:

  • every branch policy setting and what it does

  • recommended configurations for different team sizes

  • CLI commands to automate policy setup

  • best practices used by enterprise teams

  • common policy conflicts and how to fix them

By the end, you’ll know exactly how to enforce safe, auditable pull request workflows in Azure DevOps.

What Are Branch Policies in Azure DevOps?

Branch policies are server-side rules that Azure DevOps enforces on pull requests targeting a specific branch. When a policy is enabled on a branch, Azure DevOps blocks direct pushes to that branch and requires all changes to go through a pull request that satisfies every configured policy before it can be completed.

Branch policies answer the question: “What conditions must be met before code can merge into this branch?” They are the enforcement layer, they don’t suggest or recommend; they block. A PR cannot be completed until every required policy shows a passing status, regardless of how many reviewers have approved.

Policies are configured per branch (or per branch pattern like release/*) and per repository. You can have strict policies on main, lighter policies on develop, and different policies on release branches, all within the same repository.

For a full overview of how policies fit into the code review workflow, see the complete Azure DevOps code review guide. For who can configure and bypass policies, see the permissions guide.

Complete Policy Settings Reference

Navigate to: Project Settings → Repos → Repositories → [Select repo] → Policies → [Select branch]

1. Require Minimum Number of Reviewers

This policy blocks merge until a minimum number of reviewers have approved the PR.

Setting

Options

Recommended

What It Does

Minimum number of reviewers

1–10

1 (small teams), 2 (6+ devs)

The number of unique approvers required before merge

Allow requestors to approve their own changes

Checked / Unchecked

Unchecked

If checked, the PR author’s approval counts toward the minimum. Uncheck to enforce independent review.

Prohibit the most recent pusher from approving their own changes

Checked / Unchecked

Checked

Prevents the person who pushed the latest commit from being one of the approvers. Closes the loophole where a reviewer pushes a “minor fix” and then approves their own push.

Allow completion even if some reviewers vote “Wait for author” or “Reject”

Checked / Unchecked

Unchecked

If checked, the minimum count of approvals is sufficient even if other reviewers voted negatively. Unchecked means any Reject or Wait blocks completion.

When new changes are pushed

Reset all approval votes / Reset approval votes of the person pushing / Do not reset

Reset all approval votes

Controls whether existing approvals remain valid after the author pushes new commits. “Reset all” forces re-review after every push — the strictest option. “Reset approval votes of the person pushing” is a middle ground.

CLI command:

az repos policy approver-count create \\
  --allow-downvotes false \\
  --blocking true \\
  --branch main \\
  --creator-vote-counts false \\
  --enabled true \\
  --minimum-approver-count 2 \\
  --repository-id <REPO_ID> \\
  --reset-on-source-push true

Common mistake: Setting minimum reviewers to 2 on a team of 3 developers means PRs block until 2/3 of the team reviews. On small teams, start with 1 required reviewer to avoid bottlenecks.

2. Check for Linked Work Items

Requires the PR to be linked to at least one Azure Boards work item (task, bug, user story, etc.).

Setting

Options

Recommended

What It Does

Requirement

Required / Optional

Required

“Required” blocks merge if no work item is linked. “Optional” shows a warning but doesn’t block.

CLI command:

az repos policy work-item-linking create \\
  --blocking true \\
  --branch main \\
  --enabled true \\
  --repository-id

Why it matters: Work item linking creates traceability — every code change maps to a tracked piece of work. This is essential for audits, compliance, and understanding why a change was made six months later.

3. Check for Comment Resolution

Blocks merge until all PR comments are resolved.

Setting

Options

Recommended

What It Does

Requirement

Required / Optional

Required

“Required” blocks merge if any active (unresolved) comment exists on the PR. “Optional” shows a warning but allows merge.

CLI command:

az repos policy comment-required create \\
  --blocking true \\
  --branch main \\
  --enabled true \\
  --repository-id

How resolution works: A comment can be resolved by anyone with “Contribute to pull requests” permission — the author, the reviewer who left it, or any other reviewer. Reviewers can also mark comments as “Won’t Fix” which counts as resolved. This prevents PRs from being stuck on a single unresponsive reviewer’s comment.

4. Limit Merge Types

Restricts which merge strategies are available when completing a PR targeting this branch.

Setting

Options

Recommended

What It Does

Basic merge (no fast-forward)

Allowed / Not allowed

Branch-dependent

Standard merge commit. Best for develop→main where you want merge points visible.

Squash merge

Allowed / Not allowed

Branch-dependent

Collapses all PR commits into one. Best for feature→develop to keep history clean.

Rebase and fast-forward

Allowed / Not allowed

Branch-dependent

Replays commits on top of target. Produces linear history but rewrites commit hashes.

Semi-linear merge

Allowed / Not allowed

Branch-dependent

Rebases first, then creates merge commit. Linear + merge points. Strictest, requires no conflicts before merge.

CLI command:

az repos policy merge-strategy create \\
  --blocking true \\
  --branch main \\
  --enabled true \\
  --repository-id <REPO_ID> \\
  --allow-no-fast-forward true \\
  --allow-squash true \\
  --allow-rebase false \\
  --allow-rebase-merge false

Recommended per branch:

Branch

Allowed Strategies

Rationale

main

Merge commit only

Preserve merge points for release tracking

develop

Squash only

Clean history, one commit per feature

release/*

Merge commit only

Preserve full history for hotfix traceability

feature/*

No policy needed

Feature branches are typically short-lived

For a deep dive on each strategy with visual history diagrams, see the merge strategies guide.

5. Build Validation

Runs an Azure Pipeline and requires it to pass before merge. This is how you enforce automated tests, linting, security scans, and build verification on every PR.

Setting

Options

Recommended

What It Does

Build pipeline

Select from available pipelines

Your CI pipeline

Which pipeline to trigger when the PR is created or updated

Trigger

Automatic / Manual

Automatic

“Automatic” triggers the build on every PR create/update. “Manual” requires someone to queue it.

Policy requirement

Required / Optional

Required

“Required” blocks merge if the build fails. “Optional” shows status but doesn’t block.

Build expiration

Immediately / After N hours / Never

After 12 hours or Immediately when target branch updates

Controls when a passing build becomes stale and needs re-running. “Immediately” re-triggers when the target branch changes. “After N hours” expires after the set period.

Display name

Free text

Descriptive (e.g., “CI Build + Tests”)

Shown on the PR status — use clear names so developers know what failed

Path filter (optional)

Include/exclude paths

Use when pipelines are path-specific

Trigger build only when files in specific paths change. Useful for monorepos with separate pipelines per service.

CLI command:

az repos policy build create \\
  --blocking true \\
  --branch main \\
  --build-definition-id <PIPELINE_ID> \\
  --display-name "CI Build + Tests" \\
  --enabled true \\
  --manual-queue-only false \\
  --queue-on-source-update-only true \\
  --repository-id <REPO_ID> \\
  --valid-duration 720

The --valid-duration is in minutes. 720 = 12 hours. Set to 0 for “Immediately when target branch updates.”

Multiple build validations: You can add more than one build validation policy to the same branch. For example, add your CI pipeline and a separate security scan pipeline. Both must pass before merge. Each one is configured independently.

6. Status Checks (External Services)

Blocks merge until an external service posts a “succeeded” status on the PR. This is how external tools like AI code reviewers, third-party SAST scanners, and coverage analyzers integrate with Azure DevOps branch policies.

Setting

Options

Recommended

What It Does

Status to check

Select from posted statuses

Tool-specific (e.g., codeantai/review)

The status key that the external tool posts. You’ll see available statuses after the tool has posted at least once.

Policy requirement

Required / Optional

Required for security tools

“Required” blocks merge until the status is “succeeded.”

Authorized account

Any / Specific account

Specific account

Restricts who can post this status. Set to the service account or PAT identity used by the tool — prevents anyone from spoofing a passing status.

Reset status

When source branch changes / Never

When source branch changes

Controls whether the status resets (requires re-check) when the author pushes new commits.

CLI command:

az repos policy status create \\
  --blocking true \\
  --branch main \\
  --enabled true \\
  --repository-id <REPO_ID> \\
  --status "codeantai/review" \\
  --status-genre "codeantai"

How external tools post status: External tools use the Azure DevOps REST API (POST /_apis/git/repositories/{id}/pullRequests/{id}/statuses) to post a status with a state (succeeded, failed, pending, error) and a target URL. Once a matching status check policy is configured, Azure DevOps blocks merge until the tool posts succeeded.

7. Automatically Included Reviewers

Auto-assigns specific reviewers when a PR modifies files matching a path filter. This is Azure DevOps’s equivalent of GitHub CODEOWNERS.

Setting

Options

Recommended

What It Does

Reviewers

Users or groups

Use groups

Who to auto-add. Use groups so the team isn’t blocked when one person is unavailable.

Path filter (optional)

File path patterns

Scope to sensitive paths

Which file changes trigger this reviewer. Example: /src/api/*, *.sql, /infrastructure/*. Leave empty to trigger on all files.

Policy requirement

Required / Optional

Required for sensitive paths

“Required” means this reviewer must approve before merge. “Optional” means they’re added but don’t block.

Allow requestors to approve their own changes

Checked / Unchecked

Unchecked

If the PR author is the auto-included reviewer (e.g., they’re in the security group), can they approve their own PR? Usually no.

If the source branch involves a merge with the target

Checked / Unchecked

Unchecked

Technical edge case — whether merge commits from the target branch count as file changes for path filtering.

CLI command:

az repos policy required-reviewer create \\
  --blocking true \\
  --branch main \\
  --enabled true \\
  --repository-id <REPO_ID> \\
  --required-reviewer-ids "<USER_OR_GROUP_ID>" \\
  --path-filter "/src/security/*" \\
  --message "Security team review required for changes to security modules"

Example configuration for a typical enterprise:

Path Filter

Reviewer Group

Required?

Use Case

/src/api/*

Backend Team

Required

API changes need backend review

/src/frontend/*

Frontend Team

Required

UI changes need frontend review

/infrastructure/*

DevOps Team

Required

Infra changes need ops review

*.sql, /migrations/*

DBA Team

Required

Schema changes need DBA review

/src/auth/*, /src/security/*

Security Team

Required

Auth/security changes need security review

/docs/*

Tech Writers

Optional

Doc changes benefit from but don’t require writer review

For a detailed comparison between GitHub CODEOWNERS and Azure DevOps auto-reviewers, including a migration guide, see the permissions guide.

Step-by-Step: Configure Branch Policies via the Web UI

Protecting the main Branch (From Zero to Production-Ready)

Step 1: Navigate to branch policies

Go to Project Settings → Repos → Repositories → [Select your repo] → Policies. Select the branch you want to protect (e.g., main).

If your branch doesn’t appear in the list, click Add branch protection and type the branch name or pattern.

Step 2: Enable minimum reviewers

Toggle Require a minimum number of reviewers to ON. Set the count to 1 (small teams) or 2 (teams of 6+). Uncheck “Allow requestors to approve their own changes.” Set “When new changes are pushed” to “Reset all approval votes.”

From this moment, no one can push directly to main. All changes must go through a PR with at least one independent approval.

Step 3: Require linked work items

Toggle Check for linked work items to ON. Set to Required. Every PR must now link to at least one Azure Boards work item.

Step 4: Require comment resolution

Toggle Check for comment resolution to ON. Set to Required. PRs cannot be merged until all review comments are resolved.

Step 5: Add build validation

Under Build Validation, click + Add build policy. Select your CI pipeline. Set trigger to Automatic, requirement to Required, and build expiration to 12 hours or Immediately when target branch is updated. Give it a clear display name like “CI Build + Unit Tests.”

Step 6: Restrict merge types

Under Limit merge types, check only the strategies your team uses. For main, a common choice is merge commit only (preserves merge points) or squash only (clean one-commit-per-PR history).

Step 7: Add external status checks (optional)

Under Status checks, click + Add status policy. Select the status posted by your external tools (e.g., CodeAnt AI). Set to Required and configure the authorized account.

Step 8: Add auto-included reviewers (optional)

Under Automatically included reviewers, click + Add. Add groups for sensitive file paths — security team for /src/auth/*, DBA team for *.sql, etc.

Result: Your main branch now requires:

  • At least N independent approvals (no self-approval)

  • Linked work item

  • All comments resolved

  • Passing CI build

  • Passing external status checks (if configured)

  • Specific reviewers for sensitive file paths (if configured)

  • Only allowed merge strategies

Step-by-Step: Configure All Policies via CLI

The CLI is essential when managing policies across multiple repositories. Every policy type has a create, update, list, and delete command.

List All Existing Policies

# List all policies on a branch
az repos policy list \\
  --repository-id <REPO_ID> \\
  --branch main \\
  --output table

# Get a specific policy's full configuration
az repos policy show --id

Complete CLI Command Reference

# ──────────────────────────────────────────────
# 1. Minimum reviewers
# ──────────────────────────────────────────────
az repos policy approver-count create \\
  --allow-downvotes false \\
  --blocking true \\
  --branch main \\
  --creator-vote-counts false \\
  --enabled true \\
  --minimum-approver-count 2 \\
  --repository-id <REPO_ID> \\
  --reset-on-source-push true

# ──────────────────────────────────────────────
# 2. Linked work items
# ──────────────────────────────────────────────
az repos policy work-item-linking create \\
  --blocking true \\
  --branch main \\
  --enabled true \\
  --repository-id <REPO_ID>

# ──────────────────────────────────────────────
# 3. Comment resolution
# ──────────────────────────────────────────────
az repos policy comment-required create \\
  --blocking true \\
  --branch main \\
  --enabled true \\
  --repository-id <REPO_ID>

# ──────────────────────────────────────────────
# 4. Merge strategy
# ──────────────────────────────────────────────
az repos policy merge-strategy create \\
  --blocking true \\
  --branch main \\
  --enabled true \\
  --repository-id <REPO_ID> \\
  --allow-no-fast-forward true \\
  --allow-squash true \\
  --allow-rebase false \\
  --allow-rebase-merge false

# ──────────────────────────────────────────────
# 5. Build validation
# ──────────────────────────────────────────────
az repos policy build create \\
  --blocking true \\
  --branch main \\
  --build-definition-id <PIPELINE_ID> \\
  --display-name "CI Build + Tests" \\
  --enabled true \\
  --manual-queue-only false \\
  --queue-on-source-update-only true \\
  --repository-id <REPO_ID> \\
  --valid-duration 720

# ──────────────────────────────────────────────
# 6. Required reviewers (auto-included)
# ──────────────────────────────────────────────
az repos policy required-reviewer create \\
  --blocking true \\
  --branch main \\
  --enabled true \\
  --repository-id <REPO_ID> \\
  --required-reviewer-ids "<USER_OR_GROUP_ID>" \\
  --path-filter "/src/security/*" \\
  --message "Security team review required"

# ──────────────────────────────────────────────
# 7. Status check (external tools)
# ──────────────────────────────────────────────
az repos policy status create \\
  --blocking true \\
  --branch main \\
  --enabled true \\
  --repository-id <REPO_ID> \\
  --status "codeantai/review" \\
  --status-genre "codeantai"

Update and Delete Policies

# Update an existing policy (get policy ID from 'az repos policy list')
az repos policy approver-count update \\
  --id <POLICY_ID> \\
  --minimum-approver-count 3

# Delete a policy
az repos policy delete --id <POLICY_ID> --yes

Recommended Policies by Team Maturity

Tier 1: Startup / Small Team (2–5 Developers)

Priority: Don’t block velocity. Catch the worst mistakes.

Policy

Setting

Why

Minimum reviewers

1

Every change gets a second pair of eyes, but don’t bottleneck on multiple reviewers

Linked work items

Optional

Encourage traceability without blocking quick fixes during early development

Comment resolution

Required

Feedback shouldn’t be ignored, this is low-friction

Build validation

Required (CI pipeline with build + unit tests)

Prevents broken builds from reaching main

Merge type

Squash only

Keeps history clean while the team is moving fast

Auto-reviewers

Not needed yet

Team is small enough that everyone sees every PR

Status checks

Not configured yet

Add when you introduce security scanning tools

Tier 2: Growth Team (6–20 Developers)

Priority: Enforce process without micromanaging. Teams are specializing.

Policy

Setting

Why

Minimum reviewers

2

Two independent reviews catch more issues and reduce bus factor

Linked work items

Required

Non-negotiable — every change maps to tracked work

Comment resolution

Required

Same as Tier 1

Build validation

Required (CI + integration tests + linting)

Expand the CI pipeline as the codebase grows

Merge type

Squash for develop, merge commit for main

Different strategies per branch — clean feature history, visible release points

Auto-reviewers

Required for sensitive paths

Backend team reviews API, DBA reviews SQL, security reviews auth

Vote reset

Reset all votes on new pushes

Prevents stale approvals — critical when PRs are larger and reviews take longer

Status checks

Required (SAST / AI code review)

Add external quality and security checks

Tier 3: Enterprise (20+ Developers, Compliance Requirements)

Priority: Auditability, compliance, zero unreviewed code reaching production.

Policy

Setting

Why

Minimum reviewers

2–3 (branch-dependent)

2 for develop, 3 for main and release branches

Linked work items

Required

Audit requirement — every change traceable to a work item

Comment resolution

Required

Same as Tier 1–2

Build validation

Required (CI + integration + security + compliance checks)

Multiple build validations: unit tests, integration tests, security scans, license compliance

Merge type

Locked per branch

Squash for feature→develop, merge commit for develop→main, merge commit for hotfix→release

Auto-reviewers

Required for all sensitive paths + optional for all others

Security, infrastructure, database, API, and compliance paths all have mandatory reviewers

Vote reset

Reset all votes on new pushes

Non-negotiable for compliance — ensures every commit is reviewed

Status checks

Required (SAST + SCA + AI code review + coverage)

Multiple external checks: CodeAnt AI for code review, security scanning, coverage thresholds

Self-approval

Disabled everywhere

No developer can approve their own changes

Bypass permissions

Restricted to a dedicated “Hotfix Approvers” group

Bypass is audited and available only to senior engineers for emergencies

Policies at Scale: Cross-Repo Scripts

Enterprise teams with dozens or hundreds of repositories need to apply consistent policies without clicking through the UI for each repo. The Azure CLI combined with shell scripting handles this.

Apply Standard Policies to All Repositories

#!/bin/bash
# apply-standard-policies.sh
# Applies minimum viable policies to all repos in a project

ORG="<https://dev.azure.com/your-org>"
PROJECT="your-project"
BRANCH="main"
PIPELINE_ID="<YOUR_CI_PIPELINE_ID>"

# Get all repository IDs
REPO_IDS=$(az repos list \\
  --org "$ORG" \\
  --project "$PROJECT" \\
  --query "[].id" \\
  --output tsv)

for REPO_ID in $REPO_IDS; do
  REPO_NAME=$(az repos show --id "$REPO_ID" --org "$ORG" --project "$PROJECT" --query "name" --output tsv)
  echo "Configuring policies for:$REPO_NAME ($REPO_ID)"

  # 1. Minimum 2 reviewers
  az repos policy approver-count create \\
    --allow-downvotes false \\
    --blocking true \\
    --branch "$BRANCH" \\
    --creator-vote-counts false \\
    --enabled true \\
    --minimum-approver-count 2 \\
    --repository-id "$REPO_ID" \\
    --reset-on-source-push true \\
    --org "$ORG" \\
    --project "$PROJECT" \\
    2>/dev/null && echo "  ✓ Reviewer policy created" || echo "  ⚠ Reviewer policy already exists or failed"

  # 2. Require linked work items
  az repos policy work-item-linking create \\
    --blocking true \\
    --branch "$BRANCH" \\
    --enabled true \\
    --repository-id "$REPO_ID" \\
    --org "$ORG" \\
    --project "$PROJECT" \\
    2>/dev/null && echo "  ✓ Work item policy created" || echo "  ⚠ Work item policy already exists or failed"

  # 3. Require comment resolution
  az repos policy comment-required create \\
    --blocking true \\
    --branch "$BRANCH" \\
    --enabled true \\
    --repository-id "$REPO_ID" \\
    --org "$ORG" \\
    --project "$PROJECT" \\
    2>/dev/null && echo "  ✓ Comment policy created" || echo "  ⚠ Comment policy already exists or failed"

  # 4. Build validation (if pipeline exists for this repo)
  az repos policy build create \\
    --blocking true \\
    --branch "$BRANCH" \\
    --build-definition-id "$PIPELINE_ID" \\
    --display-name "CI Build + Tests" \\
    --enabled true \\
    --manual-queue-only false \\
    --queue-on-source-update-only true \\
    --repository-id "$REPO_ID" \\
    --valid-duration 720 \\
    --org "$ORG" \\
    --project "$PROJECT" \\
    2>/dev/null && echo "  ✓ Build policy created" || echo "  ⚠ Build policy already exists or failed"

  echo "---"
done

echo "Done. Policies applied to all repositories."

Audit Policies Across All Repositories

#!/bin/bash
# audit-policies.sh
# Reports which repos have policies and which don't

ORG="<https://dev.azure.com/your-org>"
PROJECT="your-project"
BRANCH="main"

echo "=== Policy Audit:$PROJECT ==="
echo ""

REPO_IDS=$(az repos list \\
  --org "$ORG" \\
  --project "$PROJECT" \\
  --query "[].{id:id, name:name}" \\
  --output json)

echo "$REPO_IDS" | jq -r '.[] | "\\(.id) \\(.name)"' | while read REPO_ID REPO_NAME; do
  POLICY_COUNT=$(az repos policy list \\
    --repository-id "$REPO_ID" \\
    --branch "$BRANCH" \\
    --org "$ORG" \\
    --project "$PROJECT" \\
    --query "length(@)" \\
    --output tsv 2>/dev/null)

  if [ "$POLICY_COUNT" -gt 0 ] 2>/dev/null; then
    echo "✅$REPO_NAME$POLICY_COUNT policies on$BRANCH"
  else
    echo "❌$REPO_NAME — NO policies on$BRANCH"
  fi
done

Branch Pattern Policies

Instead of protecting individual branches, protect all branches matching a pattern. This is useful for release branches:

# Protect all release/* branches with 2 reviewers + build validation
az repos policy approver-count create \\
  --allow-downvotes false \\
  --blocking true \\
  --branch "release/*" \\
  --creator-vote-counts false \\
  --enabled true \\
  --minimum-approver-count 2 \\
  --repository-id <REPO_ID> \\
  --reset-on-source-push true

Branch patterns use glob matching: release/* matches release/1.0, release/2.0, etc. This means newly created release branches automatically inherit the policy — no manual configuration needed.

Troubleshooting: Common Policy Conflicts and Issues

“All policies pass, but the Complete button is grayed out”

Cause 1: A required reviewer hasn’t voted yet. Even if minimum reviewer count is met (e.g., 2 of 3 required reviewers approved), an auto-included required reviewer who hasn’t voted blocks completion.

Fix: Check the “Reviewers” section on the PR. Look for reviewers marked as “Required” (has a lock icon) who haven’t voted. They must vote “Approve” before the PR can be completed.

Cause 2: Build validation expired. If build expiration is set and the build passed more than N hours ago, it’s considered stale and needs re-running.

Fix: Click “Queue build” to re-trigger the validation pipeline, or ask the PR author to push a new commit (which triggers automatic re-build if configured).

“Build validation keeps re-triggering on every push”

This is expected behavior when “Trigger” is set to “Automatic” and “Queue on source update only” is enabled. Every push to the source branch triggers a new build.

If builds are queueing too frequently: Set “Queue on source update only” to true (ignores target branch updates) and increase the build expiration window. This means the build only re-runs when the PR author pushes new commits, not when someone else merges into main.

“Required reviewer can’t be removed from the PR”

Auto-included reviewers (from “Automatically included reviewers” policy) cannot be removed from the PR manually. They’re added by the policy and will remain for the lifetime of the PR.

Workaround: If the required reviewer is unavailable (on leave, left the company), a Project Administrator can temporarily disable the auto-included reviewer policy, complete the PR, and re-enable it. Alternatively, use groups instead of individuals so that any group member can satisfy the requirement.

“PR shows merge conflicts but I can’t resolve them”

Branch policies block the merge button when there are conflicts, but Azure DevOps doesn’t provide an in-browser conflict resolution tool for all merge types.

Fix: Resolve conflicts locally: pull the target branch into your feature branch (git merge main), resolve conflicts, commit, and push. The PR will update and the conflict status will clear.

“Status check is stuck on ‘Pending’”

An external tool (e.g., AI code reviewer, SAST scanner) hasn’t posted its status yet, or it posted but with a different status key than what the policy expects.

Fix: Check if the tool ran successfully (check the tool’s dashboard or logs). Verify the status key matches exactly — the policy checks for an exact string match on the status name. If the tool uses codeantai/pr-review but the policy expects codeantai/review, it won’t match.

“Policy was configured but it’s not being enforced”

Possible causes:

  1. Policy is on the wrong branch. Policies are per-branch. A policy on main doesn’t apply to PRs targeting develop.

  2. Policy is disabled. Check if the policy is toggled to “Enabled” in the settings.

  3. User has Bypass permission. Users with “Bypass policies when completing pull requests” can merge without satisfying policies. Check the permissions guide for who has this permission.

  4. The policy applies to a branch pattern that doesn’t match. Verify the branch pattern (e.g., release/*) matches the actual branch name.

“Different team members see different merge type options”

This is correct behavior. The merge type dropdown on the Complete dialog only shows strategies allowed by the “Limit merge types” policy. If only squash is allowed, developers only see the squash option.

If a developer sees all merge types, the “Limit merge types” policy may not be enabled on the target branch, or the developer has bypass permissions.

“I want different policies for different file paths, not just different branches”

Azure DevOps branch policies apply per-branch, not per-file-path — with one exception: “Automatically included reviewers” supports path filters. For everything else (build validation, minimum reviewers, merge types), the policy applies to the entire PR regardless of which files changed.

Workaround for build validation: Use path filters in the build validation policy. When you add a build policy, you can set path filters so the build only triggers when specific paths change. This lets you run different pipelines for /src/api/* vs /src/frontend/*.

Add AI Quality Gates with CodeAnt AI

Branch policies enforce process, minimum reviewers, linked work items, passing builds. But they don’t analyze the actual code. A PR can satisfy every policy and still contain security vulnerabilities, logic errors, or performance problems that human reviewers missed.

AI code review fills this gap by adding an intelligent code quality gate that evaluates every line of code, not just whether process was followed.

CodeAnt AI, used by Fortune 500 development teams on Azure DevOps and reviewed on Gartner Peer Insights, integrates as a status check in branch policies. When configured:

  1. A PR is created or updated → Azure DevOps fires a webhook → CodeAnt AI analyzes the full diff

  2. CodeAnt AI posts inline comments for quality and security findings, with one-click fixes developers can apply directly from the PR

  3. CodeAnt AI posts a status check (succeeded or failed) based on the quality gate threshold

  4. The branch policy blocks merge until the status check passes, just like build validation

This means critical security vulnerabilities and code quality issues block the merge, regardless of whether human reviewers caught them. Developers learn from every fix, and leadership dashboards give engineering leaders visibility into code health, review velocity, and security posture across the organization.

To add CodeAnt AI as a required status check:

  1. Install and configure CodeAnt AI (cloud setup guide | self-hosted setup guide)

  2. Create a test PR so CodeAnt AI posts its first status

  3. Go to Project Settings → Repos → Policies → [branch] → Status checks

  4. Add a new status check, select the CodeAnt AI status, and set it to Required

The quality gate now enforces automatically on every PR targeting this branch, no manual intervention needed. If you face any doubt or need help, book your 1:1 with our experts here.

FAQs

What is a branch policy in Azure DevOps?

How do I protect the main branch in Azure DevOps?

Can I have different policies for different branches?

What’s the difference between build validation and status checks?

Can policies be bypassed?

Table of Contents

Start Your 14-Day Free Trial

AI code reviews, security, and quality trusted by modern engineering teams. No credit card required!

Share blog: