git-ops
Git hygiene: clean up merged branches, prune stale remotes, and verify repository state.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Git hygiene: clean up merged branches, prune stale remotes, and verify repository state.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
Consult external AI council (Gemini 3.5 Flash, Codex, Qwen, GLM-5.2, Kimi) for thorough reviews and consensus-driven decisions. Use ONLY when explicitly invoked with "/council" or when user says "consult the council", "invoke council", or "council review". Do NOT auto-trigger on generic phrases like "thorough review".
PR babysitter: monitors CI status, auto-rebases when behind, auto-fixes CI where possible, delegates review comment handling to dlc:pr-check, and re-requests review after fixes. Designed for /loop usage with Remote Control.
Council review reference data — expertise weights, structured response format, scoring thresholds, and false positive taxonomy. Background knowledge for council subagents.
Audit review checklist for a repo: cluster recurring review-comment themes across merged PRs in a window, diff against docs/code-review-checklist.md, and open a PR proposing new entries with PR traceability. Designed for /schedule monthly cadence. Pass --dry-run to print clusters without opening a PR. Trigger phrases: audit review checklist, update review checklist, cluster PR findings.
Multi-agent development workflow using Agent Teams. Supports five modes: plan (architect teammate + PM teammate debate → plan.md), dev (developer teammate + code-tester teammate + qa-tester teammate + reviewer teammate iterate → code), full (plan → approval gate → dev), auto (plan → dev, no gate), and bugfix (tester + developer + reviewer TDD triad → fix + PR). Use when tasks benefit from collaborative agent teammates with peer messaging.
You MUST use this skill before /pm when work is ambiguous, scope is unclear, or multiple approaches exist. Explores problem space, proposes 2-3 approaches with trade-offs, and produces an approved spec document that feeds into both issue creation (/pm) and implementation planning (/cdt). Triggers: brainstorm, explore idea, think through, design approach, what should we build, explore options, weigh approaches, compare solutions, needs help deciding between alternatives.
| name | git-ops |
| description | Git hygiene: clean up merged branches, prune stale remotes, and verify repository state. |
| allowed-tools | ["Bash","AskUserQuestion"] |
Automated git hygiene — clean up merged branches, prune stale remote tracking refs, and verify repository state.
Fetch latest state, prune deleted remote branches, and sync the default branch.
# Detect the default branch dynamically
# 2>/dev/null suppresses errors when symbolic-ref is not set (e.g. shallow clone)
DEFAULT_BRANCH=$(git symbolic-ref refs/remotes/origin/HEAD 2>/dev/null | sed 's|refs/remotes/origin/||')
# Fallback: check for main, then master
if [ -z "$DEFAULT_BRANCH" ]; then
if git show-ref --verify --quiet refs/remotes/origin/main; then
DEFAULT_BRANCH="main"
elif git show-ref --verify --quiet refs/remotes/origin/master; then
DEFAULT_BRANCH="master"
else
echo "ERROR: Cannot determine default branch. Aborting."
exit 1
fi
fi
echo "Default branch: $DEFAULT_BRANCH"
# Fetch and prune stale remote tracking refs
git fetch origin --prune
# Abort if worktree has uncommitted changes
if [ -n "$(git status --porcelain)" ]; then
echo "ERROR: Worktree is dirty — stash or commit your changes before running git-ops."
exit 1
fi
# Capture starting branch before switching — Step 3 uses this for the commit range
START_REF=$(git branch --show-current)
# Switch to default branch and pull (fast-forward only to avoid merge commits)
git checkout "$DEFAULT_BRANCH"
git pull --ff-only origin "$DEFAULT_BRANCH"
If git pull --ff-only fails, abort with: "ERROR: non-fast-forward update for $DEFAULT_BRANCH. Resolve manually."
Combine two detection methods and deduplicate:
# Method 1: Branches fully merged into the default branch
MERGED=$(git branch --merged "$DEFAULT_BRANCH" | grep -v '^\*' | sed 's/^[[:space:]]*//')
# Method 2: Branches whose remote tracking ref is gone (plumbing command for reliable parsing)
GONE=$(git for-each-ref --format '%(refname:short) %(upstream:track)' refs/heads | grep '\[gone\]' | cut -d' ' -f1)
# Combine and deduplicate: track which method(s) detected each branch
# Branches in both lists get reason "merged + gone"
Filter out protected branches — never include these in candidates:
$DEFAULT_BRANCH (the dynamically detected default branch)mainmasterdeveloprelease/*# Filter protected branches from the combined candidate list
echo "$CANDIDATES" | grep -v -E "^(main|master|develop|${DEFAULT_BRANCH})$" | grep -v '^release/'
For each candidate, record:
| Field | Value |
|---|---|
name | Branch name |
reason | merged (from method 1), gone (from method 2), or merged + gone (both) |
has_remote | yes if git ls-remote --exit-code --heads origin "$name" succeeds, no otherwise |
If no candidates are found, print "No cleanup candidates found. Repository is clean.", skip Steps 4 and 5, and continue with Step 3.
Check whether commits on the current branch follow the conventional commit format required by semantic-release.
# Use START_REF captured before default-branch checkout in Step 1; fall back to HEAD
TARGET_REF="${START_REF:-HEAD}"
# Check commits on current branch not yet merged into default branch
COMMITS=$(git log --format="%s" "origin/${DEFAULT_BRANCH}..${TARGET_REF}" 2>/dev/null)
if [ -z "$COMMITS" ]; then
echo "No commits ahead of ${DEFAULT_BRANCH} to check."
else
TOTAL=0; CONVENTIONAL=0; NON_CONVENTIONAL=0; BAD_MSGS=""
while IFS= read -r msg; do
TOTAL=$((TOTAL + 1))
# Single-quoted regex avoids shell expansion; allows optional scope and breaking-change (!)
if echo "$msg" | grep -qE '^(feat|fix|chore|docs|style|refactor|test|perf|ci|build|revert)(\([^)]*\))?(!)?: .+'; then
CONVENTIONAL=$((CONVENTIONAL + 1))
else
NON_CONVENTIONAL=$((NON_CONVENTIONAL + 1))
BAD_MSGS+=$'\n'" - ✗ \"$msg\""
fi
done < <(printf '%s\n' "$COMMITS")
if [ "$NON_CONVENTIONAL" -gt 3 ]; then
COMMIT_SEVERITY="High"
elif [ "$NON_CONVENTIONAL" -gt 0 ]; then
COMMIT_SEVERITY="Medium"
else
COMMIT_SEVERITY="Info"
fi
echo "Commit quality: $COMMIT_SEVERITY ($CONVENTIONAL/$TOTAL conventional)"
fi
Severity table:
| Condition | Severity |
|---|---|
| All commits conventional | Info (positive) |
| Any non-conventional commit | Medium |
| More than 3 non-conventional commits | High |
Store: total_commits, conventional_count, non_conventional_count, list of non-conventional messages.
This check is informational only — results feed into the Step 6 report; no GitHub issue is created.
Display the candidate list with reasons:
Found {n} branch(es) to clean up:
{branch-1} (merged, has_remote: no) → delete local only
{branch-2} (gone, has_remote: no) → delete local only
{branch-3} (merged + gone, has_remote: yes) → delete local + remote
Use AskUserQuestion with three options:
| Option | Behavior |
|---|---|
| Delete all | Proceed to delete all candidates |
| Let me pick | Present each branch individually for yes/no selection |
| Skip | Abort cleanup — no branches deleted |
If the user selects Skip, print "Cleanup skipped." and jump to Step 6.
If the user selects Let me pick, iterate through each candidate and use AskUserQuestion to confirm deletion individually. Collect the confirmed subset.
For each confirmed branch:
# Safe delete — Git will refuse if the branch is not fully merged
if ! git branch -d "$BRANCH_NAME"; then
echo "WARNING: Failed to delete $BRANCH_NAME — skipping."
continue
fi
# If the branch has a remote tracking ref, delete it from origin
if git ls-remote --exit-code --heads origin "$BRANCH_NAME" > /dev/null; then
git push origin --delete "$BRANCH_NAME"
fi
Safety rules:
-d (NOT -D) — Git's built-in safety check prevents deleting unmerged branches$DEFAULT_BRANCH, main, master, develop, release/*) even if they appear in candidates (defense-in-depth)git branch -d fails for a branch, report the failure and continue with the next branch — do not abort the entire cleanupgit push origin --delete fails, report the failure but count the local deletion as successfulPrint a summary:
Git ops complete.
Before: {n} local branches
After: {n} local branches
Deleted: {n} branches
Deleted:
- {branch-1} (merged)
- {branch-2} (gone)
Failed (if any):
- {branch-3}: not fully merged (use git branch -D to force)
Remaining:
- main
- develop
- feature/in-progress
Commit message quality:
- Total commits on branch: {n}
- Conventional: {n} Non-conventional: {n}
- Status: [✓ all conventional | ⚠ {n} non-conventional] — severity: {severity}
{For each non-conventional commit:}
- ✗ "{message}"
If no branches were deleted (skip or no candidates), omit only the "Deleted" and "Failed" sections — always include the "Remaining" section and the "Commit message quality" section below it.
If no commits are ahead of the default branch (Step 3 found an empty range), replace the entire "Commit message quality:" section (including the header) with:
No commits ahead of {DEFAULT_BRANCH} to check.