File
Blob: docs/data-flows.md
Data Flows
This document describes the primary data flows of the server: pushing (receive-pack), fetching (upload-pack), and the Web UI blob views.
Push (git-receive-pack)
- Client sends
POST /:owner/:repo/git-receive-pack - Worker acquires a receive lease via
beginReceive()RPC. If a lease is already active, returns503 Retry-After: 10. - Worker parses pkt-line commands and the packfile payload from the request body.
- Worker writes the
.packto R2, builds.idxinline, and writes it to R2. - Worker commits refs and pack-catalog metadata atomically via
finalizeReceive()RPC. - Returns a pkt-line
report-statusresponse with sideband progress.
Metadata maintained by the DO
- SQLite tables (embedded in the DO):
pack_catalog(pack_key, ...)— authoritative pack metadata for read-path discovery and compaction
Fetch (git-upload-pack v2)
- Client sends capability advertisement request:
GET /:owner/:repo/info/refs?service=git-upload-pack - For
POST /:owner/:repo/git-upload-packwith a v2 body:ls-refscommand: reads the DO via RPC (getHead()andlistRefs()) and responds with HEAD + refsfetchcommand:- Negotiation phase (
done=false): server returns an acknowledgments block only (ACK/NAK), nopackfilesection - Parses wants/haves and computes minimal closure using frontier-subtract approach with stop sets
- Loads the active pack catalog via
src/git/object-store/catalog.ts#loadActivePackCatalog(), memoized per request with limiter + soft budget - Streaming pack assembly (no buffering):
- Single-pack:
streamPackFromR2()streams directly from R2 with backpressure - Multi-pack union:
streamPackFromMultiplePacks()with proper delta resolution - Uses
crypto.DigestStreamfor incremental SHA-1 computation - Emits sideband-64k with progress messages on channel 2
- Single-pack:
- If repository has no packs, returns
503withRetry-After: 5 - If closure traversal times out, tries a safe multi-pack union based on recent packs
- Negotiation phase (
Web UI blob views
GET /:owner/:repo/blob?ref=...&path=...(preview)- Resolves path to an OID via pack-first reads through the worker-local object store
- If the file is "too large" (configurable threshold), shows a friendly message and links to raw
- If not too large, fetches the object and renders text (with simple binary detection)
GET /:owner/:repo/raw?oid=...&name=...(raw)- Reads the object via pack-first store, decompresses, and streams
- Uses
Content-Disposition: inlineby default (add&download=1to force attachment) - Uses
text/plain; charset=utf-8for safety (prevents HTML/JS execution)
Merge commit exploration
GET /:owner/:repo/commits(main page)- Displays commit history with expandable merge commits
- Merge commits show a badge and are clickable to expand side branch history
GET /:owner/:repo/commits/fragments/:oid(AJAX fragment)- Called when user clicks a merge commit row
- Uses
listMergeSideFirstParent()to traverse non-mainline parents - Algorithm:
- Probe mainline (parents[0]) to build a stop set
- Initialize frontier with side parents (parents[1..])
- Priority queue traversal by author date (newest first)
- Stop when: reached limit, hit mainline, timeout, or scan limit
- Returns HTML fragment with commit rows for dynamic insertion
- No caching at UI level (dynamic content)