Skip to content

Commit 8fb9e66

Browse files
mtnbikencclaude
andcommitted
Enhance branch-cleanup with multi-layered merge detection
Improves the git:branch-cleanup command to detect merged branches using multiple methods, preventing false negatives when branches are rebased, squashed, or cherry-picked. Key improvements: - Added check_if_merged() function with 4 detection methods: * Standard: git branch --merged (commits in main history) * Merge-commit: searches merge commit messages * Content-identical: compares content with git diff (catches rebases) * Cherry-picked: detects equivalent patches with git cherry - Enhanced categorization to show detection method used - Updated examples to demonstrate new merge status labels - Improved output format with explanatory notes for rebased branches This fixes cases where branches show as unmerged despite having identical content in main, such as when maintainers rebase PRs before merging. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
1 parent a50fc18 commit 8fb9e66

File tree

1 file changed

+61
-6
lines changed

1 file changed

+61
-6
lines changed

plugins/git/commands/branch-cleanup.md

Lines changed: 61 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -34,12 +34,20 @@ The command should follow these steps:
3434
2. **Gather Branch Information**
3535
- List all local branches: `git branch`
3636
- Get current branch: `git branch --show-current`
37-
- Identify merged branches: `git branch --merged <main-branch>`
37+
- Identify merged branches using multi-layered detection:
38+
- Standard merge: `git branch --merged <main-branch>`
39+
- Merge commit messages: `git log <main-branch> --merges --oneline`
40+
- Content comparison: `git diff <main-branch>...<branch> --quiet`
41+
- Cherry-pick detection: `git cherry <main-branch> <branch>`
3842
- Check remote tracking: `git branch -vv`
3943
- Find remote-deleted branches: `git remote prune origin --dry-run`
4044

4145
3. **Categorize Branches**
42-
- **Merged branches**: Fully merged into main branch
46+
- **Merged branches**: Detected via one of these methods:
47+
- Standard: Commits directly in main branch history
48+
- Merge commit: Found in main's merge commit messages
49+
- Content-identical: All changes present in main (rebased/cherry-picked)
50+
- Cherry-picked: All commits have equivalents in main
4351
- **Gone branches**: Remote tracking branch no longer exists
4452
- **Stale branches**: Last commit older than threshold (e.g., 3 months)
4553
- **Protected branches**: main, master, develop, release/*, hotfix/*
@@ -79,8 +87,53 @@ fi
7987
# Get current branch
8088
current_branch=$(git branch --show-current)
8189

82-
# Find merged branches
83-
git branch --merged "$main_branch" | grep -v "^\*" | grep -v "$main_branch"
90+
# Multi-layered merge detection function
91+
# Returns: "merged:<method>" or "not-merged"
92+
check_if_merged() {
93+
local branch=$1
94+
local main_branch=$2
95+
96+
# Method 1: Standard merge check (commits in main history)
97+
if git branch --merged "$main_branch" | grep -q "^[* ]*${branch}$"; then
98+
echo "merged:standard"
99+
return 0
100+
fi
101+
102+
# Method 2: Check merge commit messages (catches squash merges and rebased branches)
103+
if git log "$main_branch" --merges --oneline | grep -q "Merge branch '${branch}'"; then
104+
echo "merged:merge-commit"
105+
return 0
106+
fi
107+
108+
# Method 3: Content comparison (handles rebased/cherry-picked branches)
109+
# If diff is empty, all content is in main even if commit hashes differ
110+
if git diff --quiet "$main_branch"..."$branch" 2>/dev/null; then
111+
echo "merged:content-identical"
112+
return 0
113+
fi
114+
115+
# Method 4: Cherry-pick detection (all commits have equivalents in main)
116+
# Commits prefixed with '-' have equivalent patches in main
117+
local unmerged=$(git cherry "$main_branch" "$branch" 2>/dev/null | grep -c '^+')
118+
if [ "$unmerged" -eq 0 ]; then
119+
echo "merged:cherry-picked"
120+
return 0
121+
fi
122+
123+
echo "not-merged"
124+
return 1
125+
}
126+
127+
# Find all merged branches with detection method
128+
for branch in $(git branch | grep -v "^\*" | sed 's/^[ ]*//'); do
129+
if [ "$branch" != "$main_branch" ]; then
130+
merge_status=$(check_if_merged "$branch" "$main_branch")
131+
if [[ "$merge_status" == merged:* ]]; then
132+
method=${merge_status#merged:}
133+
echo "$branch|$method"
134+
fi
135+
fi
136+
done
84137

85138
# Find branches with deleted remotes ("gone")
86139
git branch -vv | grep ': gone]' | awk '{print $1}'
@@ -123,8 +176,9 @@ git remote prune origin
123176
Current branch: feature/new-api
124177
125178
=== Merged Branches (safe to delete) ===
126-
feature/bug-fix-123 Merged 2 weeks ago
127-
feature/update-deps Merged 1 month ago
179+
feature/bug-fix-123 Merged (standard) - 2 weeks ago
180+
feature/update-deps Merged (merge-commit) - 1 month ago
181+
feature/bug-fix-123 Merged (content-identical) - 3 days ago
128182
129183
=== Gone Branches (remote deleted) ===
130184
feature/old-feature Remote: gone
@@ -139,6 +193,7 @@ git remote prune origin
139193
140194
Recommendations:
141195
- Safe to delete: feature/bug-fix-123, feature/update-deps (merged)
196+
* Note: feature/bug-fix-123 has different commits but identical content (rebased)
142197
- Safe to delete: feature/old-feature, hotfix/urgent-fix (remote gone)
143198
- Review needed: experiment/prototype (unmerged, stale)
144199

0 commit comments

Comments
 (0)