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

git-own

v1.0.2

Published

Git contributor statistics CLI — per-author commits, lines, and code ownership

Downloads

85

Readme

git-own

Git contributor statistics CLI — scan a repository and see who wrote what, how much they own, and when they were active.

npm version license node


git-own analyzes any git repository and reports per-author statistics: commits, lines added/removed, files touched, active days, and current code ownership — the share of the codebase each author owns today, computed with git blame.

$ git-own

┌────────────────────┬───────────────────────────────────┬─────────┬────────┬────────┬───────┬──────┬────────────┬────────────┬────────┐
│ Author             │ Email                             │ Commits │ +Lines │ -Lines │ Files │ Days │ First      │ Last       │  Code% │
├────────────────────┼───────────────────────────────────┼─────────┼────────┼────────┼───────┼──────┼────────────┼────────────┼────────┤
│ Sindre Sorhus      │ [email protected]            │     187 │  4,172 │  3,984 │    59 │  115 │ 2013-08-03 │ 2025-09-08 │ 42.50% │
├────────────────────┼───────────────────────────────────┼─────────┼────────┼────────┼───────┼──────┼────────────┼────────────┼────────┤
│ Richie Bendall     │ [email protected]           │      15 │    376 │    859 │    18 │   13 │ 2019-03-01 │ 2024-01-20 │ 15.05% │
├────────────────────┼───────────────────────────────────┼─────────┼────────┼────────┼───────┼──────┼────────────┼────────────┼────────┤
│ LitoMore           │ [email protected] │       5 │    254 │    123 │     6 │    5 │ 2022-06-26 │ 2022-10-31 │  7.50% │
└────────────────────┴───────────────────────────────────┴─────────┴────────┴────────┴───────┴──────┴────────────┴────────────┴────────┘

Total: 71 authors · 348 commits · +9,127 / -6,761 lines · 1,661 blameable lines · 26 files · 6 excluded

Table of contents

Features

| Category | What | | --- | --- | | Code ownership | Code% via git blame (whitespace-insensitive) — who owns the code now, not who wrote the most ever | | History stats | Commits, +Lines, -Lines, files touched, active days, first/last commit — from a single streaming git log pass | | Time filtering | --since/--until date filters and --from/--to revision ranges; Code% reflects only code written in the range | | Author identity | Grouped by email; respects .mailmap; --merge-by-name for same-name duplicates | | Author filter | --author to show only matching contributors (name or email substring) | | File exclusions | Auto-excludes lock files, build output, minified code, vendored dirs; --exclude globs, .git-own-ignore, .gitattributes | | Config file | .git-own.json for persistent defaults | | Output formats | Pretty table (default), JSON, CSV, Markdown | | Performance | Parallel blame (--concurrency, auto-on by default) | | Sort & limit | By any metric; default sort is Code% descending |

Install

Via npm

npx git-own [path] [options]          # run without installing
npm install -g git-own                # install globally
git-own [path] [options]

From source

Requires Node.js 20+ and pnpm.

git clone https://github.com/ahmedsemih/git-own.git
cd git-own
pnpm install
pnpm build
node dist/index.js [path] [options]

Quick start

# scan the current directory
git-own

# scan a specific repo, show top 10 by commits
git-own /path/to/repo --top 10 -s commits

# who contributed in 2025?
git-own --since 2025-01-01 --until 2025-12-31

# export to JSON for scripting
git-own -f json | jq '.authors[] | {name, codePercent}'

# merge duplicate authors with same name
git-own --merge-by-name

Usage

Run from inside a repository (defaults to the current directory):

git-own
git-own /path/to/repo
git-own --branch main
git-own --branch v1.2.0

Output formats

git-own -f json       # machine-readable (totals + authors array)
git-own -f csv        # spreadsheet-friendly, one row per author
git-own -f markdown   # GitHub-rendered table
{
  "totals": {
    "authors": 71,
    "commits": 348,
    "additions": 9127,
    "deletions": 6761,
    "blameableLines": 1661,
    "files": 26,
    "excludedFiles": 6
  },
  "authors": [
    {
      "name": "Sindre Sorhus",
      "email": "[email protected]",
      "commits": 187,
      "additions": 4172,
      "deletions": 3984,
      "filesTouched": 59,
      "activeDays": 115,
      "firstCommit": "2013-08-03T02:16:26+02:00",
      "lastCommit": "2025-09-08T21:47:34+07:00",
      "blameLines": 706,
      "codePercent": 42.5045
    }
  ]
}
| Author | Email | Commits | +Lines | -Lines | Files | Days | First | Last | Code% |
| --- | --- | ---: | ---: | ---: | ---: | ---: | --- | --- | ---: |
| Sindre Sorhus | [email protected] | 187 | 4172 | 3984 | 59 | 115 | 2013-08-03 | 2025-09-08 | 42.50% |

_Total: 71 authors · 348 commits · +9127 / -6761 lines · 1661 blameable lines · 26 files_

Sort, limit, and filter

git-own -s commits --top 10    # top 10 by commit count
git-own -s additions           # most insertions across history
git-own -s name                # alphabetical
git-own --author "sindre"      # only matching authors (name or email)
git-own --author "gmail.com"   # filter by email domain
git-own --merge-by-name        # merge same-name/different-email duplicates

Sort keys: pct (default) · commits · additions · deletions · files · name

Time and revision filtering

git-own --since 2024-01-01                       # commits from 2024 onwards
git-own --since 2024-01-01 --until 2024-12-31    # 2024 only
git-own --from v1.0 --to v2.0                    # commits between two tags
git-own --until 2024-06-30                       # everything up to a date

How Code% works with filters:

When --since, --until, --from, or --to is used, Code% reflects only code written during the filtered period. Blame lines whose originating commit falls outside the range are not counted. So git-own --since 2025-01-01 shows each author's share of the code written in 2025, not their share of the entire codebase.

When --to or --until is used, the blame pass also runs at that point in time (the range tip), not at HEAD.

Authors with 0 commits in the filtered range are hidden by default. Use --no-hide-inactive to show them.

Piping

The spinner and diagnostics go to stderr; data goes to stdout — pipes just work:

git-own -f json | jq '.authors[] | {name, codePercent}'
git-own -f csv > contributors.csv
git-own -f markdown >> README.md

File exclusions

Generated files like lock files and build output can dwarf real source code and skew stats. git-own excludes them from both the blame and history passes using four sources, combined:

| Source | What it covers | How to disable | | --- | --- | --- | | Built-in defaults (on by default) | Lock files, build dirs (dist/, build/), minified code (*.min.js), source maps (*.map), vendored code (vendor/) | --no-default-excludes | | .git-own-ignore | A file at the repo root with .gitignore-style syntax (# comments, ! negation, trailing slash for dirs) | Remove the file | | --exclude <glob> | Repeatable CLI flag for ad-hoc exclusions (same gitignore semantics) | Don't pass it | | .gitattributes | Files marked linguist-generated or -diff (GitHub's method for detecting generated files) | --no-gitattributes |

# exclude everything under src/generated/
git-own --exclude 'src/generated/**'

# exclude all .sql files and a specific config
git-own -e '*.sql' -e 'config/secrets.json'

# turn off all automatic exclusions, analyze everything
git-own --no-default-excludes --no-gitattributes

# persist project-wide excludes
echo 'docs/'    > .git-own-ignore
echo '*.gen.ts' >> .git-own-ignore
git-own
# Lock files
pnpm-lock.yaml  package-lock.json  npm-shrinkwrap.json  yarn.lock
Cargo.lock  Gemfile.lock  composer.lock  poetry.lock  Pipfile.lock
go.sum  flake.lock

# Build / output directories
dist/  build/  out/  coverage/  .next/  .nuxt/  .turbo/  .svelte-kit/

# Minified code
*.min.js  *.min.css  *.min.mjs  *.min.cjs

# Source maps
*.map

# Vendored code
vendor/  third_party/  node_modules/

Patterns follow gitignore semantics: a pattern with no slash matches at any depth, a trailing slash means the whole directory, and a leading slash anchors to the repo root. Use -v to see how many files each source excluded.

Config file

A .git-own.json file at the repo root can set persistent defaults for any CLI flag — no need to retype them every run.

{
  "format": "table",
  "sort": "commits",
  "mergeByName": true,
  "excludes": ["docs/**", "*.gen.ts"],
  "concurrency": 4
}

Precedence: explicit CLI flag > config file > built-in default

Use --no-config to skip reading the file. Verbose mode (-v) shows which config file was loaded.

Merging duplicate authors

The same person may appear multiple times with different emails (e.g. a work email and a GitHub noreply email). Two methods to merge them:

| Method | Handles | How | | --- | --- | --- | | --merge-by-name | Same name, different email | Auto-merges authors with the same case-insensitive name | | .mailmap | All duplicate types (including different names) | Git's native author mapping file; respected automatically, no flag needed |

Both methods can be combined: --merge-by-name for the easy cases + .mailmap for the tricky ones. See gitmailmap(5) for .mailmap syntax.

How it works

git-own makes two passes over the repository:

┌──────────────────────────────────────────────────────────────────┐
│  History pass                                                    │
│  git log --no-merges -M -C --numstat --format=…                  │
│  → commits, +Lines, -Lines, files touched, active days, dates   │
├──────────────────────────────────────────────────────────────────┤
│  Blame pass                                                      │
│  git ls-tree → filter → git blame --line-porcelain (parallel)    │
│  → Code% (current ownership, filtered by in-range commits)       │
└──────────────────────────────────────────────────────────────────┘

Code% is blameLines / totalBlameLines * 100 — the share of lines attributed to each author. Without filtering, this is the share of the current codebase; with filtering, it's the share of code written during the filtered period.

+Lines / -Lines are historical totals (everything ever added/removed in the range), so refactors that delete and rewrite code will inflate those without changing Code%.

Author identity is grouped by lowercased email (name when email is empty). .mailmap is always respected: git blame applies it automatically and the log pass uses %aN/%aE, keeping the two passes consistent.

Options reference

git-own [path] [options]

Arguments:
  path                    path to the git repository to scan (default: cwd)

Options:
  -b, --branch <rev>      revision to scan (default: HEAD)
  -f, --format <fmt>      table | json | csv | markdown (default: table)
  -s, --sort <key>        pct | commits | additions | deletions | files | name
                          (default: pct)
  --top <n>               show only the top N authors
  --author <names>        show only matching authors (comma-separated)
  --since <date>          only count commits after this date
  --until <date>          only count commits before this date
  --from <rev>            start revision (exclusive) for rev-range analysis
  --to <rev>              end revision (inclusive) for rev-range analysis
  --merges                include merge commits (excluded by default)
  --no-whitespace         disable whitespace-insensitive blame
  --include-binary        also blame binary files (skipped by default)
  -e, --exclude <glob>    exclude files matching this glob (repeatable)
  --no-default-excludes   do not apply the built-in exclude patterns
  --no-gitattributes      do not respect .gitattributes generated-file markers
  --merge-by-name         merge authors with the same name (case-insensitive)
  --concurrency <n>       files to blame in parallel (default: min(8, CPUs))
  --no-hide-inactive      show authors with 0 commits in the filtered range
  --no-config             do not read .git-own.json config file
  -v, --verbose           show progress and diagnostics on stderr
  -V, --version           output the version number
  -h, --help              display help

Limitations

  • Submodules are not descended; only the top-level repository is scanned.
  • Binary files are skipped in the blame pass by default. Use --include-binary to attempt them anyway.
  • Shallow clones have incomplete history; a warning is printed on stderr.
  • Merge commits are excluded by default. Use --merges to include them.
  • --merge-by-name merges by exact (case-insensitive) name match only. Different-name variants of the same person require a .mailmap file.

License

MIT © Ahmed Semih Erkan