---
title: "Twenty Stale Branches Across 30 Clones, and the Close Step That Left Them Behind"
canonical: https://dxdev.com/blog/2026-09-17_branch-graveyard-automated-cleanup/
datePublished: 2026-09-17
---
The audit of our 30 clones of the same web platform came back with 20 stale branches, and some of them held work that existed nowhere but on one machine.

That last part turned a chore into a problem. A stale branch is clutter. A stale branch holding the only copy of a commit is a loss waiting for a disk failure. So before deleting anything, I backed up every branch whose work had never been pushed, and only then started pruning. The audit session ran from 9:37 that morning to just past midnight.

## The theory I dropped

I went in with a working theory about which branch names were legitimate. I suspected that one hyphenated variant of the hotfix naming was irregular. Then I read the platform's own branching doc, which names that hyphenated form as the canonical hotfix work branch, so the theory was wrong. I dropped it that same day.

The same lesson showed up a second time in the cleanup code. My clone-cleanup step relied on git's own safety check before deleting a branch, and that check is narrower than the proof I already had that a branch had been merged into develop. Git refused to delete branches I could show were done. The cleanup now trusts the merge proof it already runs.

## What was leaving them behind

Closing a ticket in our tracker did nothing to the branches attached to it. The ticket went to done, the fix shipped, and the branch stayed in whatever clone it was created in. Nothing connected "ticket closed" to "branch is now garbage", so any cleanup depended on a person remembering, and 30 clones is too many places to remember.

So the fix went into the close path itself. Closing a ticket now cleans up its sibling and wrapper branches as part of the close, and the clone lock gets released on close too. The end state I wanted is that nobody runs a sweep, because nothing is left over to sweep.

## Three repos, three ideas of a legitimate branch

The second cause showed up once I read how the branches were named. Three repos on the same platform had each drifted toward their own idea of what a legitimate branch looks like. A cleanup rule that is correct for one repo misjudges the other two.

I filed a ticket to give all three repos one shared branch rule, and it is pushed. On the tooling side, our internal repo keeps a copy of the platform's branch rules, and copies drift. I added a check that goes red when our copy stops matching the platform's. If the rule changes upstream and we do not follow, we find out that day.

## Start from the event that made it stale

The event that made these branches stale was a ticket closing, and it had been available the whole time. We had been treating the mess as a housekeeping habit when it was a missing step in a workflow we run every day.

If you have a pile of anything that gets created on an event, find the opposite event and wire the cleanup there. Then add a check where a copied rule can drift, so the next audit has nothing to find.
