contributor-graphs

Who built it,
and when.

Point it at any repository and get a contributor timeline: a publication-ready SVG for your paper or README, and a self-contained interactive HTML page for digging in. Time across the top, contributors down the side, every bar shaded by how busy that month was.

$cargo install contributor-graphs

one binary, no runtime uses your gh token path · owner/repo · git URL

Open the interactive version
nf-core/rnaseq · live Open interactive

Features

What it gives you.

One command reads the git history, merges scattered identities, enriches them from GitHub, and draws the result two ways. No server, no build step, no runtime.

Two files per run

A vector .svg you can cite, and an interactive .html page from the same data.

Activity timeline

Months across the top, contributors down the side, each cell shaded by that month's commit count.

Identity merging

Folds one person's many names and email addresses back into a single contributor.

GitHub enrichment

Resolves usernames, avatars and company from GitHub in parallel, even from old or noreply emails.

Affiliation grouping

Colour rows by organisation, or collapse to one row per company with --by-affiliation.

Interactive page

Search, sort, set a commit threshold, brush-zoom a date range, read details on hover, export a PNG. On mobile the controls tuck into a menu while the timeline stays pinned.

Many repos, one timeline

Point it at one repo, a handful, or every repo in an org, even across several orgs. They pool into a single chart, with commits shared by overlapping histories deduplicated by SHA.

One binary

Rust with no runtime to install, and it finds your gh token automatically. The HTML it writes inlines its avatars, so it opens offline or on gh-pages.

Shareable views

Filters live in the URL, so a zoomed-in, filtered chart is a link you can send.

Install

Get the binary.

Grab a prebuilt binary, install with Cargo, or run it through Docker. The GitHub CLI is optional but worth having: it's how the tool finds a token for username and avatar lookups without hitting the anonymous rate limit.

In CI, the GITHUB_TOKEN that Actions injects is picked up automatically, with nothing else to configure.

Prebuilt binary

Download the archive for your platform from the releases page, unpack it, and put contributor-graphs on your PATH. No toolchain required.

Cargo

# latest from GitHub
cargo install --git https://github.com/ewels/contributor-graphs

# once published to crates.io
cargo install contributor-graphs

Docker

# writes into the mounted dir; passes your token through
docker run --rm -v "$PWD:/work" -e GITHUB_TOKEN \
  ghcr.io/ewels/contributor-graphs nf-core/rnaseq

Usage

Point it at a repo.

Each argument is a local path, a GitHub owner/repo slug, a git URL, or a bare owner (org or user) that expands to all of its repos.

Everything is cached under ~/.cache/contributor-graphs: the clones, the parsed history, and the GitHub lookups. On a re-run a quick git ls-remote checks each repo's tip, so anything unchanged skips the fetch, the log parse, and the API calls entirely. A whole org that took minutes the first time redraws in seconds. Pass --refresh to pull everything fresh.

$ contributor-graphs nf-core/rnaseq Clone the history, enrich from GitHub, write nf-core-rnaseq.svg and .html.
$ contributor-graphs nf-core seqeralabs Pool every non-fork repo across both orgs into one timeline, with shared commits deduplicated by SHA.
$ contributor-graphs . --open Use the current checkout and open the interactive page when it's done.
$ contributor-graphs MultiQC/MultiQC --min-commits 10 --sort commits Trim the long tail of one-off contributors and order by who committed most.
$ contributor-graphs nf-core/rnaseq --by-affiliation Collapse the chart to one row per organisation instead of per person.

Common flags

Flag What it does
-o, --output-dir Where to write the two files. Defaults to the cwd.
--min-commits Hide contributors below this many commits.
--max-contributors Cap the static chart to the top N (default 40).
--by-affiliation One row per organisation instead of per person.
--sort first · last · commits · duration · name
--include-bots Keep bot accounts, dropped by default.
--no-co-authors Don't credit Co-authored-by trailers (counted by default; also a live toggle in the page).
--config YAML curation file: identities, group aliases, and time-bounded affiliations.
--affiliations CSV/TSV affiliations: one row per period, columns username, full name, affiliation, start, end.
--since / --until Restrict to a window of commit history.
--no-github Skip all network calls; render from git alone.
--refresh Ignore the cache and pull history and GitHub data fresh.

Run --help for the full list.

Affiliations

Group people by where they work.

The tool reads each contributor's company from their GitHub profile and uses it to colour the chart by organisation. Spelling variants get folded together, so seqeralabs, Seqera Labs and Seqera all become one group, and the most common organisations get distinct colours while the long tail shares a neutral grey.

When the organisations are the story rather than the individuals, --by-affiliation merges everyone from each one into a single bar (in the interactive page it's a live toggle, so try it on the whole-org example).

For manual control, pass a YAML curation file with --config. It carries three optional sections: identities (merge a person's names, emails, and logins), aliases (group-name variants that mean the same org), and affiliations (who was where, and when). Anything you write here is authoritative and is never folded away by the auto-detection.

# curation.yml
identities:
  - [Phil Ewels, ewels]

aliases:
  Seqera: [Seqera Labs, seqeralabs]

affiliations:
  ewels:
    - { group: SciLifeLab, until: "2022-05" }
    - { group: Seqera, since: "2022-05" }

$ contributor-graphs nf-core/rnaseq --config curation.yml

Repeat the periods under a matcher to give one person several affiliations over time (dates are YYYY, YYYY-MM, or YYYY-MM-DD; until is exclusive, overlaps resolve to the later since). Their row is then drawn as one bar per period, coloured by the organisation active at the time, and the by-affiliation view splits their commits across those orgs by date.

Prefer a spreadsheet? Pass a CSV or TSV file with --affiliations instead (the delimiter is auto-detected), with columns username, full name, affiliation, start, end, and a row per period. The full name is optional, but when set it wins over the auto-detected name. Use it on its own or alongside --config (aliases stay in the YAML).

# affiliations.csv
username,full name,affiliation,start,end
ewels,Phil Ewels,SciLifeLab,2014,2022-05
ewels,Phil Ewels,Seqera,2022-05
maxulysse,,Seqera,2022-11,2025-12

$ contributor-graphs nf-core/rnaseq --affiliations affiliations.csv

How it works

What happens on each run.

  1. Read the history. git log gives every commit's author, email and timestamp, honouring .mailmap.
  2. Merge identities. Commits are clustered by shared email, then by shared name: one person under five addresses, folded back together.
  3. Ask GitHub. Each identity is resolved to a username, avatar and profile in parallel, so a noreply email still finds the right account.
  4. Bin and draw. Commits are counted per month per person, then rendered to a self-contained SVG and an interactive HTML page.
Copied