Skip to main content

oh-my-gitstats

中文 | English

Collect commit data from multiple git repositories and visualize it as a single interactive HTML report.

Line Chart Heatmap

Features

  • Batch Collection — Recursively scan a directory for all git repositories
  • Incremental Sync — Only fetch new commits since the last collection
  • Automated Workflowgitstats auto runs collect → sync → visualize and opens the browser
  • Line Charts — Switch metric (lines changed / commit count) and granularity (day / week / month); editable date range bar (two date inputs + 30D / 90D / 6M / 1Y / ALL presets), with the legend filtered to the selected range
  • Calendar Heatmaps — View commit activity filtered by year
  • Aggregate and Per-Repo Views — A 2-column grid showing combined or per-repo statistics
  • Repo Detail Modal — Click any repo card to open its line chart, heatmap, and meta info (commits / lines / first / last / local / remote / action)
  • Local / Remote Indicators — Each sync status is rendered as two independent signal lamps for working-tree state and remote-tracking state
  • VS Code Integration — Open repo folders directly from the HTML report

Installation

pip install oh-my-gitstats

Or install from source:

git clone https://github.com/amomorning/oh-my-gitstats.git
cd oh-my-gitstats
pip install -e .

Quick Start

First time, collect from each project directory (paths are recorded to the config automatically):

cd ~/projects && gitstats collect .
cd ~/work && gitstats collect .

After that, a single command runs collect → sync → visualize and opens the browser:

gitstats auto

You can also edit the config file manually to add directories:

# Auto-created at:
~/.gitstats/settings.json
{
  "collect_paths": [
    "/home/user/projects",
    "/home/user/work"
  ]
}

Options:

Option Description
-v, --verbose Show detailed output for each step (default: spinner only)
--check Check GitHub archive status (requires network; set GITHUB_TOKEN for private repos)
--no-open Do not open the HTML file in the browser after generation

Commands

collect — Collect commit data

Scan a directory for git repositories and export them to JSON:

gitstats collect /path/to/repos
Option Description
-o, --output Directory to save JSON files (default: ~/.gitstats/data)
-q, --quiet Suppress output messages
--skip Skip repos that already have a JSON file
--check Check GitHub archive status

sync — Incremental sync

Update existing JSON files with only new commits — faster than re-collecting:

gitstats sync
Option Description
-q, --quiet Suppress output messages
--check Check GitHub archive status

Typical workflow with multiple directories:

# One-time: collect from different locations
gitstats collect /path/to/work-projects
gitstats collect /path/to/personal-projects --skip

# Later: update all at once
gitstats sync

visualize — Generate visualization

Create an interactive HTML file from the collected data:

gitstats visualize
Option Description
-o, --output HTML file path (default: ~/.gitstats/stats.html)

Granularity and metric can be switched dynamically in the generated HTML — no need to regenerate.

archive — Mark repositories (interactive)

Opens an interactive multi-select list of all known repositories. Use arrow keys to navigate, space to toggle, and enter to confirm. Repositories that are currently archived (either via a previous archive run or via --check from the GitHub API) are pre-checked.

gitstats archive
gitstats archive -o ./data   # use a non-default data directory
Option Description
-o, --data-dir Directory containing JSON files (default: ~/.gitstats/data)

On submit, only repositories whose effective archived state actually changes are rewritten. You will be prompted to refresh the HTML.

Requires an interactive terminal. In CI / non-TTY environments the command exits with an error.

Configuration

Config file at ~/.gitstats/settings.json (auto-created on first run):

{
  "data_dir": "~/.gitstats/data",
  "output_html": "~/.gitstats/stats.html",
  "collect_paths": []
}
Field Description
data_dir Where JSON files are stored
output_html Where the HTML visualization is generated
collect_paths Directories gitstats auto scans (auto-populated when you run collect)

GitHub Token (Optional)

--check queries the GitHub API to check archive status. Without authentication, only public repositories can be checked (rate limit: 60 requests/hour).

If GITHUB_TOKEN is not set, a warning is printed when using --check.

To check private repositories, set the GITHUB_TOKEN environment variable:

Linux / macOS

export GITHUB_TOKEN=ghp_your_token_here
gitstats sync --check

Windows (PowerShell)

Set for the current session:

$env:GITHUB_TOKEN="ghp_your_token_here"
gitstats sync --check

Set permanently: SettingsSystemAboutAdvanced system settingsEnvironment Variables → User variables → New

Getting a token

  1. Go to GitHubSettingsDeveloper settingsPersonal access tokensTokens (classic)
  2. Click Generate new token (classic)
  3. Give it a name (e.g. oh-my-gitstats)
  4. Under Select scopes, no additional scopes are needed for public repos
  5. To access private repositories, check the repo scope
  6. Click Generate token and copy the value (starts with ghp_)

Use Tokens (classic), not Fine-grained tokens. With a token, the rate limit increases to 5,000 requests/hour.

Output

The generated HTML contains:

  1. Line Chart (01 / Trend) — Metric selector (lines changed / commit count) + granularity selector (day / week / month) + editable date range bar with two <input type="date"> (or <input type="month"> when granularity is month) and preset buttons (30D / 90D / 6M / 1Y / ALL). The range drives and is driven by the ECharts dataZoom; the legend is filtered to show only repositories with commits inside the selected range.

  2. Aggregate Heatmap (02 / Aggregate) — Combined activity across all repos with a year selector (all years / specific year); height auto-adjusts when switching between single-year and multi-year ranges.

  3. Individual Heatmaps (03 / Repositories) — A 2-column grid of per-repo cards. Each card shows the repo name, monospace path, Local + Remote signal lamps (small colored circles labeled L / R, in green / yellow / red / gray), and a Continue / Archived button with an MDI icon (vscode://file/ URI). A Show Archived toggle in the section header controls whether archived cards are visible (hidden by default). Click any card to open the detail modal with a per-repo line chart (default granularity day), heatmap, and a 7-cell meta grid (commits / lines / first / last / local / remote / action). Closeable via the × button, a backdrop click, or the Escape key.

Individual Heatmaps

JSON Format

Each repository generates a JSON file (~/.gitstats/data/{repo_name}.json):

{
  "repo_name": "my-project",
  "repo_path": "/absolute/path/to/my-project",
  "last_commit_hash": "a1b2c3d4...",
  "sync_status": "synced",
  "is_archived": false,
  "commits": [
    {
      "timestamp": "2024-01-15T10:30:00",
      "additions": 45,
      "deletions": 12
    }
  ]
}

last_commit_hash — HEAD hash at collection time. During sync, repos with a matching hash are skipped.

sync_status — Sync state, decomposed at render time into two independent Local + Remote signal lamps (the stored JSON value is a single enum):

sync_status Local Remote
synced 🟢 Clean 🟢 Synced
local_changes 🟡 Dirty 🟢 Synced
remote_ahead 🟢 Clean 🟡 Ahead
diverged 🟡 Dirty 🟡 Ahead
local_only_clean 🟢 Clean ⚪ None
local_only_dirty 🟡 Dirty ⚪ None
network_error_clean 🟢 Clean 🔴 Error
network_error_dirty 🟡 Dirty 🔴 Error

is_archived — Whether the repo is archived on GitHub (set by --check). Values: true, false, or null (not checked or check failed).

manual_archived — Manual override set by gitstats archive. Values: true, false, or null. When present, it takes priority over is_archived. The rendered HTML shows the effective value (manual wins).

Requirements

  • Python 3.9+
  • click, gitpython, pyecharts, jinja2, requests, questionary

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

oh_my_gitstats-0.4.0.tar.gz (40.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

oh_my_gitstats-0.4.0-py3-none-any.whl (36.1 kB view details)

Uploaded Python 3

File details

Details for the file oh_my_gitstats-0.4.0.tar.gz.

File metadata

  • Download URL: oh_my_gitstats-0.4.0.tar.gz
  • Upload date:
  • Size: 40.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.9

File hashes

Hashes for oh_my_gitstats-0.4.0.tar.gz
Algorithm Hash digest
SHA256 ef8f98a84b5b8c7d5e1f2b06d8b61f16748f135b676797eac8080f7a4f86c938
MD5 a73c125b54d001bdc670cf5d2ab02057
BLAKE2b-256 554d52064a020a1fafc1e6c61aaec7ba88b637e7482d8c3b1257d3d7c3a40b30

See more details on using hashes here.

File details

Details for the file oh_my_gitstats-0.4.0-py3-none-any.whl.

File metadata

  • Download URL: oh_my_gitstats-0.4.0-py3-none-any.whl
  • Upload date:
  • Size: 36.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.9

File hashes

Hashes for oh_my_gitstats-0.4.0-py3-none-any.whl
Algorithm Hash digest
SHA256 4b48ec17ac4a473138c597e6bb2d617c5e5ec992e75e94ede7fc0ee6d961414c
MD5 10f55f166aea2a5fa0cc24ee5a564a67
BLAKE2b-256 f72630ebec31715e5430081eb79735efb1c4e456c22073ddc48a15accf82c214

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page