---
title: "git"
description: "The git door. Plain git clients use it; no Pando client is needed.\n\n```\nGET  /{owner}/{monorepo}/{repo}.git/info/refs?service=git-upload-pack\nGET  /{owner}/{monorepo}/{repo}.git/info/refs?service=git-receive-pack\nPOST /{owner}/{monorepo}/{repo}.git/git-upload-pack\nPOST /{owner}/{monorepo}/{repo}.git/git-receive-pack\n```\n\nA plain repo drops the repo segment: `/{owner}/{name}.git/...`. The\nother shape answers 404 saying which one fits. An old `owner/name`\n(after a rename or a transfer) still works.\n\nCredentials: HTTP Basic with the user's credential as the password\n(any username; this is what `pando credential`, the git credential\nhelper, supplies), or `Authorization: Bearer <credential>`. Without\ncredentials the door answers 401 with `WWW-Authenticate: Basic`, so a\ncredential helper is asked.\n\nProtocol v2 `object-info` (sizes without downloading): Artifacts does\nnot offer it, so the door adds `object-info` to the v2 advertisement and\nanswers `command=object-info` itself, in git's own reply format\n(`size`, then `<oid> <size>` per object; an unknown object gets\n`<oid> ` with no size). Sizes come from a per-repo index, filled on\nfirst ask and kept forever. Every other v2 command goes to Artifacts\nunchanged.\n\nClone and fetch also accept the read token from a hook delivery\n(`read_token` for a web hook, 30 minutes; `PANDO_READ_TOKEN` for a\nBuildkite build, at least 24 hours so Buildkite's Retry can still\nclone), so CI clones from `clone_url` with no credential of its own.\n\nOnly members of the monorepo get through.\n\nWrites per repo: an Artifacts repo takes about two writes at once, so\nevery write (a push, a branch create or delete, a merge, a meta layer\ncommit) waits for one of the repo's two write slots, first come first\nserved. git just waits. A push that waits 120 s gets\n`remote error: Pando: <repo> is busy with other writes; try the push again`.\nThe ceiling is about 5 to 10 small pushes a second per repo.\n\nPush rule (receive-pack). The door reads the command list before the\npack. If any command updates or deletes the repo's default branch\n(`refs/heads/main`), it refuses the whole push with git's usual\n`! [remote rejected] main (main is protected; ...)` line. Creating main\nwhen it does not exist yet is allowed: that is the first push of\n`pando init`. Main moves only by a merge.\n\nBusy repos. Artifacts runs about 2 receive-packs at once per repo and\nanswers others \"busy\". The door holds a push of up to 1 MiB in memory\nand sends it again once, after 150 to 400 ms. A push that is still\nrefused, or is larger, is rejected with\n`Pando: <repo> is busy with other pushes right now; push again` (every\nref `busy; push again`), and nothing is written: push again. A call to\nArtifacts that fails outright is handled the same way: retried once\nfor a held push, else `Pando: <repo> couldn't take this push right\nnow; push again`, never a bare HTTP 500.\n\nPush size. One push carries at most 64 MiB of receive-pack request\n(67,108,864 bytes), Artifacts' limit. A push whose `Content-Length` is\nover it is refused before anything goes to Artifacts; a streamed one is\ncut off before its pack ends, so it cannot land. Either way git gets\n`Pando: this push is over 64 MiB, the most one push can carry\n(Artifacts' limit); nothing landed.`, how to push in steps (for a\nfirst push of main: `pando init`, which pushes the history in steps on\n`refs/pando/import` and `refs/pando/import-files`, then deletes them),\nand every ref `over 64 MiB; push in steps`. Nothing is recorded.\n\nRaw files, GET or HEAD, beside the git door:\n`/{owner}/{monorepo}/projects/{project}/raw/{path}?ref=` for a\nmonorepo's project (the repo at `projects/{project}`, named\n`projects-{project}`), `/{owner}/{name}/raw/{path}?ref=` for a plain\nrepo, and `/{owner}/{monorepo}/raw/{path}?v=` for a monorepo's own\nfiles (the meta layer; `v` is a meta layer version).\nMembers only, by the session cookie or a Bearer credential. Served so\nnothing runs: `Content-Security-Policy: sandbox`, nosniff, images as\nimages, everything else as `text/plain` (HTML and SVG included) or,\nwith a NUL in its first 8,000 bytes, `application/octet-stream`.\n`ETag` is the content's hash (the git blob's; a large meta file's\nSHA-256). By branch, or a meta file now: `private, no-cache` (a repeat\nis a 304); by a 40-character sha or a `v`: `private, max-age=31536000,\nimmutable`.\n\nThe door records each pushed branch's head and, on its first push, its\nauthor (the user). Then it delivers the `branch.opened` and `push`\nhooks.\n"
---

> Documentation Index
> Fetch the complete documentation index at: https://docs.gitpando.com/llms.txt
> Use this file to discover all available pages before exploring further.

Path: Pando API

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.


Source: https://docs.gitpando.com/api/tags/git/index.md
