Stop Ghosting Your Own Repos: Automate Stale Branch Cleanup with GitHub Actions
You know the feeling. You run git branch -a and a wall of text scrolls past. Most of those branches are "temporary" fixes from 2024. Some are features that were merged months ago but never deleted. A few are experiments that died a quiet death.
Leaving stale branches lying around isn't just "messy." It slows down your team, makes it harder to find what's actually active, and creates a mental tax every time you look at your repository.
In this guide, I'll show you how to automate the audit and cleanup of stale branches using GitHub Actions, so you never have to manually "clean house" again.
The Problem with Manual Cleanup
Most developers treat branch cleanup like doing the dishes: they wait until the pile is so high they can't ignore it anymore. Then someone spends an hour guessing which branches are safe to delete, occasionally deleting something important by mistake, and inevitably missing half the mess.
The issues with manual cleanup are clear:
- It's inconsistent. It only happens when someone gets annoyed enough.
- It's risky. Without a clear record of when a branch was last touched, you're guessing.
-
It's boring. No one wants to spend their Friday afternoon running
git branch -D.
Automating the Audit
The first step in a safe cleanup process isn't deletion—it's visibility. You need to know which branches are stale before they disappear.
We can use a GitHub Action to scan the repository for branches that haven't seen a commit in a specific number of days (e.g., 90 days). Instead of deleting them immediately, the action should create a report.
Here is a basic implementation strategy using a custom GitHub Action I built called stale-branch-cleaner.
Step 1: Create the Cleanup Workflow
Create a file at .github/workflows/stale-branches.yml:
name: Stale Branch Audit
on:
schedule:
- cron: '0 9 * * 1' # Run every Monday at 9:00 AM
workflow_dispatch: # Allow manual triggering
jobs:
audit:
runs-on: ubuntu-latest
permissions:
contents: write
issues: write
steps:
- name: Check for stale branches
uses: ollieb89/stale-branch-cleaner@v1
with:
stale-days: '90'
dry-run: 'true' # Important: report only, don't delete yet
create-issue: 'true' # Create a GitHub Issue with the results
Step 2: Review the Report
When this workflow runs, it won't touch your code. Instead, it will open a GitHub Issue that looks like this:
Title: 🧹 Stale Branch Report (2026-03-21)
Body:
The following branches have had no activity for over 90 days:
| Branch | Last Commit | Author |
|---|---|---|
feature/old-ui-experiment |
2024-11-12 | @dev-alpha |
fix/temp-patch-v1 |
2025-01-05 | @dev-beta |
refactor/removed-module |
2024-09-30 | @dev-alpha |
Total stale branches found: 3.
Moving to Auto-Deletion
Once you've run the audit for a few weeks and you're confident in the results, you can move to a "soft delete" or a full auto-cleanup.
The "Safe" Auto-Delete Pattern
I recommend a 90-day stale window with a "dry run" period of one month. This gives everyone on the team a chance to see the issue and "rescue" any branch they still care about (by simply pushing a dummy commit or re-labeling it).
To enable auto-deletion, update your workflow:
- name: Cleanup stale branches
uses: ollieb89/stale-branch-cleaner@v1
with:
stale-days: '120' # Older branches only
dry-run: 'false' # This will actually delete branches!
create-issue: 'true' # Still create an issue to log what was removed
Protecting Important Branches
Not all "inactive" branches are stale. You might have long-lived release branches, hotfix branches, or documentation branches that shouldn't be touched even if they haven't moved in 6 months.
The stale-branch-cleaner action automatically protects:
mainmasterdevelop- Any branch matching
release/* - Any branch matching
hotfix/*
You can also provide a custom ignore list:
with:
stale-days: '90'
ignore-branches: 'archive/*,legacy-v1,important-refactor'
Why This Matters for DevOps
Clean repositories lead to clean CI/CD.
- Faster clones: Fewer refs to fetch when running shallow clones.
- Clearer visibility: Your branch dropdown only shows work that is actually happening.
- Lower security risk: Old branches often contain outdated dependencies with known vulnerabilities that might accidentally get merged or deployed.
Conclusion
Stop letting "temporary" branches become permanent fixtures of your repository. Automating the cleanup process turns a manual chore into a background process that keeps your development environment sharp and professional.
If you want to try this out, the tool is open source and available on GitHub:
- stale-branch-cleaner — Automates the audit and deletion of stale branches.
Part of the GitHub Actions Toolkit
I'm building a suite of tools to make GitHub Actions more manageable for developers:
- workflow-guardian — Lints your workflows for security and best practices.
- test-results-reporter — Aggregates all your test results into a single PR comment.
- pr-size-labeler — Auto-labels PRs by size to improve review quality.
Give them a star if they help your workflow!
Top comments (0)