Skip to content

Feareis/Orphan

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

20 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

orphan

The bus factor, made concrete.

Not an abstract score — the named list of files whose knowledge sits with a single person, sorted by how much is actually at risk.

PyPI version Python versions Downloads License: MIT No dependencies

orphan in action

---

What it does

Every mature codebase has files only one person has ever really touched. Some are harmless. Some are a terraform module or an nginx.conf holding up production, understood by exactly one engineer — who may have left months ago.

orphan reads your git history and surfaces those files by name, with the owner, the age of the last commit, and a risk category. It reads history only, never file contents, so it works on any repository regardless of language — application code and infrastructure alike.

The three categories

Age alone is misleading: a LICENSE written once and never touched looks exactly like a dangerous orphan, but it's the healthiest file in the repo. orphan separates stable from risky using two axes — how much a file has evolved (commit count, a proxy for accumulated knowledge) and whether its sole owner is still active.

Category Meaning Signal
silo Many commits, one owner, still active Live, concentrated knowledge. One brain holds a growing area.
orphan Many commits, one owner, now inactive The knowledge has likely already walked out the door.
· stable Few commits (a base or config file) Low risk. Shown for completeness, not as an alarm.

The stable bucket exists on purpose: it's where the classic false positives land (base files an author wrote once before moving on), so they stop drowning out the real risks.

Why you'll like it

  • Zero dependencies. Pure Python standard library, 3.8+.
  • Portable. One self-contained module, no build step — install it or just run it from source.
  • Language-agnostic. Works on Terraform, Ansible, shell, YAML — anything git tracks, not just source code.
  • Localized output. English, French, German, Spanish, Italian (see Languages).
  • Scriptable. --json for pipelines and dashboards.

Installation

From PyPI

pipx install orphan

Then, in any repository:

orphan

From source (no install)

Clone the repo and run it as a module — nothing to build:

git clone https://github.com/Feareis/Orphan
cd Orphan
python3 -m orphan

That's it, no dependencies. English is built in; the other languages come from orphan/locales.json, shipped alongside the code.

Usage

orphan                     # analyze the current repository
orphan ../other-repo       # analyze another repository by path
orphan --lang fr           # localized output (en, fr, de, es, it)
orphan --dense-commits 8   # raise the silo/orphan vs stable threshold
orphan --active-months 6   # "inactive owner" cutoff (default: 12 months)
orphan --threshold 2       # also consider files with up to 2 authors
orphan --top 40            # cap the displayed rows (0 = all)
orphan --path infra/       # restrict to a subdirectory
orphan --json              # machine-readable output (never localized)

Options

Option Default Description
repo (positional) . Path to the git repository to analyze.
--lang en Output language: en, fr, de, es, it.
--path (repo root) Restrict analysis to a subdirectory of the repo.
--threshold 1 Max distinct authors for a file to be considered single-owned.
--dense-commits 5 Commits from which a file counts as knowledge-dense (silo/orphan vs stable).
--active-months 12 An author with no commit for N months counts as inactive.
--top 25 Show only the N riskiest files (0 for all).
--json (off) Emit raw JSON instead of the terminal report.
--no-color (off) Disable ANSI colors.

JSON output

--json emits stable, language-neutral data — ideal for CI gates or a dashboard:

{
  "summary": { "total": 12, "silo": 3, "orphan": 4, "stable": 5, "tracked_files": 210, "dense_commits": 5 },
  "files": [
    {
      "path": "infra/pipeline.tf",
      "kind": "infra",
      "category": "orphan",
      "owners": ["Bob"],
      "owner_count": 1,
      "commits": 8,
      "last_commit": "2024-05-01T10:00:00+00:00",
      "age_days": 800,
      "departed": true
    }
  ]
}

Languages

Switch the display language with --lang. English is built into the code; the other languages live in orphan/locales.json, shipped with the package. If that file is missing or a string is absent — or even mistranslated with a wrong {placeholder} — that line falls back to English instead of failing.

Adding a language (no code required)

Translations are pure data. To add, say, Portuguese:

  1. Open orphan/locales.json.
  2. Copy the "en" block — it's the reference and lists every key.
  3. Rename it "pt" and translate the values. Keep the {placeholders} intact.
  4. For the age units, note the _one / _other pairs — they exist so plurals read correctly (e.g. 1 mês vs 6 meses).
  5. Add "pt" to the --lang choices in orphan/cli.py (the LANGUAGES tuple).
  6. Open a pull request. 🎉

How it works

A single git log pass over the whole repository collects, per file, the set of authors and the date of the last commit, plus each author's most recent activity anywhere in the repo. %aN applies your .mailmap, so one person committing under several emails counts once. Files are then bucketed into the three categories and sorted so the densest live silos rise to the top.

One git invocation for the whole repo — fast even on large histories.

Limitations

Honest by design:

  • Commit count is a proxy for knowledge, not size. A large file written in a single commit reads as stable even if it holds a lot.
  • Renames aren't followed in a repo-wide log, so a freshly renamed file may look single-owner even if it had history under its old name.
  • Ownership is per commit, not per line. "Who has ever touched this file" is the right orphan signal and far faster than running git blame per file.
  • "Inactive" is inferred from git activity, not HR data. Someone working on another repo for a year will read as inactive. Tune --active-months to your team's rhythm.

Contributing

Issues and pull requests welcome — a new translation, a smarter category heuristic, an extra infra file type. Adding a language needs no Python (see above).

License

MIT — do what you like, no warranty.

About

The bus factor, made concrete: the named list of single-owner files in a repo, ranked by risk. Git-history only, language-agnostic, zero deps.

Topics

Resources

License

Stars

0 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages