SonarQube Branch Analysis: Track Code Quality Across Feature Branches

SonarQube Branch Analysis: Track Code Quality Across Feature Branches

SonarQube branch analysis creates a separate quality view for each branch. You can see the quality gate status of feature branches independently from main, compare coverage and issues per branch, and set branch-specific quality gates.

Key Takeaways

Branch analysis requires Developer Edition or higher. Community Edition only supports the main branch. SonarCloud includes branch analysis at all tiers.

Pass sonar.branch.name to identify the branch. Most CI plugins detect this automatically from environment variables.

Short-lived vs long-lived branches behave differently. Feature branches are short-lived and compared against the base branch. Release/maintenance branches are long-lived and get full independent analysis.

Branch analysis doesn't create new projects. All branches of a project live under the same project key in SonarQube.

New Code Period is per-branch. Each branch tracks its own "new code" window for coverage and issue counting.

Branch Analysis Concepts

Short-lived vs Long-lived Branches

Short-lived branches (feature branches, PR branches):

  • Compared against the parent branch
  • "New code" = code introduced since branching from parent
  • Intended to be merged and then deleted
  • Lifecycle: appears when analyzed, cleaned up after inactivity

Long-lived branches (main, develop, release/, hotfix/):

  • Analyzed independently with their own full history
  • "New code" period set per-branch (date, version, or previous analysis)
  • Shown permanently in the project UI

Configuring Branch Types

By default, SonarQube auto-classifies based on branch name patterns. Customize in Administration → Configuration → Analysis Scope → Branch Types:

Long-lived branch patterns:
- main
- master  
- develop
- release/*
- hotfix/*

Everything else is treated as short-lived.

CI Configuration

Passing Branch Name

# Maven
mvn sonar:sonar \
  -Dsonar.branch.name=feature/my-feature \
  -Dsonar.branch.target=main  # optional: what to compare against

# Gradle
./gradlew sonarqube \
  -Dsonar.branch.name=$(git branch --show-current)

# sonar-scanner
sonar-scanner \
  -Dsonar.branch.name=$CI_COMMIT_BRANCH

GitHub Actions (Auto-Detection)

- name: SonarQube Analysis
  uses: SonarSource/sonarqube-scan-action@master
  env:
    SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
    SONAR_HOST_URL: ${{ secrets.SONAR_HOST_URL }}
  # sonar.branch.name is auto-detected from GITHUB_REF

The official SonarQube GitHub Action auto-detects the branch from GITHUB_REF. Manual override:

with:
  args: -Dsonar.branch.name=${{ github.ref_name }}

GitLab CI

sonarqube:
  script:
    - sonar-scanner
      -Dsonar.branch.name=$CI_COMMIT_BRANCH

GitLab CI exposes $CI_COMMIT_BRANCH automatically.

Viewing Branch Results

In the SonarQube project UI:

  1. The branch selector (top-left of the project) shows all analyzed branches
  2. Select any branch to see its quality gate, issues, coverage, and duplications
  3. The "New Code" tab shows issues introduced on this branch vs the baseline
  4. Quality gate status is per-branch

Branch badges in README:

[![Quality Gate](https://sonarqube.example.com/api/project_badges/measure?project=myproject&metric=alert_status&branch=main)](https://sonarqube.example.com/dashboard?id=myproject&branch=main)

Branch-Specific Quality Gates

Different quality gates for different branches:

# Assign a stricter quality gate to main
curl -X POST "http://sonarqube/api/qualityprofiles/add_project" \
  -u admin:admin \
  -d "language=java&qualityProfile=Strict-Production-Gate&project=myproject"

Note: Quality gates apply to the project, not per-branch, in current SonarQube versions. Use different projects for fundamentally different branch policies.

Managing Branch Cleanup

Old branches accumulate. Configure automatic cleanup:

Administration → Configuration → Analysis Scope → Branches and Pull Requests:

Short-lived branches TTL: 30 days (inactive branches deleted after 30 days)
Long-lived branches TTL: 0 days (never auto-deleted)

Or delete branches via API:

curl -X DELETE "http://sonarqube/api/project_branches/delete" \
  -u admin:admin \
  -d "project=myproject&branch=feature%2Fold-feature"

Comparing Branch Coverage

SonarQube doesn't have a built-in branch comparison UI, but you can use the API:

# Coverage on main
curl "http://sonarqube/api/measures/component?component=myproject&branch=main&metricKeys=coverage"

# Coverage on feature branch
curl "http://sonarqube/api/measures/component?component=myproject&branch=feature%2Fmy-feature&metricKeys=coverage"

Response:

{
  "component": {
    "measures": [
      {"metric": "coverage", "value": "78.5"}
    ]
  }
}

Script to fail CI if branch coverage drops more than 5% below main:

MAIN_COVERAGE=$(curl -s "http://sonarqube/api/measures/component?component=myproject&branch=main&metricKeys=coverage" \
  | jq -r '.component.measures[0].value')
BRANCH_COVERAGE=$(curl -s "http://sonarqube/api/measures/component?component=myproject&branch=feature/my-feature&metricKeys=coverage" \
  | jq -r '.component.measures[0].value')

echo "Main: $MAIN_COVERAGE%, Branch: $BRANCH_COVERAGE%"

if (( $(echo "$BRANCH_COVERAGE < $MAIN_COVERAGE - 5" | bc -l) )); then
  echo "ERROR: Coverage dropped more than 5% compared to main"
  exit 1
fi

New Code Period Per Branch

Each branch can have its own new code period. Useful for release branches that need a different baseline:

Project Settings → New Code → Per branch settings

main: Previous version (last SonarQube analysis)
release/1.x: Specific date (start of the release branch)
feature/*: (auto) compared to parent branch

Branch analysis gives each team member visibility into their branch's quality without polluting the main branch dashboard.

Read more

Start now free