npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@michael-baker-us/git-branch-cleaner

v1.0.0

Published

Audit and safely clean up local git branches: merged, gone, stale, abandoned.

Readme

git-branch-cleaner (gbc)

Audit a repository's local branches — merged, gone (upstream deleted), stale, abandoned — and clean them up safely. gbc previews everything, deletes nothing without an explicit flag or confirmation, and archives instead of destroying by default.

$ gbc status
  BRANCH                  STATUS      LAST COMMIT   AHEAD/BEHIND   UPSTREAM
* main                    protected   today         -              -
  feature/dark-mode       active      today         2/0            (never pushed)
  feature/sepa            gone        today         1/0            (deleted)
  fix/rounding            merged      today         0/1            (never pushed)

2 branches safe to clean (gone, merged). Run: gbc clean

Safety model (read this first)

Deleting branches is destructive, so gbc is built defensively:

  • Nothing is deleted without an explicit action. status is read-only. clean requires interactive confirmation, or --yes for scripts.
  • Archive-before-delete. Before running git branch -D foo, gbc creates a lightweight tag archive/foo/<yyyy-mm-dd> at the branch tip. gbc restore foo recreates the branch from the newest archive tag. Opt out with --no-archive.
  • --dry-run mutates nothing. It prints exactly what would happen.
  • Protected branches are never touched. main, master, develop, and release/* are protected by default, as is the currently checked-out branch. This holds even with --yes.
  • No remote branches are ever deleted. v1 only deletes local branches and prunes local remote-tracking refs (prune-remotes).

Install

npm install -g @michael-baker-us/git-branch-cleaner   # provides the `gbc` binary
# or run from a clone:
npm install && npm run build && node dist/index.js status

Requires Node 20+ and git on the PATH.

Commands

| Command | What it does | | --- | --- | | gbc status | Read-only audit table (the default command). | | gbc clean | Interactively delete safe candidates; archives first. | | gbc restore <branch> | Recreate a branch from its newest archive tag. | | gbc prune-remotes | Preview + prune stale remote-tracking refs. |

gbc clean

Flow: show candidates → checkbox multi-select (all pre-checked) → type-to-confirm → per branch: create archive tag, then git branch -D.

| Flag | Effect | | --- | --- | | --dry-run | Print planned actions, change nothing. | | --yes | Skip prompts (scripting); deletes all candidates. | | --no-archive | Delete without creating recovery tags. | | --include-stale | Also offer stale branches. | | --include-abandoned | Also offer abandoned branches. |

Candidates default to merged + gone. In a non-interactive session (pipe/CI), clean refuses to prompt and asks you to pass --yes or --dry-run.

Exit codes: 0 success / nothing to do · 1 user aborted · 2 git error.

Classification

Branches are classified in strict precedence order:

  1. protected — matches a protected pattern, or is the current branch.
  2. gone — upstream was tracked but has been deleted ([gone]).
  3. merged — merged into the default branch (see below).
  4. abandoned — older than staleDays and behind default by > 50 commits and never pushed.
  5. stale — tip older than staleDays (default 30).
  6. active — everything else.

How "merged" is detected (and its limits)

  • Ancestry merge: git branch --merged <default> catches normal and --no-ff merges.

  • Squash-merge heuristic: git branch --merged misses squash merges, so gbc also treats a branch as merged when git cherry <default> <branch> reports no + lines — i.e. every unique commit on the branch already has a patch-equivalent in the default branch.

    Caveats you should know:

    • Branches with zero unique commits are excluded from the heuristic (they would otherwise look "merged" spuriously).
    • The heuristic compares per-commit patch IDs. A branch of several commits squashed into one combined commit on the default branch will not always be detected, because the individual patch IDs don't match the combined one. Such branches remain stale/active — safe, just not auto-flagged.

Configuration

Repo-level .gbcrc.yaml (all fields optional), overridable by flags:

staleDays: 30
protectedPatterns:
  - main
  - master
  - develop
  - release/*
defaultRemote: origin
defaultBranch: main   # omit to auto-detect from origin/HEAD, then main/master

Global flags: --stale-days <n>, --remote <name>, --default-branch <name>, --protect <glob> (repeatable; appended to the protected list, never replacing the defaults).

Development

npm install
npm test          # vitest against real temp git repos
npm run lint      # eslint
npm run typecheck # tsc --noEmit
npm run build     # emit dist/

Tests build real temporary git repositories via a fixture helper and run the actual command logic against them. Time is injected through a single clock seam so relative dates and staleness are deterministic. All git access goes through one injectable runGit wrapper, and only machine-readable (--porcelain / --format, NUL-separated) output is ever parsed.

Non-goals (v1)

  • No remote branch deletion (local branches + local tracking-ref pruning only).
  • No GitHub/GitLab API usage — "merged" is decided by git ancestry, not PR state.
  • No GUI/TUI beyond interactive prompts.

License

MIT