branch-origin
v0.1.1
Published
CLI and web tool that infers the most likely parent branch of any Git branch using merge-base analysis, reflog and confidence scoring.
Maintainers
Readme
Branch Origin Finder
Why this exists
Git does not store the parent branch of a branch. When a developer creates feature/payment-refactor, Git never records whether it came from main, develop or release/2.1. This tool infers the most likely parent branch from the commit history instead of guessing.
It is not a tutorial project. It solves a real developer tooling problem, using merge-base analysis, reflog inspection and upstream tracking to produce a confidence score, not an absolute answer. Git does not guarantee ground truth here, so the tool never claims to.
Features
- CLI command
branch-origin <branch-name>with a confidence score, defaulting to the current branch when none is given --allflag to analyze every local branch against the others in one pass--jsonflag for structured output-C <path>flag to run against a repository other than the current directory- Works with npm, yarn, bun and pnpm: the CLI compiles to plain JS (
pnpm build:cli) and exposes abinentry, it does not assume any single package manager - Merge-base analysis, ranked by recency in the commit graph (not just by commit date, which can tie or be rewritten by a rebase)
- Reflog inspection for local
checkoutentries and branch creation records (local only) - Upstream tracking via
branch.<name>.merge - Candidate branches are not hardcoded to
main/master: the remote's actual default branch (origin/HEAD) is detected and always included, whatever it is named - A topology check that rules out a candidate when the target branch is provably older than it, instead of reporting a confident but nonsensical match
- Web interface: paste a
--jsonresult to visualize the branch graph, confidence score and reasons, no server-side git access involved - The confidence bar and percentage count up together, color-coded by tier (high / medium / low)
- French/English language toggle
- Light/dark theme toggle (with interaction sounds)
Example output:
Branch: feature/payment-refactor
Likely source branch : develop (95%)
Branch point : commit 4d0acce
Reasons :
Reflog checkout entry found from develop
Nearest common ancestor found, more recent than other candidates
Fewer divergent commits than mainTech stack
- Next.js (App Router)
- Node.js / CLI core (
commander,simple-git, compiled withtsup) - Tailwind CSS + Shadcn UI (web interface)
- next-themes (dark/light mode)
- cuelume (interaction sounds)
- pnpm (repo tooling), npm/yarn/bun all work for running the built CLI
Screenshots / Demo GIF
Light mode:

Dark mode:

Pasting a CLI result, exploring the confidence breakdown, and toggling theme/language:

How to reuse
As an installed CLI: npx branch-origin <branch-name> --json, or npm install -g branch-origin and run branch-origin <branch-name> directly. No clone needed. The published package (branch-origin on npm) is a single self-contained file with no runtime dependencies of its own.
From the repo, for development:
- Clone the repo and install dependencies:
pnpm install - Run the CLI directly with
pnpm branch-origin <branch-name> -C /path/to/repo, or--jsonfor structured output, or--allto check every branch at once pnpm build:clibuilds and bundlesdist/cli.js(used for the npm release), runnable withnode dist/cli.js <branch-name> --jsonregardless of package manager- Start the web interface with
pnpm dev, then paste a--jsonresult (or click "Load example") to visualize it
The web interface is a companion for CLI output, not a replacement for it: it only renders JSON you paste into it, it never runs Git itself (Vercel's serverless functions have no git binary, and cloning arbitrary repositories server-side is a security surface this project deliberately avoids, see the architecture notes below).
Architecture
lib/git/infer-origin.tsis the entry point of the analysis: it resolves candidate branches, gathers signals for each, and scores themlib/git/branches.tsresolves candidates: it readsorigin/HEADto find the real default branch whatever it is named, falls back to common integration branch names (main,master,develop,release/*), and falls back again to every other local branch if none matchlib/git/merge-base.ts,lib/git/reflog.tsandlib/git/upstream.tseach read one independent signal from the repository (merge-base and divergence, reflog checkout entries, upstream tracking config)lib/git/ancestry.tsranks merge-base commits by actual position in the commit graph rather than trusting commit timestamps alone; it shells out directly withchild_processbecausesimple-git'sraw()does not reliably surface a non-zero exit code when a command likemerge-base --is-ancestorproduces no stderr outputlib/git/confidence.tsturns the gathered signals into a weighted score and a list of reasons, and filters out candidates the commit graph proves cannot be the sourcebin/branch-origin.tsis the CLI entry point (commander), calling the samelib/gitcore used by the web interface;tsup.config.tsbundles it (CommonJS, dependencies included) into a singledist/cli.jswith zero runtime dependencies of its ownscripts/prepare-npm-package.mjswrites a minimaldist/package.json(no dependency on the Next.js app's own dependencies) sonpm publishfromdist/ships a small, self-contained CLI packagelib/git/types.tsdefinesConfidenceReasonas acodeplus structuredparams, so both the English CLI output and the localized web UI can render the same reason from the same datalib/git/validate.tsis a small runtime type guard for JSON pasted into the web interface, so malformed input fails with a readable error instead of a crashcomponents/git/holds the web interface:json-input-form.tsx(paste + parse),origin-result-card.tsx(score, reasons, candidate breakdown),branch-graph.tsx(the divergence diagram),confidence-bar.tsx(color-coded, animated vialib/hooks/use-count-up.ts) andcli-command.tsx(the pnpm/npm/yarn/bun command picker with copy-to-clipboard)lib/i18n/holdsen.json/fr.jsondictionaries;localizeReason()re-renders aConfidenceReasonin the active localelib/github.tsreads the repo's live star count from the GitHub API (revalidated every 5 minutes) for the header's "star this repo" button
