---
name: gitea-migrate
description: Migrate a local project into Jonathan's self-hosted Gitea (192.168.0.12:3010), or clean up an existing repo, without committing secrets, node_modules, build artifacts, large media, or databases. Use when asked to put a project in git/Gitea, version a project, publish a repo, "add this to Gitea", strip large files from history, or clean a bloated .git. Enforces gitignore-before-init, pre-commit safety guards, and on-server history rewriting for big repos.
---

# Gitea Migrate

Get a project into Gitea cleanly. The recurring failure mode is **bloat and secrets** entering git: raw video, `node_modules`, `.next`/build caches, databases, and `.env` files. Prevent them BEFORE `git add`.

## Hard rules

- **NEVER commit:** `.env` (any), `node_modules/`, build artifacts (`dist/`, `build/`, `.next/`, `.turbo/`), caches, databases (`*.db`, `pg_wal`, `pg-data/`, `pgdata/`), large media (`*.mp4/.mov/.webm`, big images), archives (`*.zip/.tar.gz`), `.DS_Store`.
- **Write `.gitignore` BEFORE `git add`** so gigabytes never enter the object store.
- **Check free disk space first.** Jon's Mac is tight (~7–8 GB free); a big `git add` can fill it and lock up the whole agent. Do heavy/history work ON THE SERVER (317 GB free), not the Mac.
- **Inspect tracked `.env` files individually** — some are harmless templates/public build vars (e.g. `VITE_*`), but DATABASE_URL/JWT_SECRET/tokens must stay out.
- Repos are **private**, default branch `main`; the working branch is `dev`.
- **Never push the OUTER workspace repo** (`~/.openclaw/workspace`) to Gitea — it holds SOUL/USER/TOOLS/memory and infra context. Keep it local.

## Gitea reference

- API base: `http://192.168.0.12:3010` · web UI same host:3010
- User: `jonathan` · credentials in memory (`memory/2026-06-10.md`) — never hardcode in committed files
- Create repo: `POST /api/v1/user/repos` `{ "name": "<repo>", "private": true }`
- List repos: `GET /api/v1/user/repos?limit=100`
- Repo naming: lowercase, spaces→hyphens (e.g. "PR v3" → `pr-v3`).
- Git SSH port is `2222` (HTTP push is simplest for LAN).

## Workflow — migrate a clean/small project

1. **Pre-flight scan** — commits, dirty count, tracked secrets/big files, `.git` size:
   ```bash
   d="path/to/project"
   git -C "$d" rev-list --count HEAD 2>/dev/null
   git -C "$d" ls-files | grep -iE '(^|/)\.env$' ; git -C "$d" ls-files | grep -c node_modules
   git -C "$d" ls-files -s | awk '{print $4}' | while read f; do s=$(wc -c <"$d/$f" 2>/dev/null); [ "${s:-0}" -gt 5000000 ] && echo "BIG $f"; done
   du -sh "$d/.git" 2>/dev/null
   ```

2. **Write/extend `.gitignore`** (before adding anything) covering the categories above, plus project-specific big dirs found in step 1.

3. **Initialize if needed** (`git init -b main`), then `git add -A`.

4. **SAFETY GATE — abort the commit if any staged file is a secret or oversized:**
   ```bash
   git -C "$d" diff --cached --name-only | grep -iE '(^|/)\.env$' && { echo "ABORT: .env staged"; exit 1; }
   git -C "$d" diff --cached --name-only | while read f; do s=$(wc -c <"$d/$f" 2>/dev/null); [ "${s:-0}" -gt 52428800 ] && echo "ABORT: >50MB $f"; done
   ```

5. **Commit** a checkpoint, **create the Gitea repo**, set remote, **push `main`**:
   ```bash
   git -C "$d" remote add gitea "http://jonathan:<PASS>@192.168.0.12:3010/jonathan/<repo>.git" 2>/dev/null \
     || git -C "$d" remote set-url gitea "http://jonathan:<PASS>@192.168.0.12:3010/jonathan/<repo>.git"
   git -C "$d" push -u gitea main
   ```

6. **Scrub the credential from the remote URL** afterward (don't leave the password in `.git/config`):
   ```bash
   git -C "$d" remote set-url gitea "http://192.168.0.12:3010/jonathan/<repo>.git"
   ```

7. Verify on Gitea (`GET /api/v1/repos/jonathan/<repo>` → 200, `"empty":false`).

## Workflow — big/bloated repo (history rewrite)

When `.git` is large or `node_modules`/media are baked into history, rewrite on the **server** (disk headroom), using `git filter-repo`:

- **If history has no value** (one bloat commit): reinitialize — `rm -rf .git`, add `.gitignore`, fresh `git init -b main`, commit source only. (Bruno: 24 GB → 752 KB this way.)
- **If history is worth keeping:** strip paths in-place —
  ```bash
  git -C "$d" filter-repo --force --invert-paths \
    --path node_modules --path Research --path-glob '*.mp4' --path-glob '*.zip'
  ```
  Then add `.gitignore`, commit dirty source, push. (Provisioning: 119 MB → 3.4 MB; preserved commits.)
- Avoid inline `python3 -c`/`perl`/`ruby` with encoded execution in commands (triggers safety heuristics); prefer `grep`/`jq`/`awk` and the `filter-repo` flags above.

## Notes

- A status doc lives at `web-projects/MIGRATION-STATUS.md`.
- After publishing new repos, refresh the landing page (see `project-directory` skill).
