Initialize and import
Start a pristine repository from one pinned tree, or from another repository's full history, committed by the same manifest compare-and-swap as a push.
Which one
Both write into an existing, pristine destination and copy every object into its own packs.
| Initialize | Import | |
|---|---|---|
| Creates | One new parentless commit on one branch, with HEAD pointing at it | Every head and tag, and HEAD (symbolic or detached), with their full reachable history |
| Source | A full commit OID in another gitcask repository | A gitcask repository, or a public HTTPS Git URL |
| History | None: only the source tree is copied | All of it, unchanged |
| Commit content | Message, author and committer supplied by the caller | The source objects as they are |
Initialize from a pinned tree
The caller pins a full commit OID, not a branch. Its tree is uploaded into the destination's wal/ before the manifest CAS publishes the new commit.
pinned commit_oid
upload tree closure to wal/
CAS manifest.pb
201
{
"source": {"owner": "templates", "repo": "starter", "commit_oid": "0123456789012345678901234567890123456789"},
"branch": "main",
"operation_key": "project-creation-7",
"message": "Initial project",
"committer": {"name": "Project Builder", "email": "builder@example.test", "when": "2026-09-28T00:00:00Z"}
}{"ref":"refs/heads/main","commit_oid":"<new root oid>","tree_oid":"<source tree oid>","seq":1,"replayed":false}Import a full history
Resolve pins the source refs into a snapshot. Your platform persists it, then imports exactly that snapshot.
POST api/import/resolve
persist the snapshot
POST api/import
CAS manifest.pb
201
Resolve
{"source":"templates/starter"}{"source":"templates/starter","object_format":"sha1","refs":[{"name":"refs/heads/develop","oid":"<full lower-case oid>","peeled":""}],"head":{"symbolic_target":"refs/heads/develop","oid":"<full lower-case oid>"},"snapshot_hash":"<sha256>"}Import
{"operation_key":"creation-123","snapshot":{"source":"templates/starter","object_format":"sha1","refs":[{"name":"refs/heads/develop","oid":"<full lower-case oid>","peeled":""}],"head":{"symbolic_target":"refs/heads/develop","oid":"<full lower-case oid>"},"snapshot_hash":"<sha256>"}}{"operation_key":"creation-123","request_hash":"<sha256>","snapshot_hash":"<sha256>","seq":1,"refs_count":1,"head":{"symbolic_target":"refs/heads/develop","oid":"<original oid>"},"replayed":false}Endpoints and retries
Repeat the identical request to retry. An exact replay returns the original result with replayed:true and never opens the source or moves a ref.
| Endpoint | Body limit | Answers |
|---|---|---|
POST /{owner}/{repo}/api/initialize | 64 KiB | 201 first, 200 exact replay |
POST /{owner}/{repo}/api/import/resolve | 4 KiB | 200 snapshot; resolve again if lost before persisting |
POST /{owner}/{repo}/api/import | 1 MiB | 201 first, 200 exact replay |
GET /{owner}/{repo}/api/import/receipt?operation_key=…&request_hash=… | No body | 200 with replayed:true, 404 absent, 409 key or hash mismatch |
operation_key- 1–128 printable ASCII characters without whitespace.
- Receipt
- One bounded receipt, committed in the same manifest CAS, records the operation key, the request fingerprint and the original result.
- Permissions
- Every attempt, replays included, needs destination write and source read. The receipt GET needs only target read.
- Pristine
- No committed WAL work, packs, checkpoint or receipt. A repository whose refs were all deleted is not pristine.
- Streaming
- With Accept: text/event-stream, work streams as a task with progress; the HTTP status is 200 and the terminal packet carries the result or error.
Boundaries and bounds
- Object format
- SHA-1 and SHA-256 between gitcask repositories; source and target must match (400 otherwise).
- Git LFS
- Any recognized LFS pointer is rejected with 422 before publication. Import checks every historical small blob, not only the tip.
- Gitlinks
- Copied unchanged; submodules are never fetched or recursed.
- External import
- Public HTTPS on port 443, SHA-1 only, no credentials, query or fragment. DNS is pinned to public addresses and every redirect is refused.
| [import] key | Default | Bounds |
|---|---|---|
max_refs | 1024 | Heads and tags per snapshot |
max_objects | 1000000 | Acquired historical objects |
max_bytes | "1 GiB" | External response bytes and output pack; also server.max_push_bytes |
resolve_timeout | "30s" | Refs and HEAD acquisition |
timeout | "15m" | Bulk acquisition and validation, before the CAS |
Errors
Non-503 errors are plain text. A 503 is retryable JSON with Retry-After: retry the identical request.
Initialize
| Status | Meaning |
|---|---|
| 400 | Invalid request/identity/branch/full commit ID, non-commit source object, or different object formats |
| 401 | Missing or invalid credentials |
| 403 | Write denied by the existing forwarded-identity contract |
| 404 | Missing or unauthorized repository, or unavailable pinned source commit |
| 409 | Destination is not pristine, or a committed initializer has a different operation key or fingerprint |
| 413 | Request body or configured server.max_push_bytes pack limit exceeded |
| 422 | Source tree contains a Git LFS pointer; this operation does not copy LFS payloads |
| 503 | Temporary object-store/authentication-service failure; retry the identical request |
Import
| Status | Meaning |
|---|---|
| 400 | Invalid snapshot/hash/format/source URL or unsafe DNS result |
| 401 / 403 / 404 | Existing auth/permission/missing-repository contract |
| 409 | Nonpristine, operation conflict, or pinned source unavailable |
| 413 | JSON, refs, transfer, output pack or object bound exceeded |
| 422 | Empty/unborn source, LFS pointer history, or source requiring auth/redirect/dumb HTTP |
| 503 | Resolve busy, deadline, source DNS/transport, store/auth failure or drain; retry fixed request |