# gitea-heatmap-backfill Retroactively populate the Gitea activity heatmap from existing Git history. When you migrate repositories into Gitea, past commits do not appear in the contribution heatmap because no `action` records exist for them. This script reads the commit history directly from the bare repositories on disk and inserts the missing records into the Gitea SQLite database. --- ## Tested on | Component | Version | |---|---| | Gitea | **1.26.2** | | Database | SQLite 3 | Other Gitea versions using SQLite may work but have not been tested. PostgreSQL and MySQL backends are not supported. --- ## How it works 1. Discovers all bare repositories under the Gitea repository root 2. Runs `git log --all` on each one to extract commit SHAs, author emails and dates 3. Resolves each email against the `email_address` table, primary address **and** all registered alternative addresses are matched 4. Inserts one `action` row per commit (op\_type = 5, PUSH\_EVENT) into the Gitea SQLite database 5. Deduplicates via a SHA-256 content hash so the script is safe to run multiple times --- ## Requirements - Python 3.7+ - `git` available on the machine running the script - Read/write access to the Gitea SQLite database file - Gitea using SQLite as its database backend --- ## Setup ### 1. Clone the repository ```bash git clone https://github.com/Maethik/gitea-heatmap-backfill.git cd gitea-heatmap-backfill ``` No external dependencies, only the Python standard library is used. ### 2. Register all your commit emails in Gitea The script matches commits by email. Open **Settings → Email Addresses** in your Gitea profile and add every email address you have ever used in your commits (work addresses, old personal addresses, GitHub no-reply addresses, etc.). You can check which emails appear in your history: ```bash # Replace the path with your actual repository root for repo in /path/to/gitea/repositories/owner/*.git; do git -C "$repo" log --all --format="%ae" done | sort | uniq ``` ### 3. Configure paths The script is configured via two environment variables or by editing the constants at the top of the file. | Variable | Default | Description | |---|---|---| | `DB_PATH` | `/etc/komodo/stacks/gitea/data/gitea/gitea.db` | Absolute path to `gitea.db` on the host | | `GITEA_ROOT` | `/etc/komodo/stacks/gitea/data/git/repositories` | Absolute path to the Gitea repository root on the host | To find the correct paths for your setup: ```bash # Find the repository root declared in app.ini docker exec gitea cat /data/gitea/conf/app.ini | grep -E "^ROOT\s*=" # Find the host path mounted into the container docker inspect gitea | grep -A 10 '"Mounts"' ``` --- ## Usage > **The script runs on the Docker host, not inside the container.** > Python is not available inside the minimal Gitea image. ```bash # Using environment variables DB_PATH=/path/to/gitea.db \ GITEA_ROOT=/path/to/repositories \ python3 gitea_backfill.py ``` ```bash # Or edit the constants directly at the top of the script, then run python3 gitea_backfill.py ``` ### Fix git safe.directory errors If git refuses to read the repositories due to ownership mismatch, run this once before executing the script: ```bash git config --global --add safe.directory '*' ``` ### Expected output ``` Gitea Heatmap Backfill ============================================ [1] Creating backup → /path/to/gitea.backup-before-backfill.db [✓] Backup created. [✓] 5 email(s) loaded from email_address table [✓] 8 repo(s) loaded from repository table [✓] 8 bare repo(s) found on disk [2] Existing PUSH_EVENT rows: 0 [→] owner/my-project (id=3) 847 commits found. [500 inserted so far] [→] owner/another-repo (id=4) 312 commits found. ... ──────────────────────────────────────────── Backfill complete ──────────────────────────────────────────── Inserted : 1159 Skipped : 0 (already present or bad date) No user : 4 (email not registered in Gitea) No repo : 0 (repo not found in database) ──────────────────────────────────────────── Restart Gitea to refresh the heatmap: docker restart gitea ``` ### After the script completes Restart Gitea so the heatmap is recomputed from the new records: ```bash docker restart gitea ``` --- ## Troubleshooting **`No user` count is high** Some commit emails are not registered in Gitea. Run the email audit command from the Setup section above, then add the missing addresses in your Gitea profile settings. **`No repo` count is non-zero** The repository name on disk does not match the `owner_name/name` stored in the database. Check for casing differences: ```bash # Names in the database docker exec gitea sqlite3 /data/gitea/gitea.db \ "SELECT owner_name, name FROM repository;" # Names on disk ls /path/to/gitea/repositories/owner/ ``` **`git log` fails with `dubious ownership`** ```bash git config --global --add safe.directory '*' ``` **Running the script a second time** Safe. Already-inserted rows are detected via their content hash and skipped. --- ## Rollback A backup of the database is created automatically before any writes at: ``` /path/to/gitea.backup-before-backfill.db ``` To restore it: ```bash docker stop gitea cp /path/to/gitea.backup-before-backfill.db /path/to/gitea.db docker start gitea ``` --- ## Limitations - SQLite only — not compatible with Gitea instances using PostgreSQL or MySQL - Commit emails must be registered in Gitea; unmatched emails are skipped - Wiki repositories (`*.wiki.git`) are intentionally ignored