Clean up local Git branches that have merged PRs on GitHub
npm install git-cleanup-merged



A Node.js command-line tool that automatically identifies and deletes local Git branches that have been merged via GitHub Pull Requests.
---
-  CI runs on all pull requests and on push to main/master only via GitHub Actions (tests Node.js 18.x, 20.x)
- This avoids duplicate runs for feature branches and is the recommended best practice for open source projects.
-  Live coverage tracking via Codecov
- ๐ฆ Branch coverage threshold: CI will fail if branch coverage drops below 75%
- ๐ JUnit test results and coverage are uploaded to Codecov for every CI run
- ๐งช Run tests locally:
``bash`
npm test
npm run test:coverage
npm run test:coverage
- ๐ Check coverage report:
After running , open coverage/lcov-report/index.html in your browser for a detailed report.
- ๐ Code quality: ESLint and Prettier configured for consistent code style
---
- ๐ Smart Detection: Automatically checks GitHub PR status for tracked branches
- ๐ท๏ธ Untracked Branch Support: Clean up local-only branches with --untracked-only modemain
- โ
Safe Deletion: Only deletes branches with merged or closed PRs, or untracked branches
- ๐ Protection: Never deletes , master, or your current branch
- ๐ Preview Mode: Dry-run option to see what would be deleted
- ๐ Directory Support: Operate on any git repo by passing a directory as the first argument
- โก Performance: Parallel PR status checking and branch deletion for faster processing
- ๐จ Colorful Output: Clear visual indicators with status icons (โ
Merged, ๐ Closed, โณ Open)
- ๐ Status Overview: Shows comprehensive branch status table
- โก Interactive Spinner: Real-time progress updates with an animated spinner
- ๐ก๏ธ Comprehensive Testing: 100% test coverage for statements, branches, functions, and lines with 168 test cases
- ๐ฏ Code Quality: ESLint and Prettier for consistent code style
- ๐ง Smart UX: Focused modes - main mode for PR cleanup, untracked mode for local cleanup
Before installing, make sure you have:
- Node.js (version 18 or higher - tested on 18.x and 20.x)
- Git installed and configured
- GitHub CLI (gh) installed and authenticated (only required for main mode, not for --untracked-only)
- Active internet connection for GitHub API calls (only required for main mode)
If you don't have GitHub CLI installed:
macOS (Homebrew):
`bash`
brew install gh
Windows (Chocolatey):
`bash`
choco install gh
Linux (Ubuntu/Debian):
`bash`
curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg | sudo dd of=/usr/share/keyrings/githubcli-archive-keyring.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" | sudo tee /etc/apt/sources.list.d/github-cli.list > /dev/null
sudo apt update
sudo apt install gh
Authenticate GitHub CLI:
`bash`
gh auth login
`bashInstall globally from npm (if published)
npm install -g git-cleanup-merged
$3
`bash
Clone the repository
git clone https://github.com/ondro/git-cleanup-merged.git
cd git-cleanup-mergedInstall dependencies
npm installMake executable (Unix/macOS/Linux)
chmod +x index.jsCreate symlink for global access (optional)
npm link
`$3
`bash
Download the script directly
curl -o git-cleanup-merged https://raw.githubusercontent.com/ondro/git-cleanup-merged/main/index.js
chmod +x git-cleanup-mergedMove to your PATH
sudo mv git-cleanup-merged /usr/local/bin/
`$3
`bash
Run directly without installing
npx git-cleanup-mergedOr from GitHub
npx https://github.com/ondro/git-cleanup-merged.git
`Usage
$3
> Note: At the start of every run, the tool will display the name of the repository directory being scanned (e.g. 'git-local-branch-cleanup' or 'ollama-git-commit'), so you always know which directory is being operated on.
#### Main Mode (Default) - Clean up branches with merged PRs
`bash
Clean up merged branches (with confirmation)
git-cleanup-mergedClean up merged branches in a different directory
git-cleanup-merged ../path/to/repoPreview what would be deleted (dry run)
git-cleanup-merged --dry-runShow detailed processing information
git-cleanup-merged --verboseCombine options
git-cleanup-merged ../path/to/repo --dry-run --verbose
`#### Untracked Mode - Clean up local-only branches
`bash
Clean up untracked branches (local branches without remote tracking)
git-cleanup-merged --untracked-onlySame as above using shorthand
git-cleanup-merged -uPreview untracked branches (dry run)
git-cleanup-merged --untracked-only --dry-runSame as above using shorthand
git-cleanup-merged -u -nShow detailed processing for untracked branches
git-cleanup-merged --untracked-only --verboseSame as above using shorthand
git-cleanup-merged -u -vClean up untracked branches in a different directory
git-cleanup-merged ../path/to/repo --untracked-onlySame as above using shorthand
git-cleanup-merged ../path/to/repo -u
`$3
| Option | Short | Description |
| ------------------ | ----- | ------------------------------------------------------------------------------------ |
|
[DIRECTORY] | | Path to a git repository to operate on. Defaults to the current directory if omitted |
| --dry-run | -n | Show what would be deleted without actually deleting |
| --verbose | -v | Show detailed information during processing |
| --untracked-only | -u | Only process untracked local branches (no remote tracking branch) |
| --count | -c | Display branch count summary and exit (no deletion) |
| --version | -V | Show version information |
| --help | -h | Show help message |$3
#### Main Mode (Default) - Branches with merged PRs
`
๐ Scanning repository: my-project
โ
Dependencies checked
โ
Current branch: main
โ
Finished checking 3 tracked branchesโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Branch Icon Status
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
feature/user-authentication โ
Merged
bugfix/header-layout โ
Merged
feature/experimental ๐ Closed
feature/dark-mode โณ Open
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ The following branches have merged or closed PRs and will be deleted:
feature/user-authentication
bugfix/header-layout
feature/experimental
Proceed with deletion? (y/N): y
โ
Deleted branch feature/user-authentication
โ
Deleted branch bugfix/header-layout
โ
Deleted branch feature/experimental
โ
Successfully deleted 3 branches
`#### Untracked Mode - Local-only branches
`
๐ Scanning repository: my-project
โ
Dependencies checked
โ
Current branch: main
โ
Finished processing 2 untracked branchesโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Branch Icon Status
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
debug/test-branch ๐ท๏ธ Untracked
temp/experiment ๐ท๏ธ Untracked
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ The following untracked local branches will be deleted:
debug/test-branch
temp/experiment
Proceed with deletion of untracked branches? (y/N): y
โ
Deleted branch debug/test-branch
โ
Deleted branch temp/experiment
โ
Successfully deleted 2 branches
`How It Works
$3
1. Dependency Check: Verifies you're in a Git repository and GitHub CLI is installed/authenticated
2. Current Branch Detection: Identifies and protects your current working branch
3. Tracked Branch Discovery: Lists only branches that have remote tracking (excluding
main, master, current branch)
- Uses Git's upstream tracking information to accurately detect tracked branches
- Works with any remote name (origin, upstream, etc.) - not hard-coded to "origin"
- Robust parsing handles multiple consecutive spaces in Git output
4. PR Status Check: Queries GitHub API for each branch's PR status with progress indication
5. Results Display: Shows a comprehensive status table with clear visual indicators
6. Safe Deletion: Only deletes branches with merged or closed PRs (with user confirmation)$3
1. Dependency Check: Verifies you're in a Git repository (GitHub CLI not required)
2. Current Branch Detection: Identifies and protects your current working branch
3. Untracked Branch Discovery: Lists only local branches without remote tracking (excluding
main, master, current branch)
- Uses Git's upstream tracking information to accurately detect untracked branches
- Works with any remote name (origin, upstream, etc.) - not hard-coded to "origin"
- Robust parsing handles multiple consecutive spaces in Git output
4. Results Display: Shows untracked branches with ๐ท๏ธ icon
5. Safe Deletion: Deletes untracked branches (with user confirmation)Branch Status Indicators
$3
| Icon | Status | Description |
| ---- | ------ | ------------------------------------------------------ |
| โ
| Merged | PR has been merged - branch is safe to delete |
| ๐ | Closed | PR has been closed without merging - branch is safe to delete |
| โณ | Open | PR is still open - branch will be preserved |
| โ | No PR | No PR found for this branch - branch will be preserved |
$3
| Icon | Status | Description |
| ---- | --------- | ----------------------------------------------------- |
| ๐ท๏ธ | Untracked | Local branch without remote tracking - safe to delete |
Safety Features
- Protected Branches: Never touches
main, master, or your current branch
- Confirmation Required: Always asks before deleting (unless in dry-run mode)
- GitHub Verification: Only deletes branches with confirmed merged or closed PRs (main mode)
- Untracked Detection: Only deletes local branches without remote tracking (untracked mode)
- Robust Parsing: Handles various Git output formats including multiple consecutive spaces
- Error Handling: Graceful failure handling with informative messages
- Progress Feedback: Real-time spinner shows current operation status
- Smart UX: Main mode focuses on PR cleanup, untracked mode focuses on local cleanupTroubleshooting
$3
"Not in a git repository"
- Make sure you're running the command from within a Git repository
"GitHub CLI (gh) is not installed"
- Install GitHub CLI following the prerequisites section above
"GitHub CLI is not authenticated"
- Run
gh auth login and follow the authentication process"Failed to get current branch"
- Ensure you're in a valid Git repository with at least one commit
Branch names appearing garbled in terminal
- This was a known issue with the spinner display that has been fixed in recent versions
$3
For troubleshooting, use verbose mode to see detailed processing:
`bash
Main mode with verbose output
git-cleanup-merged --verbose --dry-runUntracked mode with verbose output
git-cleanup-merged --untracked-only --verbose --dry-runSame as above using shorthand
git-cleanup-merged -u -v -n
`Development
$3
`
git-cleanup-merged/
โโโ __tests__/ # Test files
โ โโโ index.test.js # Main functionality tests
โ โโโ spinner.test.js # Spinner component tests
โ โโโ utils.test.js # Utility function tests
โโโ coverage/ # Coverage reports (generated)โโโ src/
โ โโโ bin.js # CLI entry point
โ โโโ index.js # Main GitCleanupTool class
โ โโโ utils/
โ โโโ index.js # Utility functions
โ โโโ spinner.js # Spinner component
โโโ package.json
โโโ package-lock.json
โโโ eslint.config.mjs # ESLint configuration
โโโ .prettierrc # Prettier configuration
โโโ README.md
`$3
- GitCleanupTool: Main class that orchestrates the cleanup process
- Spinner: Enhanced spinner class with proper terminal handling and testability
- CLI Entry Point: Separate
bin.js file for clean CLI execution
- Test Suite: Comprehensive tests covering all functionality and edge cases$3
1. Fork the repository
2. Create a feature branch
3. Make your changes
4. Test thoroughly with both
--dry-run and actual deletion
5. Submit a pull request$3
`bash
Run all tests
npm testRun tests with coverage
npm run test:coverageRun linting
npm run lintRun linting with auto-fix
npm run lint -- --fixFormat code
npm run format
`License
MIT License - see LICENSE file for details.
๐ Changelog
$3
- Implemented major refactoring of branch handling: unified
getBranches with mode support; added parallel PR status checks and deletion with concurrency limits; updated README to reflect new performance and icon details; bumped package version to 1.0.2. Enhanced error messaging, streamlined spinner usage, and improved test coverage for new logic.
- feat: Add new --version flag, improve error handling, and enhance timeouts
- chore: Bump the version to 1.0.5 and update Jest configuration
- fix: Update test case count and enhance spinner messaging
- chore: Remove unused useFullFilePath option in Jest configuration
- docs: Add NPM publishing badges and update changelog in README, Clean up and consolidate changelog in README$3
- ๐ท๏ธ New Feature: Added
--untracked-only mode to clean up local branches without remote tracking
- ๐ง Improved UX: Main mode now only shows tracked branches with PRs, untracked mode handles local-only branches
- ๐ง Smart Dependencies: GitHub CLI only required for main mode, not for untracked mode
- ๐ก Helpful Guidance: Suggests --untracked-only when no tracked branches found in main mode
- ๐ฏ 100% Test Coverage: Achieved complete test coverage with 97 comprehensive test cases
- ๐ Bug Fixes: Fixed branch tracking detection logic and improved deletion feedback
- ๐ Enhanced Testing: Added tests for all new functionality and edge cases
- ๐ง Critical Fix: Fixed branch tracking detection to use proper Git upstream relationships instead of hard-coded remote names
- ๐ ๏ธ Robust Parsing: Fixed whitespace parsing bug that could misclassify tracked branches as untracked
- ๐ Critical Bug Fix: Fixed whitespace parsing issue in branch tracking detection
- The line.split(" ") logic was not robust and could misclassify tracked branches as untracked when git for-each-ref output contained multiple consecutive spaces
- Replaced with line.split(/\s+/) and proper array handling to correctly parse branch names and upstream information
- Added comprehensive tests to verify the fix works with various whitespace scenarios
- ๐งช Enhanced Testing: Added 2 new test cases specifically for whitespace parsing edge cases
- โ
Maintained Quality: 100% test coverage preserved with 168 test cases$3
- ๐ง Node.js Compatibility: Updated to require Node.js 18+ for ESLint 9.x compatibility
- ๐งช CI Updates: Removed Node.js 16.x from CI matrix (reached end-of-life)
- ๐ฆ Dependencies: Updated to use modern ESLint flat config format
- ๐ฆ Workflow Optimization: CI now only runs on pull requests and on push to
main/master to avoid duplicate runs for feature branches
- ๐ท๏ธ New Feature: Added --untracked-only mode to clean up local branches without remote tracking
- ๐ง Improved UX: Main mode now only shows tracked branches with PRs, untracked mode handles local-only branches
- ๐ง Smart Dependencies: GitHub CLI only required for main mode, not for untracked mode
- ๐ก Helpful Guidance: Suggests --untracked-only when no tracked branches found in main mode
- ๐ฏ 100% Test Coverage: Achieved complete test coverage with 97 comprehensive test cases
- ๐ Bug Fixes: Fixed branch tracking detection logic and improved deletion feedback
- ๐ Enhanced Testing: Added tests for all new functionality and edge cases
- ๐ง Critical Fix: Fixed branch tracking detection to use proper Git upstream relationships instead of hard-coded remote names
- ๐ ๏ธ Robust Parsing: Fixed whitespace parsing bug that could misclassify tracked branches as untracked$3
- ๐ฏ 100% Test Coverage: Achieved complete test coverage across all code paths
- ๐งช Enhanced Test Suite: Added 76 comprehensive test cases covering all functionality
- ๐ง Code Quality: Added ESLint and Prettier for consistent code style
- ๐๏ธ Architecture Improvements: Separated CLI entry point for better testability
- ๐ Bug Fixes: Fixed spinner component and improved error handling
- ๐ Coverage Thresholds: Set minimum 75% branch coverage requirement
- ๐ง Node.js Compatibility: Updated to require Node.js 18+ for ESLint 9.x compatibility
- ๐งช CI Updates: Removed Node.js 16.x from CI matrix (reached end-of-life)
- ๐ฆ Dependencies: Updated to use modern ESLint flat config format
- ๐ฆ Workflow Optimization: CI now only runs on pull requests and on push to
main/master to avoid duplicate runs for feature branches$3
- Fixed spinner display issue where branch names would merge together
- Improved terminal output clearing with proper ANSI escape sequences
- Enhanced progress indicators during branch checking and deletion
- Added directory argument support for operating on different repositories
- ๐ฏ 100% Test Coverage: Achieved complete test coverage across all code paths
- ๐งช Enhanced Test Suite: Added 76 comprehensive test cases covering all functionality
- ๐ง Code Quality: Added ESLint and Prettier for consistent code style
- ๐๏ธ Architecture Improvements: Separated CLI entry point for better testability
- ๐ Bug Fixes: Fixed spinner component and improved error handling
- ๐ Coverage Thresholds: Set minimum 75% branch coverage requirement
$3
- Initial release
- Basic branch cleanup functionality
- GitHub PR integration
- Dry-run mode
- Verbose logging
- Interactive spinner with progress feedback
๐ค Support
- ๐ Bug Reports: GitHub Issues
- ๐ก Feature Requests: GitHub Discussions
- ๐ง Contact: ondrovic@gmail.com
- ๐ Documentation: This README contains comprehensive usage examples and troubleshooting
---
โ ๏ธ Important: Always run with
--dry-run` first to preview changes before actual deletion. This tool is designed to be safe, but you should always verify the branches it wants to delete.