DiffStory
Transform Git diffs into rich, interactive, self-contained HTML reports.
Understand not just what changed, but who changed it, when, and why — all offline, in a single portable file.
Current version: 1.1.10
pip install diffstory
cd my-repo
diffstory --staged
# Opens a .html in your browser
Screenshots
Why DiffStory?
Reading a diff in your terminal works — until it doesn't.
| Tool | Limitation |
|---|---|
git diff |
Plain text, no navigation, no blame context, no sharing. |
git blame |
Standalone per-file, disconnected from the diff. Requires the repository. |
diff2html |
HTML output but no blame, no offline sharing, no analytics, no search. |
| PR reviews | Tied to GitHub/GitLab. No offline access. Cannot be archived or emailed. |
DiffStory combines git diff, git blame, and git log into a single interactive HTML report — no server, no accounts, no data leaving your machine.
Features
| Feature | Description |
|---|---|
| Unified View | Classic git-style diff with line numbers and syntax highlighting. |
| Side-by-Side View | Original (left) and modified (right) columns, visually aligned. |
| Inline View | Word-level diff — green additions and red strikethrough removals on one line. |
| Blame Integration | Hover any line for author, commit, subject, and relative time. Click for full commit details. |
| Provenance Metadata | Author, date, commit message, files changed, insertions, deletions — per commit. |
| Search | Global search across file names, authors, commit subjects, and code content. |
| Filters | Narrow by file extension (.py, .js, .html) or change type (added, deleted, modified, renamed). |
| Statistics | Floating dashboard with file counts, add/delete deltas, author breakdown, and top changed files. |
| Dark Mode | Instant toggle, persists across sessions. |
| Offline Reports | All CSS, JS, and data embedded. Works in any modern browser with zero network access. |
| Single HTML Output | One file — no assets, no server, no dependencies. |
| Portable Sharing | Email, archive, attach to a PR, or file for compliance. No repository access needed to view. |
Additional Capabilities
- Keyboard navigation —
J/Kto move between files,For/to search,U/S/Ito switch views - Deep linking —
#file-0or#L-0-42links to specific files and lines - Binary file detection — Image previews and metadata placeholders
- Export formats — JSON, Markdown, and CSV alongside HTML (
--json,--md,--csv) - Review mode — Per-file checkboxes with localStorage persistence (
--review) - Config file —
~/.diffstory.tomlor.diffstory.tomlfor persistent defaults - Accordion sidebar — Click a file in the sidebar to focus it (expand clicked, collapse others); use Collapse All / Expand All to toggle globally
- Auto-update — Checks PyPI on startup and self-upgrades to the latest version transparently, so automation scripts always run the newest code. Disable with
DIFFSTORY_DISABLE_AUTO_UPDATE=1
Installation
pip install diffstory
Requires: Python 3.10+ and Git.
From source:
git clone https://github.com/lakshayjindal/diffstory.git
cd diffstory
pip install -e .
Quick Start
# Working tree diff
diffstory
# Staged changes
diffstory --staged
# Commit comparison
diffstory HEAD~1 HEAD
# Branch comparison with path restriction
diffstory main feature/auth src/
# Custom output
diffstory -o report.html
# Generate from a diff file (no git repo needed)
diffstory --diff /path/to/patch.diff
# Multiple export formats
diffstory --staged --json --md --csv
What Makes DiffStory Different?
| Feature | git diff |
diff2html |
DiffStory |
|---|---|---|---|
| HTML report | — | ✓ | ✓ |
| Offline sharing | — | — | ✓ |
| Blame / provenance | — | — | ✓ |
| Line-level author info | — | — | ✓ |
| Interactive navigation | — | ✓ | ✓ |
| Search across files | — | — | ✓ |
| Filter by type / extension | — | — | ✓ |
| Statistics dashboard | — | — | ✓ |
| Dark mode | — | — | ✓ |
| Keyboard shortcuts | — | — | ✓ |
| Deep linking | — | — | ✓ |
| Risk analysis & hotspots | — | — | ✓ |
| Single-file output | — | ✓ | ✓ |
| No runtime dependencies | ✓ | — | ✓ |
Screenshots and Walkthrough
Overview
The main report screen. A sidebar lists all changed files with add/delete counts. The diff content area renders each file with its full change history. The toolbar gives access to view switching, search, theme, statistics, and the file list.
Why it matters: You get the full context of a changeset in one view — no scrolling between terminal windows or switching between git diff and git blame.
Unified View
The default view. Lines are color-coded: green for additions, red for deletions. Line numbers for both old and new files are displayed side by side. Syntax highlighting is applied via Pygments.
Why it matters: Familiar to anyone who uses git diff, but with syntax highlighting and interactive features that the terminal cannot provide.
Side-by-Side View
Original file on the left, modified file on the right. Lines are aligned by position. Useful for understanding structural changes at a glance.
Why it matters: For large refactors or renames, seeing both versions side by side reveals patterns that a unified diff obscures.
Inline View
Word-level diffs. Instead of showing a removed line and an added line, changed words are highlighted inline — removed text is struck through in red, added text is highlighted in green.
Why it matters: When a single word changes on a long line, finding the difference in a unified diff requires careful scanning. The inline view makes it obvious instantly.
Blame Tooltip
Hover any changed line to see a tooltip with the author name, commit hash, commit subject, date, and relative time. Click the line to open a full commit detail drawer.
Why it matters: Answers "who wrote this line and why?" without leaving the report. No more switching to a terminal to run git blame.
Statistics Dashboard
A floating panel with file counts, add/delete deltas, author and commit counts, contributor breakdown, and a table of the most-changed files.
Why it matters: Gives an instant high-level summary of the changeset — useful for code reviews, release notes, and stakeholder updates.
Typical Use Cases
| Use Case | Description |
|---|---|
| Code Reviews | Generate a report from a branch diff and share the link or file. Reviewers get interactive blame, search, and filtering — no GitHub/GitLab account required. |
| Release Reviews | Before shipping, run diffstory v1.0..v2.0 to get a complete picture of everything that changed between releases. |
| QA Verification | QA engineers can search for specific files, filter by change type, and inspect blame without CLI access. |
| Client Deliverables | Share a self-contained HTML report with clients or stakeholders. They see exactly what changed without needing access to your repository. |
| Audit Trails | Archive reports for compliance. Every report is a timestamped, self-contained document with full provenance. |
| Code Archaeology | Trace who changed what and when in a specific file or function across commits. |
| Historical Investigations | Run diffstory on any range of commits to reconstruct the evolution of a feature or bug fix. |
Architecture
diffstory/ # PyPI package
├── cli.py # Argument parsing, orchestration
├── git_utils.py # Git subprocess wrappers (diff, blame, log)
├── diff_parser.py # Unified diff → structured data
├── syntax.py # Pygments syntax highlighting
├── html_generator.py # Self-contained HTML generation
├── updater.py # Auto-update check against PyPI
├── loader.py # Spinner / progress utilities
└── generators/
├── get_css.py # All CSS (inline)
└── get_js.py # All JavaScript (inline)
- Python 3.10+ — Only two runtime dependencies: Pygments (syntax highlighting) and
build/twine(packaging). - Git CLI — All Git operations go through
subprocess. No GitPython dependency. - Self-contained HTML — CSS, JavaScript, and data (blame, commits, search index) are embedded directly. No assets to serve, no network requests.
- Offline-first — Everything runs locally. Generated reports work without internet access, indefinitely.
- Auto-updating — On startup, diffstory checks PyPI for a newer version and upgrades itself automatically before running your command. No manual
pip install --upgradeneeded.
Philosophy
DiffStory is not trying to replace GitHub, GitLab, Bitbucket, or Git itself.
It exists to solve a specific problem: creating portable, shareable, interactive change reports that work anywhere, independent of infrastructure.
- Reports are static files. Open them in any browser. Email them. Archive them. Attach them to tickets.
- No accounts. No servers. No data leaves your machine.
- The report answers the five questions reviewers actually ask: What changed? Who changed it? When? Why? How did it evolve?
Roadmap
Ideas for future releases — nothing guaranteed:
- Annotations & comments — Inline commenting on specific lines, saved to the report
- PDF export — Print-quality report generation
- Diff comparison — Compare two reports side by side
- Plugin system — Custom analyzers and visualizations
- WebSocket live reload — Watch file changes and regenerate reports automatically
- Language-specific analysis — TypeScript type changes, Rust borrow checker impact, etc.
- Team review workflows — Aggregate reviews from multiple team members
Contributing
Contributions are welcome. The project is small and the codebase is straightforward.
- Issues — Bug reports, feature requests, and questions.
- Pull requests — Please open an issue first to discuss the change.
- Local development —
pip install -e .for editable install. Rundiffstory --stagedin any repo to test.
git clone https://github.com/lakshayjindal/diffstory.git
cd diffstory
pip install -e .
diffstory --staged -o /tmp/test.html
License
MIT
Release files for diffstory 1.1.10
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| diffstory-1.1.10.tar.gz | 52.5 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| diffstory-1.1.10-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 103.3 kB
Release files / diffstory-1.1.10.tar.gz
| Download URL | diffstory-1.1.10.tar.gz |
|---|---|
| Size | 52.5 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
6c179b7fe5c5f0c32cc1c8cfdf86523a0fd7d7b4e1f0e36ca924cda3a0a5bd57
|
|
BLAKE2b-256 checksum How to use checksums |
58ee285575e0661a1f7a6bcc486a3c1a94767acd4db61cd68fc5e41d067aff23
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.11.15
|
Release files / diffstory-1.1.10-py3-none-any.whl
| Download URL | diffstory-1.1.10-py3-none-any.whl |
|---|---|
| Size | 50.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
e6e49fb0c281a0fbb1932fa4dfbe4887b78b72d5817f97568f8cc10ba0d82698
|
|
BLAKE2b-256 checksum How to use checksums |
7f29be021e5339a512a3705339aec97326055346a93baa4e36154c6efa40f3c9
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.11.15
|