mcpField
G
git-branch-cleanup

git-branch-cleanup

github.com/gotalab开发41835 次安装3 天前更新
代码仓库

关于 git-branch-cleanup

用于安全整理和清理本地 Git 分支的 Agent Skill,适合维护本地分支较多的开发者。它按合并状态、远程跟踪和陈旧程度分类,并在删除前进行安全检查与确认。

主要功能

  1. 01按安全状态分类分支
  2. 02识别合并、陈旧及远程已删除分支
  3. 03保护当前分支和受保护分支
  4. 04检查未推送提交与 worktree
  5. 05支持预览并要求删除确认

适用场景

  1. 01清理已合并的本地分支
  2. 02审查远程已删除或长期未更新的分支
  3. 03删除分支前检查未推送提交和 worktree
  4. 04预览可能删除的分支

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/gotalab/skillport --skill git-branch-cleanup

安装后在 Claude Code 中输入/git-branch-cleanup确认已加载。

详细介绍

Git 分支清理

安全地整理并清理本地 Git 分支。根据分支的合并状态、陈旧程度和远程跟踪情况进行分类,然后指导用户安全地删除分支。

目录

  • 快速开始
  • 工作流(步骤 1-5)
  • 命令参考
  • 演练模式
  • 安全检查清单

快速开始

  1. 分析分支(步骤 1)
  2. 按安全级别分类(步骤 2)
  3. 显示结果并询问用户要删除哪些分支(步骤 3)
  4. 根据安全防护规则进行检查(步骤 4)
  5. 确认后执行删除(步骤 5)

工作流

步骤 1:分支分析

使用以下命令收集信息:

# Decide base branch (prefer auto-detect; fallback to main)
BASE_BRANCH="$(
  git symbolic-ref --quiet --short refs/remotes/origin/HEAD 2>/dev/null | sed 's@^origin/@@'
)"
[ -n "$BASE_BRANCH" ] || BASE_BRANCH=main

# List all branches with last commit date
git for-each-ref --sort=-committerdate refs/heads/ \
  --format='%(refname:short)|%(committerdate:relative)|%(upstream:trackshort)|%(contents:subject)'

# Merged branches (against base)
git branch --merged "$BASE_BRANCH"

# Unmerged branches
git branch --no-merged "$BASE_BRANCH"

# Branches whose upstream is gone (remote deleted)
git branch -vv | grep -F ': gone]' || true

# List worktrees (branches with '+' prefix in git branch -v have worktrees)
git worktree list

# Branches with worktrees ('+' prefix indicates worktree association)
git branch -v | grep '^+' || true

# Branches ahead of upstream (have unpushed commits)
git for-each-ref refs/heads \
  --format='%(refname:short) %(upstream:trackshort)' \
  | grep '>' || true
步骤 2:分类

按安全级别对分支进行分类:

类别描述安全性
已合并(安全)已合并到基础分支可安全删除
远程分支已删除远程分支已删除建议检查
陈旧30 天以上没有提交需要检查
有工作树分支已在工作树中检出(git branch -v 中以 + 为前缀)请先移除工作树
领先于上游有尚未推送的提交⚠️ 请勿删除
未合并正在进行中的工作谨慎处理

注意:30 天是检测陈旧分支的合理默认值。如有需要,可根据团队的迭代周期进行调整(例如,采用 2 周迭代的团队可设为 14 天)。

步骤 3:显示格式
## Branch Analysis Results

### Safe to Delete (Merged)
  - feature/login (3 weeks ago) - Add login feature
  - fix/typo (2 months ago) - Fix typo in readme

### Remote Deleted
  - feature/old-api (1 month ago) - Remote branch no longer exists

### ⚠️ Ahead of Upstream (DO NOT DELETE)
  - feature/wip (1 day ago) - Has 3 unpushed commits

### Stale Branches (30+ days)
  - experiment/cache (2 months ago) - Unmerged

### Active (Unmerged)
  - feature/new-dashboard (2 days ago) - Work in progress

---
Which categories would you like to delete?
1. Merged only (safest)
2. Merged + remote deleted
3. Select individually
步骤 4:安全防护规则

绝不删除以下分支:

  • main
  • master
  • trunk
  • develop
  • development
  • 当前检出的分支

删除前务必确认:

The following branches will be deleted:
  - feature/login
  - fix/typo

Continue? (y/N)
步骤 5:执行删除
# After confirmation
git branch -d <branch-name>  # For merged branches
git branch -D <branch-name>  # Force delete (unmerged)

对于有工作树的分支,请先移除工作树:

# Check if branch has a worktree
git worktree list | grep "\\[$branch\\]"

# Remove worktree before deleting branch
git worktree remove --force /path/to/worktree
git branch -D <branch-name>

批量删除 [gone] 分支并处理工作树:

# Process all [gone] branches, handling worktrees automatically
git branch -v | grep '\[gone\]' | sed 's/^[+* ]//' | awk '{print $1}' | while read branch; do
  echo "Processing branch: $branch"
  # Find and remove worktree if it exists
  worktree=$(git worktree list | grep "\\[$branch\\]" | awk '{print $1}')
  if [ ! -z "$worktree" ] && [ "$worktree" != "$(git rev-parse --show-toplevel)" ]; then
    echo "  Removing worktree: $worktree"
    git worktree remove --force "$worktree"
  fi
  # Delete the branch
  echo "  Deleting branch: $branch"
  git branch -D "$branch"
done

命令参考

# Bulk delete merged branches (excluding protected branches and current branch)
# Notes:
# - Uses for loop + case for bash/zsh compatibility (avoids `while IFS= read` issues in zsh).
# - Uses case statement for exact-name matching (avoids grep regex edge cases).
# - Always exclude the current branch to prevent accidental self-deletion.
BASE_BRANCH="$(git symbolic-ref --quiet --short refs/remotes/origin/HEAD 2>/dev/null | sed 's@^origin/@@')"
[ -n "$BASE_BRANCH" ] || BASE_BRANCH=main
CURRENT_BRANCH="$(git branch --show-current)"
for branch in $(git branch --merged "$BASE_BRANCH" | sed 's/^[* ]*//'); do
  case "$branch" in
    main|master|trunk|develop|development|"$CURRENT_BRANCH"|"") continue ;;
    *) git branch -d "$branch" ;;
  esac
done

# Prune remote-tracking references (requires network access)
# Note: This may fail if offline or remote is unreachable.
# If it fails, skip this step - branch analysis still works with cached remote data.
git fetch --prune || echo "Warning: Could not reach remote. Using cached data."

# List oldest branches (30+ days)
git for-each-ref --sort=committerdate refs/heads/ \
  --format='%(committerdate:short) %(refname:short)' | head -20

# Worktree commands
git worktree list                              # List all worktrees
git worktree remove /path/to/worktree          # Remove a worktree
git worktree remove --force /path/to/worktree  # Force remove (even if dirty)
git worktree prune                             # Clean up stale worktree refs

演练模式

预览将要执行的删除操作,但不实际执行:

# Preview only
BASE_BRANCH="$(git symbolic-ref --quiet --short refs/remotes/origin/HEAD 2>/dev/null | sed 's@^origin/@@')"
[ -n "$BASE_BRANCH" ] || BASE_BRANCH=main
CURRENT_BRANCH="$(git branch --show-current)"
for branch in $(git branch --merged "$BASE_BRANCH" | sed 's/^[* ]*//'); do
  case "$branch" in
    main|master|trunk|develop|development|"$CURRENT_BRANCH"|"") ;;
    *) echo "$branch" ;;
  esac
done

如果用户说“--dry-run”、“preview”或“just show me”,则启用演练模式。

安全检查清单

删除前,请确认:

  • 不是当前分支
  • 不是受保护分支(base/main/master/trunk/develop)
  • 没有尚未推送的提交(领先于上游)
  • 已先移除工作树(如果分支关联了工作树)
  • 已获得用户确认
快速安全检查命令
# Show "ahead/behind" vs upstream for each local branch
git for-each-ref refs/heads \
  --format='%(refname:short)|%(upstream:short)|%(upstream:trackshort)|%(committerdate:relative)|%(contents:subject)' \
  --sort=-committerdate

# For a specific branch, confirm it's not ahead of upstream (if upstream exists)
# (Empty output => nothing unpushed)
git log --oneline @{u}..HEAD 2>/dev/null || echo "No upstream configured for this branch"

# Check if a branch has an associated worktree
# ('+' prefix in git branch -v output indicates worktree)
git branch -v | grep "^+" | awk '{print $2}'

# Find worktree path for a specific branch
git worktree list | grep "\\[branch-name\\]"

评论

支持 Markdown