← 返回
未分类 中文

Phy Git Branch Janitor

Git branch cleanup assistant. Audits all local and remote branches, categorizes them as safe-to-delete (merged), stale-unmerged (old + no open PR), or active...
Git 分支清理助手,审计本地和远程分支,将其分为可安全删除(已合并)、陈旧未合并(老旧无开放PR)或活跃分支。
phy041 phy041 来源
未分类 clawhub v1.0.3 1 版本 100000 Key: 无需
★ 0
Stars
📥 237
下载
💾 0
安装
1
版本
#latest

概述

Git Branch Janitor

Audit every branch in your repo — local and remote — and produce a prioritized cleanup plan. Find branches that are already merged, branches that have gone stale with no activity, and branches that never made it to the remote. Get one copy-paste command to clean them all up safely.

Works on any Git repo. Optional GitHub CLI for PR cross-reference. Zero config.


Trigger Phrases

  • "clean up branches", "branch cleanup", "delete old branches"
  • "stale branches", "orphaned branches", "branch audit"
  • "git housekeeping", "which branches can I delete"
  • "/git-branch-janitor"

Step 1: Fetch Latest State

# Sync remote branch state (prune deleted remote branches from local tracking)
git fetch --all --prune

# Show current branch (to avoid deleting it)
git branch --show-current

> Important: Never delete the current branch, main, master, develop, or release/* — these are protected.


Step 2: Inventory All Branches

Run all three simultaneously to build a complete picture:

# Local branches
git branch --format='%(refname:short)' | sort

# Remote branches
git branch -r --format='%(refname:short)' | sed 's/origin\///' | sort

# All branches with last commit metadata
git for-each-ref --sort=committerdate \
  --format='%(refname:short)|%(committerdate:relative)|%(committerdate:iso)|%(authorname)|%(subject)' \
  refs/heads refs/remotes/origin \
  | grep -v "HEAD$" \
  | sort -t'|' -k3

Parse each branch's:

  • Last commit date → age bucket (< 7 days, 7-30 days, 30-90 days, > 90 days)
  • Author → who owns this branch
  • Subject → last commit message (hint about what the branch was for)

Step 3: Classify Each Branch

Class 1: SAFE-TO-DELETE (Merged)

Branches that are fully merged into the default branch:

# Branches merged into main (replace 'main' with your default branch)
DEFAULT=$(git symbolic-ref refs/remotes/origin/HEAD 2>/dev/null | sed 's/refs\/remotes\/origin\///' || echo "main")

# Local merged branches
git branch --merged "$DEFAULT" | grep -v "^\*" | grep -vE "^\s*(main|master|develop|release/)" | sed 's/^  //'

# Remote merged branches
git branch -r --merged "origin/$DEFAULT" | grep -v "HEAD" | grep -vE "(main|master|develop|release/)" | sed 's/origin\///' | sed 's/^  //'

Rule: If a branch has been fully merged into the default branch, it's safe to delete.

Class 2: STALE-UNMERGED (Review Required)

Branches NOT merged but with no recent activity:

# Branches NOT merged into main, older than 30 days
git for-each-ref \
  --format='%(refname:short)|%(committerdate:iso)|%(committerdate:relative)' \
  refs/heads \
  | while IFS='|' read -r branch date reldate; do
      # Skip protected branches
      echo "$branch" | grep -qE "^(main|master|develop|release/)" && continue
      # Check if merged
      git merge-base --is-ancestor "$branch" "$DEFAULT" 2>/dev/null && continue
      # Check age > 30 days
      DAYS=$(( ($(date +%s) - $(date -d "$date" +%s 2>/dev/null || date -j -f "%Y-%m-%d %H:%M:%S %z" "$date" "+%s" 2>/dev/null)) / 86400 ))
      [ "$DAYS" -gt 30 ] && echo "$branch|${DAYS}d old|$reldate"
  done

Rule: These need human review — was this branch abandoned? Did it become a draft PR?

Class 3: ORPHANED (Local only, never pushed)

Branches that exist locally but have no remote tracking branch:

git branch -vv | grep ": gone]" | awk '{print $1}'
# These had a remote, but remote was deleted (PR merged via GitHub UI)

git branch -vv | grep -v "\[origin" | grep -v "^\*" | awk '{print $1}'
# These were never pushed at all

Class 4: AHEAD-ONLY (Unpushed work)

Branches that have commits not on remote — don't delete these:

# Check which branches have commits ahead of remote
git branch -vv | grep "ahead"

Step 4: Cross-Reference PRs (Optional — requires gh CLI)

If gh is available, enhance stale-unmerged branches with PR status:

# Check if a branch has an open or merged PR
for branch in $STALE_BRANCHES; do
  PR=$(gh pr list --head "$branch" --state all --json number,state,title --jq '.[0]' 2>/dev/null)
  if [ -n "$PR" ]; then
    STATE=$(echo "$PR" | python3 -c "import sys,json; d=json.load(sys.stdin); print(d['state'])")
    TITLE=$(echo "$PR" | python3 -c "import sys,json; d=json.load(sys.stdin); print(d['title'][:50])")
    NUMBER=$(echo "$PR" | python3 -c "import sys,json; d=json.load(sys.stdin); print(d['number'])")
    echo "$branch → PR #$NUMBER ($STATE): $TITLE"
  else
    echo "$branch → No PR found"
  fi
done

With PR context:

  • MERGED PR → definitely safe to delete
  • CLOSED PR → was abandoned, confirm with user before deleting
  • OPEN PR → active work in progress — never delete
  • No PR → was this work captured elsewhere? Ask user.

Step 5: Generate Cleanup Commands

Produce three batches of commands:

Batch 1: Auto-Safe Deletes

# Delete merged local branches
git branch -d feat/add-login feat/fix-typo chore/update-deps

# Delete merged remote branches
git push origin --delete feat/add-login feat/fix-typo chore/update-deps

Batch 2: Gone-Remote Cleanup (Orphaned)

# These had remotes that were already deleted (usually by GitHub after PR merge)
git branch -d fix/header-bug refactor/auth-service

Batch 3: Stale-Unmerged (Review First)

# ⚠️ Review these before running — they were never merged
# Branch: wip/new-feature (last commit: 47 days ago, no PR found)
# git branch -D wip/new-feature  # -D forces delete of unmerged branch
# git push origin --delete wip/new-feature

Output Report

Always produce this report structure:

## Git Branch Janitor Report
Repo: [repo name] | Default branch: main | $(date)

### Summary
| Category | Local | Remote |
|----------|-------|--------|
| 🟢 Safe-to-delete (merged) | 8 | 6 |
| 🟠 Stale unmerged (>30 days, no open PR) | 3 | 2 |
| 🔵 Orphaned (remote gone) | 4 | — |
| ⚠️ Ahead-only (unpushed work) | 2 | — |
| ✅ Active (recent commits) | 5 | 7 |

---

### 🟢 Safe to Delete — Already Merged

| Branch | Last Commit | Author | Merged Via |
|--------|-------------|--------|-----------|
| feat/add-login | 12 days ago | alice | PR #142 (merged) |
| fix/header-bug | 23 days ago | bob | PR #138 (merged) |
| chore/bump-deps | 31 days ago | alice | Direct merge |

**One command to clean all:**

Local

git branch -d feat/add-login fix/header-bug chore/bump-deps

Remote

git push origin --delete feat/add-login fix/header-bug chore/bump-deps


---

### 🔵 Orphaned — Remote Already Deleted

These branches exist locally but their remote was deleted (e.g., GitHub merged the PR):

| Branch | Last Commit | Author |
|--------|-------------|--------|
| feat/dark-mode | 8 days ago | carol |
| fix/mobile-nav | 15 days ago | alice |

git branch -d feat/dark-mode fix/mobile-nav


---

### 🟠 Stale Unmerged — Review Before Deleting

| Branch | Age | Author | PR Status |
|--------|-----|--------|----------|
| wip/new-dashboard | 47 days | bob | No PR found |
| experiment/redis-cache | 62 days | carol | PR #120 (closed, abandoned) |

**⚠️ These were never merged. Confirm with owner before deleting:**

Only run after confirming work is captured or abandoned:

git branch -D wip/new-dashboard

git push origin --delete wip/new-dashboard


---

### ⚠️ Skipped — Has Unpushed Work

| Branch | Commits Ahead | Last Commit |
|--------|--------------|-------------|
| feat/user-settings | 7 commits | 2 days ago |
| fix/payment-flow | 2 commits | yesterday |

**Not deleted — these have unpushed commits. Push or open a PR first.**

---

### Cleanup Summary

After running the safe commands above, you'll free:
- **15 local branches** removed
- **8 remote branches** removed
- Estimated `git fetch` speed improvement: ~30% (fewer refs to sync)

Age Thresholds (Configurable)

By default, branches are flagged as "stale" after:

CategoryDefault Threshold
----------------------------
Stale (review recommended)> 30 days since last commit
Very stale (safe to flag)> 90 days since last commit
Ancient (definitely dead)> 6 months

User can override: "show branches older than 2 weeks" or "flag anything over 60 days."


Protected Branches (Never Delete)

The following patterns are always excluded from cleanup suggestions:

main, master, develop, staging, production
release/*, hotfix/*, v*.*.*
HEAD

Quick Mode

When user just wants a fast count:

Quick Branch Audit:
🟢 12 merged (safe to delete)
🔵 5 orphaned (remote gone)
🟠 3 stale unmerged (>30d, no open PR)
⚠️ 2 with unpushed commits (skip)

Safe to clean: 17 branches
Run /git-branch-janitor --full for delete commands

Why Not Just git branch -d?

git branch -d only deletes branches merged into the current HEAD — it misses:

  • Branches merged on GitHub/GitLab via squash or rebase (not a standard merge commit)
  • Remote tracking refs left behind after the remote branch was deleted
  • Branches with PRs that were closed without merging
  • Branches that diverged from main and were superseded by a re-implementation

This skill handles all four cases.


Author

Canlah AI — Run performance marketing without breaking your brand.

版本历史

共 1 个版本

  • v1.0.3 当前
    2026-05-21 15:24 安全 安全

安全检测

腾讯云安全 (Keen)

安全,无风险
查看报告

腾讯云安全 (Sanbu)

安全,无风险
查看报告

🔗 相关推荐

dev-programming

Github

steipete
使用 `gh` CLI 与 GitHub 交互,通过 `gh issue`、`gh pr`、`gh run` 和 `gh api` 管理议题、PR、CI 运行及高级查询。
★ 681 📥 329,464
office-efficiency

Phy Prd Writer

phy041
多轮PRD(产品需求文档)创建助手,逐步提出澄清问题以收集需求,随后生成完整、结构化的PRD。
★ 2 📥 621
dev-programming

CodeConductor.ai

larsonreever
AI驱动平台,提供快速全栈开发、智能体、工作流自动化及低代码AI集成的可扩展产品创建。
★ 76 📥 182,455