Skip to content

git

The git door. Plain git clients use it; no Pando client is needed.

GET  /{owner}/{monorepo}/{repo}.git/info/refs?service=git-upload-pack
GET  /{owner}/{monorepo}/{repo}.git/info/refs?service=git-receive-pack
POST /{owner}/{monorepo}/{repo}.git/git-upload-pack
POST /{owner}/{monorepo}/{repo}.git/git-receive-pack

A plain repo drops the repo segment: /{owner}/{name}.git/.... The other shape answers 404 saying which one fits. An old owner/name (after a rename or a transfer) still works.

Credentials: HTTP Basic with the user's credential as the password (any username; this is what pando credential, the git credential helper, supplies), or Authorization: Bearer <credential>. Without credentials the door answers 401 with WWW-Authenticate: Basic, so a credential helper is asked.

Protocol v2 object-info (sizes without downloading): Artifacts does not offer it, so the door adds object-info to the v2 advertisement and answers command=object-info itself, in git's own reply format (size, then <oid> <size> per object; an unknown object gets <oid> with no size). Sizes come from a per-repo index, filled on first ask and kept forever. Every other v2 command goes to Artifacts unchanged.

Clone and fetch also accept the read token from a hook delivery (read_token for a web hook, 30 minutes; PANDO_READ_TOKEN for a Buildkite build, at least 24 hours so Buildkite's Retry can still clone), so CI clones from clone_url with no credential of its own.

Only members of the monorepo get through.

Writes per repo: an Artifacts repo takes about two writes at once, so every write (a push, a branch create or delete, a merge, a meta layer commit) waits for one of the repo's two write slots, first come first served. git just waits. A push that waits 120 s gets remote error: Pando: <repo> is busy with other writes; try the push again. The ceiling is about 5 to 10 small pushes a second per repo.

Push rule (receive-pack). The door reads the command list before the pack. If any command updates or deletes the repo's default branch (refs/heads/main), it refuses the whole push with git's usual ! [remote rejected] main (main is protected; ...) line. Creating main when it does not exist yet is allowed: that is the first push of pando init. Main moves only by a merge.

Busy repos. Artifacts runs about 2 receive-packs at once per repo and answers others "busy". The door holds a push of up to 1 MiB in memory and sends it again once, after 150 to 400 ms. A push that is still refused, or is larger, is rejected with Pando: <repo> is busy with other pushes right now; push again (every ref busy; push again), and nothing is written: push again. A call to Artifacts that fails outright is handled the same way: retried once for a held push, else Pando: <repo> couldn't take this push right now; push again, never a bare HTTP 500.

Push size. One push carries at most 64 MiB of receive-pack request (67,108,864 bytes), Artifacts' limit. A push whose Content-Length is over it is refused before anything goes to Artifacts; a streamed one is cut off before its pack ends, so it cannot land. Either way git gets Pando: this push is over 64 MiB, the most one push can carry (Artifacts' limit); nothing landed., how to push in steps (for a first push of main: pando init, which pushes the history in steps on refs/pando/import and refs/pando/import-files, then deletes them), and every ref over 64 MiB; push in steps. Nothing is recorded.

Raw files, GET or HEAD, beside the git door: /{owner}/{monorepo}/projects/{project}/raw/{path}?ref= for a monorepo's project (the repo at projects/{project}, named projects-{project}), /{owner}/{name}/raw/{path}?ref= for a plain repo, and /{owner}/{monorepo}/raw/{path}?v= for a monorepo's own files (the meta layer; v is a meta layer version). Members only, by the session cookie or a Bearer credential. Served so nothing runs: Content-Security-Policy: sandbox, nosniff, images as images, everything else as text/plain (HTML and SVG included) or, with a NUL in its first 8,000 bytes, application/octet-stream. ETag is the content's hash (the git blob's; a large meta file's SHA-256). By branch, or a meta file now: private, no-cache (a repeat is a 304); by a 40-character sha or a v: private, max-age=31536000, immutable.

The door records each pushed branch's head and, on its first push, its author (the user). Then it delivers the branch.opened and push hooks.

    Navigation

    Type to search…

    ↑↓ navigate↵ selectEsc close