|
| 1 | +# CLAUDE.md |
| 2 | + |
| 3 | +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. |
| 4 | + |
| 5 | +## Commands |
| 6 | + |
| 7 | +```bash |
| 8 | +# Install dependencies |
| 9 | +uv sync |
| 10 | + |
| 11 | +# Run the application |
| 12 | +uv run commit-explorer [owner/repo] [--depth N] [--export] |
| 13 | + |
| 14 | +# Examples |
| 15 | +uv run commit-explorer # Interactive mode |
| 16 | +uv run commit-explorer torvalds/linux --depth 100 |
| 17 | +uv run commit-explorer owner/repo --export # Print graph to stdout |
| 18 | +``` |
| 19 | + |
| 20 | +## Architecture |
| 21 | + |
| 22 | +The entire application lives in a single file: `app.py` (~890 lines). |
| 23 | + |
| 24 | +### Layers |
| 25 | + |
| 26 | +1. **Git Providers** (`GitHubProvider`, `GitLabProvider`, `AzureDevOpsProvider`) — subclasses of `GitProvider` ABC. Each builds authenticated clone URLs and browser commit URLs from environment tokens. |
| 27 | + |
| 28 | +2. **`_GitBackend`** — manages git operations via Dulwich (pure-Python git): |
| 29 | + - `load(url, depth)` — bare-clones with `filter=blob:none` (no blobs, just commits+trees) into a temp dir |
| 30 | + - `_extract_commits()` — walks the DAG, returns `CommitInfo` namedtuples |
| 31 | + - `get_detail(sha)` — on-demand: computes file diffs using `tree_changes()` + `difflib.unified_diff()` |
| 32 | + - Pagination: 30 commits per page |
| 33 | + |
| 34 | +3. **`_build_graph_from_git()`** — renders the commit graph by running `git log --graph --color=always` as a subprocess. Uses `\x01`/`\x00` markers to parse commit lines vs. graph decoration lines without regex. Converts ANSI colors to Rich `Text` objects. |
| 35 | + |
| 36 | +4. **Textual UI** — `CommitExplorer(App)` is the root. Key widgets: |
| 37 | + - `CommitItem(ListItem)` — one row per commit (graph line + metadata) |
| 38 | + - `Splitter` / `GraphSplitter` — draggable dividers for resizing panels |
| 39 | + - Background work via Textual's `@work` decorator; spinner shown during clone/fetch |
| 40 | + |
| 41 | +### Data Flow |
| 42 | + |
| 43 | +``` |
| 44 | +User input (owner/repo + provider) |
| 45 | + → _fetch_commits() [@work, async] |
| 46 | + → GitProvider builds URL |
| 47 | + → _GitBackend.load() clones repo |
| 48 | + → _build_graph_from_git() renders graph |
| 49 | + → ListView populated (30 at a time) |
| 50 | + → User selects commit |
| 51 | + → _fetch_detail() [@work, async] |
| 52 | + → _GitBackend.get_detail(sha) |
| 53 | + → Detail panel updates |
| 54 | +``` |
| 55 | + |
| 56 | +### Core Types (NamedTuples) |
| 57 | + |
| 58 | +- `CommitInfo` — sha, short_sha, message, author, author_email, date, parents |
| 59 | +- `FileChange` — filename, status, additions, deletions |
| 60 | +- `CommitDetail` — info, stats, files, refs, linked_prs |
| 61 | +- `RepoInfo` — description, default_branch, language, stars, forks, branches, total_commits |
| 62 | + |
| 63 | +## Environment Variables |
| 64 | + |
| 65 | +Copy `.env.example` to `.env` for provider authentication: |
| 66 | + |
| 67 | +```bash |
| 68 | +GITHUB_TOKEN=... |
| 69 | +GITLAB_TOKEN=... |
| 70 | +GITLAB_URL=https://gitlab.com # or custom self-hosted |
| 71 | +AZURE_DEVOPS_TOKEN=... |
| 72 | +AZURE_DEVOPS_ORG=... |
| 73 | +GIT_SSL_NO_VERIFY=1 # bypass SSL cert verification (corporate proxies) |
| 74 | +``` |
| 75 | + |
| 76 | +## Key Behaviors |
| 77 | + |
| 78 | +- **Shallow clone optimization**: Uses `filter=blob:none` — file content is never fetched, only commits and trees. This makes large repos fast to load. |
| 79 | +- **SSL bypass**: When `GIT_SSL_NO_VERIFY=1` is set, a custom `urllib3.PoolManager` with `cert_reqs=ssl.CERT_NONE` is passed to Dulwich's `porcelain.clone()`. |
| 80 | +- **Graph rendering**: Avoids custom graph.c port — delegates entirely to subprocess `git log --graph`. NUL-delimited markers extract structured fields without regex parsing. |
0 commit comments