Skip to content

peetzweg/commit-history

Repository files navigation

Commit History — a star-history for GitHub commits

Commit History

A star-history, but for commits.
Watch any GitHub user's commits stack up across their whole lifetime — as one satisfying, rising chart.

🌍 commit-history.com


Type a username, get their entire coding career as a curve. It's a little hypnotic, it's a great flex, and it drops straight into your README.

👉 commit-history.com/torvalds · /gaearon · /sindresorhus

✨ What you get

  • 📈 Lifetime commit curve — every public commit since the account was born, accumulated month by month. The same data as the green contribution graph, not the noisy issues/PRs calendar.
  • ⚔️ Compare anyone — throw in comma-separated names (/torvalds,gaearon,antfu) and race their trajectories on one chart. Flip to Aligned mode to line everyone up at "month zero" regardless of when they joined.
  • 🏆 Leaderboard — an all-time ranking of everyone who's been looked up, sortable by public commits, private contributions, total activity, or followers.
  • 🔒 Public & private — for users who expose private contributions, see the hidden half of their activity too (kept separate, never silently summed).
  • 🖼️ Embed it anywhere — a live SVG chart for your own README (see below).
  • ✏️ Hand-drawn charm — an xkcd-style sketch aesthetic, a deliberate homage to the original.

🖼️ Embed in your GitHub profile

Drop a live, auto-updating chart into your profile page or any markdown file. This snippet centers the chart, follows the viewer's GitHub theme (light/dark), and links back to your full history:

<div align="center">
  <a href="https://commit-history.com/YOUR_USERNAME">
    <picture>
      <source media="(prefers-color-scheme: dark)" srcset="https://commit-history.com/embed/YOUR_USERNAME?theme=dark" />
      <img alt="YOUR_USERNAME's commit history" src="https://commit-history.com/embed/YOUR_USERNAME" />
    </picture>
  </a>
</div>

Here's Linus Torvalds:

🚀 Quick start

pnpm install
cp .env.example .env   # add your token (and optionally a database URL)
pnpm dev               # → http://localhost:3000
# .env
GITHUB_TOKEN=<classic PAT with the read:user scope>   # required
DATABASE_URL=<neon postgres url>                       # optional — see caching below

A classic Personal Access Token with read:user is enough for the public commits of any user.

🧠 How it works

  • Data comes from GitHub's GraphQL API (user.contributionsCollection.totalCommitContributions). A window spans at most a year, so a lifetime is sliced into monthly windows and fetched in batched, parallel queries (src/lib/github.ts) — one big query per month trips GitHub's resource limits on older accounts.
  • All fetching happens in server functions (src/lib/commit-history.ts), so the token never reaches the browser.
  • The chart is hand-rolled inline SVG (src/components/CommitChart.tsx) — no chart library — which is what makes the xkcd filter and the standalone embed (src/lib/chart-svg.ts) possible.
  • Caching (src/lib/cache.ts) is incremental: past months are immutable, so a returning user only re-fetches the trailing month. With DATABASE_URL set it persists to Neon Postgres (via Drizzle) and powers the leaderboard + recent lookups; without it, it falls back to an in-memory cache so the app still runs.

🛡️ Moderation

Some accounts game the board (botted commits, bought followers). To hide one until you've investigated, suspend it — a soft, reversible flag (entities.suspended_at). Suspended accounts drop off the leaderboard and "recently looked up" but stay directly viewable with an under-review notice. Run with bun (it auto-loads your local .env):

bun run suspend <login> "botted commits"   # suspend (asks to confirm)
bun run suspend --remove <login>           # reactivate
bun run suspend --list                     # list suspended accounts

🔄 Refreshing profiles

Profile metadata (followers, repos, bio, …) is fetched on lookup and cached. To re-pull it from GitHub manually — e.g. someone's follower count is stale — refresh it. Needs GITHUB_TOKEN and DATABASE_URL in .env; run with bun (it auto-loads your local .env):

bun run refresh <login>   # refresh one account
bun run refresh           # refresh only un-backfilled rows (followers is null)
bun run refresh --all     # refresh every user

☁️ Deploy (self-hosted)

The build emits a standalone Node server via nitropnpm build && pnpm start serves the whole app on port 3000. The multi-stage Dockerfile packages exactly that, so any Docker host works; production runs on Coolify (build pack: Dockerfile, port 3000) behind Cloudflare, which edge-caches /embed/* — the embeds already send s-maxage for any CDN.

Setting Value
Build docker build . (or pnpm build for bare Node)
Run container CMD / pnpm start → listens on :3000 (PORT overridable)
Environment variables GITHUB_TOKEN (required), DATABASE_URL (for the persistent cache + leaderboard)

🛠️ Tech

TanStack Start + React 19 · TanStack Query · Tailwind v4 · Drizzle + Neon Postgres · Biome.


A loving homage to star-history.com.

About

Resources

Stars

77 stars

Watchers

0 watching

Forks

Contributors