Hotspots
Files that are both large and changed often are where bugs tend to cluster and where refactoring pays off first. Each file in the current tree is placed by its size and by the number of commits that changed it; its hotspot score is changes × √lines. Files without counted lines, such as binary files, are left out.
- Files Analyzed
- 82
- of 88 in the current tree
- Top 10 Files
- 76.9%
- of the total hotspot score
- Median File Size
- 212 lines
- half of the files are at least this large
- Median Changes
- 5 commits
- half of the files changed at least this often
Change frequency by file size
Each dot is a file; a bigger dot is a higher score. The dashed lines mark the median file size and the median number of changes, so the large files that change often are in the top right. Both axes are logarithmic.
Top hotspots
The files ranked by hotspot score: the larger a file is and the more often it changes, the higher it ranks. Authors is how many people have changed the file, bots aside, as on the Code Ownership page: a hotspot only one person has changed is also a bus-factor risk.
| File | Lines | Changes | Authors | Score | Bar |
|---|---|---|---|---|---|
| gitstats/report_creator.py | 4,538 | 80 | 5 | 5,389.2 | |
| gitstats/main.py | 2,197 | 71 | 4 | 3,327.9 | |
| tests/test_report_creator.py | 4,202 | 45 | 2 | 2,917.0 | |
| tests/test_main.py | 3,609 | 43 | 2 | 2,583.2 | |
| gitstats/gitstats.css | 2,095 | 38 | 1 | 1,739.3 | |
| gitstats/aggregate.py | 2,211 | 25 | 2 | 1,175.5 | |
| tests/test_aggregate.py | 2,076 | 25 | 2 | 1,139.1 | |
| gitstats/utils.py | 1,140 | 33 | 2 | 1,114.2 | |
| README.rst | 435 | 52 | 2 | 1,084.5 | |
| uv.lock | 2,308 | 12 | 1 | 576.5 |
Table: all 82 files
| File | Lines | Changes | Authors | Score | Bar |
|---|---|---|---|---|---|
| gitstats/report_creator.py | 4,538 | 80 | 5 | 5,389.2 | |
| gitstats/main.py | 2,197 | 71 | 4 | 3,327.9 | |
| tests/test_report_creator.py | 4,202 | 45 | 2 | 2,917.0 | |
| tests/test_main.py | 3,609 | 43 | 2 | 2,583.2 | |
| gitstats/gitstats.css | 2,095 | 38 | 1 | 1,739.3 | |
| gitstats/aggregate.py | 2,211 | 25 | 2 | 1,175.5 | |
| tests/test_aggregate.py | 2,076 | 25 | 2 | 1,139.1 | |
| gitstats/utils.py | 1,140 | 33 | 2 | 1,114.2 | |
| README.rst | 435 | 52 | 2 | 1,084.5 | |
| uv.lock | 2,308 | 12 | 1 | 576.5 | |
| tests/test_utils.py | 1,683 | 14 | 1 | 574.3 | |
| gitstats/__init__.py | 343 | 25 | 4 | 463.0 | |
| .github/workflows/test.yml | 119 | 33 | 4 | 360.0 | |
| .github/workflows/gallery.yml | 212 | 21 | 2 | 305.8 | |
| pyproject.toml | 100 | 27 | 2 | 270.0 | |
| tests/test_generate_gallery_portfolio.py | 545 | 11 | 2 | 256.8 | |
| tests/test_init.py | 446 | 11 | 2 | 232.3 | |
| scripts/generate_gallery_portfolio.py | 405 | 11 | 2 | 221.4 | |
| gitstats/badge.py | 618 | 8 | 2 | 198.9 | |
| tests/conftest.py | 471 | 9 | 1 | 195.3 | |
| scripts/gallery_ecosystems.py | 644 | 7 | 1 | 177.6 | |
| docs/source/configuration.rst | 102 | 16 | 2 | 161.6 | |
| tests/test_badge.py | 423 | 7 | 2 | 144.0 | |
| docs/source/gallery.rst | 261 | 8 | 1 | 129.2 | |
| gitstats/ai_summarizer.py | 624 | 5 | 1 | 124.9 | |
| tests/test_gallery_ecosystems.py | 395 | 6 | 1 | 119.2 | |
| tests/test_ai_summarizer.py | 867 | 4 | 2 | 117.8 | |
| docs/source/getting-started.rst | 188 | 8 | 1 | 109.7 | |
| docs/source/integration.rst | 227 | 7 | 2 | 105.5 | |
| noxfile.py | 64 | 12 | 2 | 96.0 | |
| gitstats.conf | 83 | 10 | 2 | 91.1 | |
| .github/workflows/pages.yml | 56 | 12 | 3 | 89.8 | |
| .github/workflows/publish-pypi.yml | 52 | 12 | 2 | 86.5 | |
| .gitignore | 22 | 18 | 1 | 84.4 | |
| gitstats/employers.py | 434 | 4 | 1 | 83.3 | |
| gitstats/compare.py | 433 | 4 | 1 | 83.2 | |
| .pre-commit-config.yaml | 38 | 13 | 2 | 80.1 | |
| tests/test_compare.py | 380 | 4 | 1 | 78.0 | |
| gitstats/sortable.js | 355 | 4 | 1 | 75.4 | |
| .github/copilot-instructions.md | 203 | 5 | 2 | 71.2 | |
| tests/test_wrapped.py | 497 | 3 | 1 | 66.9 | |
| tests/test_ai_providers.py | 475 | 3 | 1 | 65.4 | |
| gitstats/insights.py | 460 | 3 | 1 | 64.3 | |
| gitstats/ai_providers.py | 380 | 3 | 1 | 58.5 | |
| tests/test_assistants.py | 376 | 3 | 1 | 58.2 | |
| docs/source/ai-integration.rst | 358 | 3 | 1 | 56.8 | |
| tests/test_insights.py | 351 | 3 | 1 | 56.2 | |
| tests/test_gallery_repos.py | 195 | 4 | 1 | 55.9 | |
| tests/test_employers.py | 295 | 3 | 1 | 51.5 | |
| gitstats/wrapped.py | 496 | 2 | 1 | 44.5 | |
| docs/source/index.rst | 30 | 8 | 1 | 43.8 | |
| gitstats/assistants.py | 202 | 3 | 1 | 42.6 | |
| scripts/gallery_repos.py | 187 | 3 | 1 | 41.0 | |
| .readthedocs.yaml | 26 | 8 | 1 | 40.8 | |
| docs/source/faq.rst | 37 | 5 | 2 | 30.4 | |
| .github/workflows/pre-commit.yml | 11 | 9 | 1 | 29.8 | |
| .github/workflows/release-drafter.yml | 22 | 6 | 2 | 28.1 | |
| LICENSE-GPLv3 | 674 | 1 | 1 | 26.0 | |
| gallery/repos.yml | 168 | 2 | 1 | 25.9 | |
| gitstats/sources.py | 53 | 3 | 1 | 21.8 | |
| .github/workflows/docs-preview.yml | 23 | 4 | 1 | 19.2 | |
| docs/source/contributors.rst | 14 | 5 | 1 | 18.7 | |
| LICENSE-GPLv2 | 339 | 1 | 1 | 18.4 | |
| docs/source/demo.tape | 33 | 3 | 2 | 17.2 | |
| tests/test_page_scripts.py | 270 | 1 | 1 | 16.4 | |
| .github/dependabot.yml | 25 | 3 | 1 | 15.0 | |
| gitstats/THIRD_PARTY_NOTICES.md | 25 | 3 | 1 | 15.0 | |
| docs/source/conf.py | 19 | 3 | 1 | 13.1 | |
| tests/test_ai_sdk_contract.py | 148 | 1 | 1 | 12.2 | |
| tests/test_sources.py | 33 | 2 | 1 | 11.5 | |
| docs/source/copyright.rst | 11 | 3 | 1 | 9.9 | |
| docs/source/license.rst | 20 | 2 | 1 | 8.9 | |
| gitstats/safe_html.py | 70 | 1 | 1 | 8.4 | |
| .github/ISSUE_TEMPLATE/gallery.yml | 58 | 1 | 1 | 7.6 | |
| tests/test_safe_html.py | 42 | 1 | 1 | 6.5 | |
| AGENTS.md | 41 | 1 | 1 | 6.4 | |
| gitstats/chart.umd.min.js | 20 | 1 | 1 | 4.5 | |
| .github/workflows/stale.yml | 10 | 1 | 1 | 3.2 | |
| .mailmap | 2 | 2 | 1 | 2.8 | |
| docs/source/changelog.rst | 4 | 1 | 1 | 2.0 | |
| .codespellrc | 3 | 1 | 1 | 1.7 | |
| MANIFEST.in | 3 | 1 | 1 | 1.7 |