Skip to content

Testing: Stale Branch Cleanup

Complete testing guide for stale branch cleanup automation.

Workflow: cleanup-stale-branches.yml
Test Script: test-cleanup-branches.sh

Quick Start

Run Tests (Dry-Run, No Changes)

bash
# Default: shows what would be deleted (14 days old)
./.github/workflows/test-cleanup-branches.sh

# Custom: branches older than 30 days
./.github/workflows/test-cleanup-branches.sh --days 30

# Against different remote
./.github/workflows/test-cleanup-branches.sh --remote upstream

Test Options

bash
./.github/workflows/test-cleanup-branches.sh [OPTIONS]

Options:
  --days N      Number of days; branches older than N are candidates
                Default: 14 days
                Range: 1-365 days
  
  --remote R    Git remote to inspect/delete from
                Default: origin
  
  --apply       DELETE stale branches (use only in sandbox/test repos!)
                Default: dry-run (no changes)
  
  --dry-run     Print actions without deleting (explicit flag)
  
  --help        Show help

What Gets Tested

The test script:

Identifies stale branches

  • Finds branches older than N days
  • Checks last commit date
  • Excludes protected branches (main, dev, etc.)
  • Excludes currently checked-out branch

Validates branch safety

  • Won't delete protected branches
  • Won't delete if local changes exist
  • Shows which branches would be deleted

Provides dry-run output

  • Shows exact branches to be deleted
  • Shows last commit date
  • Shows time since last activity
  • Shows branch creator

Expected Output (Dry-Run)

Analyzing branches older than 14 days...
Remote: origin
Mode: dry-run (no changes)

Would delete these branches:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 Branch Name             Last Commit  Days Old
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 fix/old-bug            2025-12-25    22 days
 feature/deprecated-ui  2025-12-20    27 days
 wip/experiment        2025-12-15    32 days
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

Total branches to delete: 3

To apply changes, run:
  ./.github/workflows/test-cleanup-branches.sh --days 14 --apply

Usage Examples

Example 1: Check Stale Branches (Safe, Read-Only)

bash
# Show branches not touched in 14 days
./.github/workflows/test-cleanup-branches.sh

# Show branches not touched in 30 days
./.github/workflows/test-cleanup-branches.sh --days 30

Example 2: Dry-Run Cleanup

bash
# Preview what WOULD be deleted (14 days, no changes)
./.github/workflows/test-cleanup-branches.sh --dry-run

# Preview with custom threshold (21 days)
./.github/workflows/test-cleanup-branches.sh --days 21 --dry-run

Example 3: Apply Cleanup (Destructive!)

bash
# ⚠️ ACTUALLY DELETE branches 14+ days old
# (only use in test repos!)
./.github/workflows/test-cleanup-branches.sh --apply

# Delete branches 21+ days old
./.github/workflows/test-cleanup-branches.sh --days 21 --apply

Example 4: Check Different Remote

bash
# Analyze upstream instead of origin
./.github/workflows/test-cleanup-branches.sh --remote upstream

# Delete from upstream (destructive!)
./.github/workflows/test-cleanup-branches.sh --remote upstream --apply

Protected Branches

The script never deletes:

  • main
  • dev
  • master
  • production
  • Currently checked-out branch
  • Branches with uncommitted changes

Why? Prevents accidental data loss.

Troubleshooting

"No branches found"

All branches are either:

  • Newer than threshold
  • Protected branches
  • Currently checked out

Try a higher threshold:

bash
./.github/workflows/test-cleanup-branches.sh --days 7

"Permission denied"

The script needs push access to delete branches:

bash
# Check authentication
git remote -v

# Test push access
git fetch origin  # Should work

If you get permission errors:

bash
# Ensure you have push access to remote
git remote set-url origin https://github.com/USERNAME/REPO.git
git push origin --dry-run

"Could not remove branch"

Branch might be:

  • Protected (check GitHub settings)
  • Has uncommitted changes
  • PR still open from that branch
  • Force-pushed or deleted remotely

"Wrong remote"

bash
# List available remotes
git remote -v

# Use correct remote
./.github/workflows/test-cleanup-branches.sh --remote <remote-name>

Safety Checklist

Before running --apply:

  • [ ] Run --dry-run first
  • [ ] Review branches to be deleted
  • [ ] Confirm none are needed
  • [ ] Test on non-critical repo first
  • [ ] Ensure backups exist (GitHub keeps deleted branches briefly)
  • [ ] Have commit history backed up

Workflow (Automated)

The cleanup-stale-branches.yml workflow:

Triggers: Schedule (weekly)

Actions:

  1. Fetches all branches
  2. Identifies branches older than threshold
  3. Posts PR or comment with summary
  4. Can be configured to auto-delete

Configuration:

  • DAYS_THRESHOLD: 14 (customize in workflow)
  • PROTECTED_BRANCHES: main, dev, production, master
  • AUTO_DELETE: false (default is dry-run)

Cost

Free! Uses GitHub's built-in Git operations.

✅ No API charges
✅ No storage impact
✅ Git cleanup is fast

Recovery

If you accidentally delete a branch:

bash
# GitHub keeps deleted branches in reflog for ~3 months
# Contact GitHub Support: https://github.com/contact

# Or check local backup
git reflog  # Shows all branch operations

Advanced: Custom Branch Protection

To protect additional branches from deletion:

Edit: .github/workflows/test-cleanup-branches.sh

Find this line:

bash
PROTECTED_BRANCHES=("main" "dev" "production" "master")

Add your branch:

bash
PROTECTED_BRANCHES=("main" "dev" "production" "master" "staging" "my-branch")

Recommendations

Suggested Settings:

  • Weekly cleanup: Remove branches > 30 days old
  • Monthly cleanup: Remove branches > 60 days old
  • Always dry-run first before applying
  • Review deleted branches in GitHub activity log

Example Workflow Schedule:

bash
# Every Monday at 2 AM UTC
schedule:
  - cron: '0 2 * * 1'

See Also

Built with VitePress