Branching Health Report
Analyse the repository's branching strategy, merge patterns, and branch hygiene, then produce a structured report with actionable recommendations.
When to Activate
Activate this skill when:
- User says "branching health report", "branch analysis", or "branching report"
- A periodic review of git branch hygiene is requested
- User wants to understand merge patterns, stale branches, or history quality
Output Location
reports/branching-health/{YYYY-MM-DD}_branching_health_report.md
Follows the reports/{topic}/{YYYY-MM-DD}_{snake_case_name}.md convention (see /docs-please RULE 4).
Process
Step 1: Locate Previous and Oldest Reports
Check for existing reports:
reports/branching-health/
Sort all reports by date. Identify:
- Previous report: The most recent report before this one
- Oldest report: The earliest report in the directory
If a previous report exists, read it to:
- Capture prior metric values (branch counts, merge patterns, stale branch counts)
- Track action plan progress
- Use as baseline for the Delta Analysis section
If an oldest report exists (and is different from the previous report), read it to:
- Capture the original baseline metrics
- Use for the Baseline Comparison columns in Delta Analysis
If no previous report exists, skip delta analysis and note this is the initial baseline. If only one prior report exists, it serves as both previous and oldest (no separate baseline column needed).
Step 2: Verify Codebase Currency
Before gathering data, confirm the local repo is up-to-date:
git fetch origin develop
LOCAL=$(git rev-parse origin/develop)
REMOTE=$(git ls-remote origin refs/heads/develop | cut -f1)
if [ "$LOCAL" != "$REMOTE" ]; then
echo "WARNING: Local develop is behind remote. Run 'git fetch origin' first."
fi
If develop is stale, warn the user and ask whether to proceed or fetch first. Branch inventory and merge pattern analysis will be inaccurate against an outdated set of remote refs.
Scheduling note: This is a snapshot report โ it analyses the live branch state as-is. There is no backfill capability. The report date is always the current date. Ideally run on Saturday to capture a full work week.
Step 3: Gather Branch Data
Run git commands to collect raw data. All commands should be run via Bash tool.
A. Branch Inventory
# Total remote branches
git branch -r | wc -l
# Branches merged to master
git branch -r --merged origin/master | grep -v 'master\|develop\|STABLE\|HEAD' | wc -l
# Branches not merged to master
git branch -r --no-merged origin/master | wc -l
# Branch age distribution
git for-each-ref --sort=committerdate --format='%(committerdate:short)' refs/remotes/origin | awk -v cutoff6m="$(date -v-6m +%Y-%m-%d)" -v cutoff1y="$(date -v-1y +%Y-%m-%d)" -v cutoff2y="$(date -v-2y +%Y-%m-%d)" '
BEGIN { lt6m=0; lt1y=0; lt2y=0; gt2y=0 }
$1 >= cutoff6m { lt6m++ }
$1 < cutoff6m && $1 >= cutoff1y { lt1y++ }
$1 < cutoff1y && $1 >= cutoff2y { lt2y++ }
$1 < cutoff2y { gt2y++ }
END { print "< 6 months:", lt6m; print "6-12 months:", lt1y; print "1-2 years:", lt2y; print "> 2 years:", gt2y }
'
B. Branch Naming Analysis
# Naming convention breakdown
git branch -r | sed 's|origin/||' | grep -v "HEAD" | \
awk '{
if (/^CFCON-/) print "CFCON-XXXXX"
else if (/^bugfix\//) print "bugfix/"
else if (/^feature\//) print "feature/"
else if (/^hotfix\//) print "hotfix/"
else if (/^STABLE\//) print "STABLE/"
else if (/^TESTING\//) print "TESTING/"
else if (/^release\//) print "release/"
else print "other"
}' | sort | uniq -c | sort -rn
C. Merge Pattern Analysis
# master history - first parent (last 50)
git log --oneline --first-parent origin/master -50
# develop history - first parent (last 50)
git log --oneline --first-parent origin/develop -50
# STABLE branch history (find latest STABLE branch)
git branch -r | grep "STABLE" | sort -t/ -k3 -r | head -1
# Merge-from-develop frequency (feature branches pulling develop in)
git log --oneline --all --grep="Merged develop into" | wc -l
# Merge-from-master frequency
git log --oneline --all --grep="Merged master into" | wc -l
# Direct commits on master (non-merge, first-parent, last 50)
git log --oneline --first-parent --no-merges origin/master -50
# master/develop divergence
git log --oneline origin/master..origin/develop --no-merges | wc -l
git log --oneline origin/develop..origin/master --no-merges | wc -l
D. Long-Lived Feature Branches Find branches with high merge-from-develop counts (signals a branch has lived too long):
# Top branches by merge-from-develop count
git log --oneline --all --grep="Merged develop into" | \
sed 's/.*Merged develop into //' | sort | uniq -c | sort -rn | head -10
E. Duplicate Merge Detection Check for tickets merged via multiple PRs to different targets:
# Find tickets appearing in both develop and STABLE merge history
git log --oneline --first-parent origin/develop --grep="pull request" -50 | \
grep -oP 'CFCON-\d+' | sort -u > /tmp/develop_tickets.txt
# Compare against STABLE
Step 4: Compute Key Metrics
Calculate these metrics from the gathered data:
| Metric | How to Calculate |
|---|---|
| Total Remote Branches | git branch -r | wc -l |
| Merged (Deletable) Branches | git branch -r --merged origin/master | wc -l minus protected branches |
| Stale Branches (>6 months) | Count branches with last commit older than 6 months |
| Branch Cleanup Ratio | Merged / Total (higher = better cleanup) |
| Merge-from-Develop Count | Total "Merged develop into" commits (lower = better; signals shorter-lived branches) |
| Direct Commits on Master | Non-merge first-parent commits on master (should be zero) |
| Master-Develop Divergence | Non-merge commits between the two (should be zero) |
| Avg Merges-from-Develop per Feature | Total merge-from-develop commits / number of distinct feature branches that have them |
| STABLE Divergence | Commits on STABLE not in master |
| Dual-Target Merges | Tickets merged to both develop and STABLE independently |
| History Readability | Subjective 1-5 score based on git log --graph complexity |
Step 5: Score Branching Health
Score each dimension on a 1-5 scale:
| Score | Level | Description |
|---|---|---|
| 1 | Critical | Major issues causing daily friction |
| 2 | Poor | Significant problems, workarounds needed |
| 3 | Functional | Works but has notable gaps |
| 4 | Good | Minor issues only |
| 5 | Excellent | Industry best practice |
Dimensions to score:
| # | Dimension | What to Assess |
|---|---|---|
| 1 | Branch Naming | Consistency of naming conventions |
| 2 | Branch Cleanup | Ratio of stale/merged-but-not-deleted branches |
| 3 | Merge Flow | Single clear promotion path (feature โ develop โ STABLE โ master) |
| 4 | Feature Branch Lifespan | How long branches live, merge-from-develop frequency |
| 5 | History Readability | Can you understand the git graph? |
| 6 | Direct Commits | Are master/develop protected from direct pushes? |
| 7 | Dual-Target Merges | Are features going to one integration branch or multiple? |
| 8 | Release Process | Is STABLE managed properly as a release candidate? |
Overall score = average of all dimensions.
Step 6: Identify Top Issues
Rank the top 5 issues by severity and impact:
For each issue:
- Impact: How it affects the team day-to-day
- Root Cause: Why this pattern exists
- Risk: What could go wrong if not addressed
- Effort to Fix: Low / Medium / High
Step 7: Delta Analysis (if previous report exists)
Compare with the previous report. If an oldest report exists (different from the previous report), include baseline columns.
## Delta Analysis
**Previous report:** {previous_report_path}
**Oldest report:** {oldest_report_path_or_"Same as previous"}
### Key Metrics Comparison
If oldest report is different from previous report:
| Metric | Oldest (Baseline) | Previous | Current | vs Previous | vs Baseline |
|--------|--------------------|----------|---------|-------------|-------------|
| Total Remote Branches | A | X | Y | +/-Z | +/-Z |
| Merged (Deletable) | A | X | Y | +/-Z | +/-Z |
| Stale (>6 months) | A | X | Y | +/-Z | +/-Z |
| Direct Commits on Master | A | X | Y | +/-Z | +/-Z |
| Master-Develop Divergence | A | X | Y | +/-Z | +/-Z |
| STABLE Divergence | A | X | Y | +/-Z | +/-Z |
| Merge-from-Develop Count | A | X | Y | +/-Z | +/-Z |
| Dual-Target Merges | A | X | Y | +/-Z | +/-Z |
If oldest report is the same as previous report (only two reports exist), omit the Oldest and vs Baseline columns:
| Metric | Previous | Current | Change |
|--------|----------|---------|--------|
| Total Remote Branches | X | Y | +/-Z |
| ... | | | |
### Scorecard Comparison
If oldest report is different from previous report:
| # | Dimension | Oldest (Baseline) | Previous | Current | vs Previous | vs Baseline |
|---|-----------|--------------------|---------|---------|----|-----|
| 1 | Branch Naming | A | X | Y | direction | direction |
| ... | | | | | | |
| | **Overall** | **A** | **X** | **Y** | **+/-Z** | **+/-Z** |
If oldest report is the same as previous report, omit the Oldest and vs Baseline columns.
### Action Plan Progress (from previous report)
| Previous Action | Status | Evidence |
|----------------|--------|----------|
| Delete stale branches | Done / Partial / Not started | Count reduced from X to Y |
| ... | | |
### Baseline Action Plan Progress (if oldest report is different from previous)
| Baseline Action (from oldest report) | Status | First Proposed | Evidence |
|--------------------------------------|--------|----------------|----------|
| {action from oldest report} | Done / Partial / Not started | {date} | |
| ... | | | |
### Long-Standing Issues (if oldest report is different from previous)
Issues that have persisted across all reports since the oldest baseline.
Step 8: 30-Day Action Plan
Produce an action plan ordered by ROI:
- Week 1: Quick Wins (< 1 day each, high impact)
- Branch cleanup scripts, protection rules
- Week 2: Process (enforce branching discipline)
- Single promotion path, naming conventions
- Week 3: Tooling (automation to prevent regression)
- Auto-delete on merge, stale branch alerts
- Week 4: Optimization (improve developer experience)
- Rebase workflow, history cleanup, documentation
Each action includes: effort estimate, expected metric improvement, owner suggestion.
End with an Expected Impact table projecting improvements.
Step 9: Write Report
Write the report to:
reports/branching-health/{YYYY-MM-DD}_branching_health_report.md
Use this header:
# ComplyFlow Branching Health Report
**Repository:** ComplyFlow Web App (`comply-flow/complyflow`)
**Date:** {today}
**Previous report:** {previous_report_filename_or_"None (initial baseline)"}
**Oldest report:** {oldest_report_filename_or_"Same as previous"_or_"None"}
**Overall Score:** **{score} / 5.0**
---
Step 10: Confirm
After generating the report:
- Show the user the file path
- Summarise: overall score, total branches, top 3 issues, top 3 quick wins
- Highlight delta trends (if previous report exists)
- Highlight baseline trends (if oldest report exists and differs from previous)
- Ask: "Review the full report, or proceed to create Jira issues for the action plan?"
Report Template (Table of Contents)
# ComplyFlow Branching Health Report
## Table of Contents
1. Executive Summary
2. Key Metrics
3. Scorecard (8 dimensions)
4. Branch Inventory
4A. Age Distribution
4B. Naming Convention Breakdown
4C. Cleanup State
5. Merge Pattern Analysis
5A. Promotion Flow (feature โ develop โ STABLE โ master)
5B. Merge-from-Develop Frequency (long-lived branch indicator)
5C. Dual-Target Merges
5D. Direct Commits on Protected Branches
6. Long-Lived Feature Branches
7. STABLE Branch Analysis
8. Top 5 Issues (ranked by severity)
9. Delta Analysis (vs Previous Report & Oldest Baseline)
10. 30-Day Action Plan
11. Data Limitations
Bitbucket Plan Constraints
ComplyFlow uses Bitbucket Standard ($3/user/month). Do NOT recommend features that require Bitbucket Premium ($6/user/month).
| Feature | Available on Standard? | Notes |
|---|---|---|
| Branch permissions (require PR, min reviewers) | Yes | Recommend freely |
| Auto-delete branch on merge | Yes | Recommend freely |
| Merge checks (require passing builds) | Yes | Recommend freely |
| Revoke approvals on source branch change | No โ Premium only | Do NOT recommend (see CFCON-20017) |
| Deployment permissions | No โ Premium only | Do NOT recommend |
| IP allowlisting | No โ Premium only | Do NOT recommend |
When writing recommendations, only suggest Bitbucket settings available on the Standard plan unless explicitly asked about a plan upgrade.
Tips
- Run all git commands via Bash tool โ do not use Grep/Glob for git operations
- Branch counts change frequently โ always gather fresh data, don't reuse stale numbers
- The merge-from-develop count is the best proxy for "feature branches live too long"
- A high dual-target merge count indicates the promotion path is unclear
- When delta shows branch counts dropping, celebrate it โ it validates cleanup work
- Score the history readability by running
git log --oneline --graph --all -50and assessing visual complexity - Note any limitations (e.g.,
git branch -r --mergedmay include false positives for squash-merged branches) - For large repos,
git for-each-refis faster thangit branchfor age analysis