Branches, Pull Requests, Merge Requests, and Edition-Aware Analysis: Guided Hands-On Workflow
Create a two-branch Git fixture, run Community Build-compatible baseline and simulation analyses, preserve branch/PR identity evidence, and diagnose shallow history safely.
Learning objectives
- Create a disposable two-branch Git repository with a known main SHA, feature SHA, and merge base.
- Run a real Community Build analysis on main and a clearly labeled feature-revision simulation without pretending it is branch/PR analysis.
- Build the exact Developer+ branch/PR parameter evidence packet without requiring a commercial license.
- Reproduce a shallow-clone defect and repair it by restoring full-enough history.
- Preserve task IDs and separate SonarQube processing evidence from provider-decoration evidence.
- Use a project-analysis token and guarded cleanup.
1. Lab contract and version assumptions
sonar.branch.name or sonar.pullrequest.*.
It models those identities explicitly and optionally executes them
only on an authorized Developer+ test instance/CI workspace.
| State | Lab value |
|---|---|
| Server |
Community Build 26.9.0.129388 at
http://localhost:9000
|
| Scanner | SonarScanner CLI 8.1.0.6389 |
| Main project | sq-ch17-main |
| Feature simulation project |
sq-ch17-feature-sim — deliberately a separate
project, not a branch
|
| Branches | main and feature/demo |
| Simulated PR |
key 17, source feature/demo,
target main
|
2. Build a two-branch repository and local origin
mkdir -p sq-ch17-lab && cd sq-ch17-lab
mkdir author && cd author
git init -b main
git config user.email "learner@example.invalid"
git config user.name "SonarQube Learner"
mkdir -p src
cat > src/app.py <<'PYCODE'
def normalize_name(name: str) -> str:
return name.strip().lower()
PYCODE
cat > sonar-project.properties <<'EOF'
sonar.projectName=SQ Chapter 17 Lab
sonar.sources=src
sonar.sourceEncoding=UTF-8
EOF
cat > .gitignore <<'EOF'
.scannerwork/
evidence/
EOF
git add .
git commit -m "main baseline"
MAIN_SHA="$(git rev-parse HEAD)"
git switch -c feature/demo
cat >> src/app.py <<'PYCODE'
def risky_branch(value: str) -> str:
# Intentionally simple change for branch identity; not an exploit fixture.
return value + "-feature"
PYCODE
git add src/app.py
git commit -m "feature change"
FEATURE_SHA="$(git rev-parse HEAD)"
MERGE_BASE="$(git merge-base main HEAD)"
printf 'main=%s\nfeature=%s\nmerge_base=%s\n' "$MAIN_SHA" "$FEATURE_SHA" "$MERGE_BASE"
git log --oneline --decorate --graph --all
The merge base should equal the baseline main commit because the feature branch has one commit on top of main. That predictable topology is the reference for every later comparison.
3. Create a disposable origin so shallow-clone behavior is real
cd ..
git clone --bare author origin.git
cd author
git remote add origin "../origin.git"
git push -u origin main
git push -u origin feature/demo
mkdir -p evidence
git show-ref | tee evidence/full-show-ref.txt
git rev-parse --is-shallow-repository | tee evidence/full-is-shallow.txt
A local bare origin lets the exercise reproduce CI-like checkout behavior without touching GitHub/GitLab/Bitbucket/Azure or any external repository.
4. Prepare two narrowly scoped Community Build projects
Create two disposable projects in the local SonarQube UI:
sq-ch17-main— the real main-branch baseline.-
sq-ch17-feature-sim— a simulation project that will analyze the feature revision as its own main branch.
Create one project-analysis token for each project. Export them only
in the current shell; do not put them in Git or
sonar-project.properties.
export SONAR_HOST_URL="http://localhost:9000"
read -rsp "Main project token: " SONAR_TOKEN_MAIN; echo
read -rsp "Feature simulation token: " SONAR_TOKEN_FEATURE; echo
export SONAR_TOKEN_MAIN SONAR_TOKEN_FEATURE
curl -fsS "$SONAR_HOST_URL/api/system/status"
sonar-scanner --version
5. Run and preserve the real main-branch analysis
cd ../author
git switch main
mkdir -p evidence/main
git rev-parse HEAD | tee evidence/main/revision.txt
git rev-parse --is-shallow-repository | tee evidence/main/is-shallow.txt
SONAR_TOKEN="$SONAR_TOKEN_MAIN" sonar-scanner -X \
-Dsonar.projectKey=sq-ch17-main \
2>&1 | tee evidence/main/scanner.log
cp .scannerwork/report-task.txt evidence/main/report-task.txt
MAIN_TASK="$(sed -n 's/^ceTaskId=//p' .scannerwork/report-task.txt)"
curl -fsS -H "Authorization: Bearer $SONAR_TOKEN_MAIN" \
"$SONAR_HOST_URL/api/ce/task?id=$MAIN_TASK" \
| tee evidence/main/ce-task.json
Wait for the task to finish before recording Quality Gate and measures. This is a normal Community Build project analysis. It establishes a real SonarQube baseline but does not license multi-branch semantics.
6. Analyze the feature revision without mislabeling it
Community Build cannot retain feature/demo as a branch
of sq-ch17-main. To satisfy the executable learning
goal without overwriting main, analyze the feature revision into the
second disposable project:
git switch feature/demo
mkdir -p evidence/feature-sim
git rev-parse HEAD | tee evidence/feature-sim/revision.txt
git merge-base main HEAD | tee evidence/feature-sim/merge-base.txt
git diff --name-status main...HEAD | tee evidence/feature-sim/diff.txt
SONAR_TOKEN="$SONAR_TOKEN_FEATURE" sonar-scanner -X \
-Dsonar.projectKey=sq-ch17-feature-sim \
2>&1 | tee evidence/feature-sim/scanner.log
cp .scannerwork/report-task.txt evidence/feature-sim/report-task.txt
sq-ch17-feature-sim is an independent project whose
“main” happens to contain the feature revision. Its overall metrics
are not PR New Code metrics and must not be
compared as if SonarQube had analyzed a commercial branch.
7. Build the faithful Developer+ identity manifest
mkdir -p evidence/commercial-simulation
cat > evidence/commercial-simulation/pr-identity.properties <<'EOF'
sonar.projectKey=sq-ch17-main
sonar.pullrequest.key=17
sonar.pullrequest.branch=feature/demo
sonar.pullrequest.base=main
EOF
cat > evidence/commercial-simulation/branch-identity.properties <<'EOF'
sonar.projectKey=sq-ch17-main
sonar.branch.name=feature/demo
EOF
git rev-parse HEAD > evidence/commercial-simulation/feature-sha.txt
git rev-parse main > evidence/commercial-simulation/target-sha.txt
git merge-base main HEAD > evidence/commercial-simulation/merge-base.txt
git diff --name-status main...HEAD > evidence/commercial-simulation/changed-files.txt
Those files are the free simulation of the commercial identity contract. They are useful evidence even on Developer+ because they let you prove what the CI job intended to analyze.
8. Optional Developer+ execution path
If you have an authorized Developer/Enterprise/Data Center test
instance and a CI workspace with the feature branch checked out and
main fetched, you may execute one of these
separate analyses:
# Branch analysis (Developer+), not a PR:
SONAR_TOKEN="$SONAR_TOKEN" sonar-scanner \
-Dsonar.projectKey=sq-ch17-licensed \
-Dsonar.branch.name=feature/demo
# Pull/Merge-request analysis (Developer+) in a CI workspace:
SONAR_TOKEN="$SONAR_TOKEN" sonar-scanner \
-Dsonar.projectKey=sq-ch17-licensed \
-Dsonar.pullrequest.key=17 \
-Dsonar.pullrequest.branch=feature/demo \
-Dsonar.pullrequest.base=main
The target/main branch should already have a successful analysis. On supported CI providers, prefer automatic branch/PR detection when configured correctly; manual PR parameters override that detection.
9. Deliberately break SCM history, then repair it
cd ..
rm -rf shallow
ORIGIN_URL="file://$(pwd)/origin.git"
git clone --depth 1 --branch feature/demo "$ORIGIN_URL" shallow
cd shallow
mkdir -p evidence
# Prediction: true
git rev-parse --is-shallow-repository | tee evidence/is-shallow-before.txt
# main may be absent; preserve the failure instead of hiding it:
git merge-base HEAD origin/main 2>&1 | tee evidence/merge-base-before.txt || true
# Least-destructive repair: fetch full history and the target branch.
git fetch --unshallow origin
git fetch origin main:refs/remotes/origin/main
git rev-parse --is-shallow-repository | tee evidence/is-shallow-after.txt
git merge-base HEAD origin/main | tee evidence/merge-base-after.txt
git diff --name-status origin/main...HEAD | tee evidence/diff-after.txt
Do not delete .git, rewrite commits, or fabricate
target refs. The repair restores the missing evidence layer.
10. Challenge: choose the owning layer
A Developer+ PR analysis has a valid ceTaskId and green
Quality Gate in SonarQube, but Azure DevOps shows no pull-request
status. What should you investigate?
Answer before revealing the next lesson: provider integration/binding, app/PAT permissions, repository identity, and PR metadata—not scanner source indexing or database state first.
Knowledge check
Why use a second Community Build project for the feature simulation?
It prevents the feature checkout from overwriting the real main project while keeping the simulation honest: it is an independent project, not branch analysis.
May you compare the feature-simulation project’s overall issue count to PR New Code issue count?
No. They represent different populations and different analysis modes.
Why create two project-analysis tokens rather than one administrator token?
Each token is narrowly scoped to the disposable project it analyzes, reducing credential blast radius.
What proves the shallow-clone defect was repaired?
--is-shallow-repository becomes false, the target
ref is present, and git merge-base succeeds.
Should branch and pull-request identity parameters be combined in one scan?
No. They describe different analysis modes; choose one identity model for a run.
Official references and version notes
- SonarQube downloads / edition matrix — Community Build 26.9.0.129388; Server 2026 Release 4.1; 2026.1.5 LTA; branch and pull-request analysis plus PR decoration start in Developer Edition.
- Branch analysis introduction — retained branch state, New Code and Quality Gate behavior.
- Setting up branch analysis — branch-name identity, CI integration and branch-level New Code guidance.
- Pull request analysis introduction — changed code relative to the target, New Code-only gate conditions, and provider decoration boundary.
-
Setting up pull request analysis
— CI prerequisite and
sonar.pullrequest.key/branch/baseparameters. -
Checked-out code
— full Git history, target refs, merge-base relevance and
fetch-depth: 0. - Quality standards and New Code — PR New Code is the code changed relative to the target branch.
- GitHub integration — CI auto-detection and PR quality-gate reporting; Chapter 18 expands provider setup.
- SonarScanner CLI 8.1.0.6389 — scanner baseline used by the mandatory lab.
Rechecked 2026-09-08. Mandatory examples target SonarQube
Community Build 26.9.0.129388 and SonarScanner
CLI 8.1.0.6389. Current commercial reference
points are SonarQube Server 2026 Release 4.1 and
2026.1.5 LTA. Current product packaging places
analysis of feature/maintenance branches, pull/merge requests, and
PR quality-gate decoration in
Developer Edition and above. Pull-request
analysis must run in a CI pipeline; the source branch must be
checked out, the target fetched, valid .git metadata
retained, and full-enough history available. SonarSource
recommends full depth; for GitHub Actions the documented pattern
is fetch-depth: 0. Supported CI systems can
auto-detect branch/PR parameters; manually supplied PR properties
override automatic detection. Recheck provider-specific
integration limits and CI auto-detection behavior before
production rollout.
Keep the academy open
Support free, practical DevOps education.
Every lesson is designed to remain readable in a browser, downloadable from GitHub, and usable without a paid learning platform. Contributions help expand and maintain the curriculum.
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0Send only Ethereum/ERC-20 compatible assets to this
address.