Skip to content

REST API

All REST API endpoints use the base path /api/repos/:owner/:repo. Request and response bodies are JSON.

GET /api/repos
GET /api/repos/:owner

Returns all known repositories, optionally filtered by owner:

{
"repos": [
{ "owner": "alice", "name": "project-a" },
{ "owner": "alice", "name": "project-b" }
]
}

Repos are discovered from R2 object prefixes, so only repos with at least one commit appear.

GET /api/repos/:owner/:repo

Returns repository metadata:

{
"owner": "alice",
"name": "project-a",
"description": "My project",
"visibility": "public",
"default_branch": "main",
"created_at": "2025-01-01T00:00:00.000Z",
"updated_at": "2025-06-01T00:00:00.000Z"
}
PATCH /api/repos/:owner/:repo
{ "description": "Updated description", "visibility": "private" }

Updatable fields: description, visibility, default_branch.

POST /api/repos/:owner/:repo/init
{ "defaultBranch": "main" }

Creates the repository with an empty HEAD pointing to the specified branch.

GET /api/repos/:owner/:repo/files?ref=main&path=src/index.ts

Returns the file content at the given ref and path:

{ "content": "console.log('hi')", "size": 17 }

Binary files are returned with base64 encoding:

{ "content": "iVBOR...", "size": 1024, "encoding": "base64", "binary": true }
GET /api/repos/:owner/:repo/files?ref=main

Lists entries at the root tree:

{
"files": [
{ "path": "README.md", "mode": "100644", "type": "blob", "sha": "abc..." },
{ "path": "src", "mode": "40000", "type": "tree", "sha": "def..." }
]
}
GET /api/repos/:owner/:repo/files/all?ref=main

Recursively lists all files (blobs only):

{
"files": [
{ "path": "README.md", "mode": "100644", "type": "blob", "sha": "abc..." },
{ "path": "src/index.ts", "mode": "100644", "type": "blob", "sha": "ghi..." }
]
}
POST /api/repos/:owner/:repo/commits
{
"ref": "main",
"message": "Add feature",
"author": "Alice",
"email": "alice@example.com",
"files": [
{ "path": "feature.ts", "content": "export const x = 1;" },
{ "path": "old-file.ts", "content": null }
],
"timestamp": 1700000000
}

Set content to null to delete a file. Returns { "sha": "abc..." }.

GET /api/repos/:owner/:repo/commits/:sha

Returns structured data for a single commit:

{
"sha": "abc...",
"tree": "def...",
"parents": ["ghi..."],
"author": "Alice",
"authorEmail": "alice@example.com",
"authorTimestamp": 1700000000,
"committer": "Alice",
"committerEmail": "alice@example.com",
"committerTimestamp": 1700000000,
"message": "Add feature\n"
}
GET /api/repos/:owner/:repo/log?ref=main&max=50

Returns commit history walking from the given ref. Add &path=src/index.ts to filter to commits that changed a specific file:

GET /api/repos/:owner/:repo/log?ref=main&path=src/index.ts

Full log response:

{
"commits": [
{
"sha": "abc...",
"tree": "def...",
"parents": ["ghi..."],
"author": "Alice",
"authorEmail": "alice@example.com",
"authorTimestamp": 1700000000,
"committer": "Alice",
"committerEmail": "alice@example.com",
"committerTimestamp": 1700000000,
"message": "Add feature\n"
}
]
}
GET /api/repos/:owner/:repo/branches
{
"branches": [
{ "name": "main", "sha": "abc...", "isHead": true },
{ "name": "feature", "sha": "def...", "isHead": false }
]
}
POST /api/repos/:owner/:repo/branches
{ "name": "feature", "startPoint": "main" }

startPoint defaults to HEAD if omitted.

DELETE /api/repos/:owner/:repo/branches/:name

Cannot delete the currently checked-out branch.

PATCH /api/repos/:owner/:repo/branches/:name
{ "newName": "feature-v2" }

Updates HEAD if it pointed to the old branch.

POST /api/repos/:owner/:repo/checkout
{ "branch": "feature" }
POST /api/repos/:owner/:repo/detach-head
{ "sha": "abc123..." }

Sets HEAD to a specific commit SHA (detached HEAD state).

GET /api/repos/:owner/:repo/tags
{
"tags": [
{ "name": "v1.0", "sha": "abc...", "type": "lightweight" },
{
"name": "v2.0", "sha": "def...", "type": "annotated",
"target": "ghi...", "tagger": "Alice", "message": "Release v2.0\n"
}
]
}
POST /api/repos/:owner/:repo/tags
{ "name": "v1.0", "target": "main" }
POST /api/repos/:owner/:repo/tags
{
"name": "v2.0",
"target": "main",
"tagger": "Alice",
"email": "alice@example.com",
"message": "Release v2.0"
}

If message is present, an annotated tag object is created. target resolves a ref or SHA to the commit being tagged (defaults to HEAD).

DELETE /api/repos/:owner/:repo/tags/:name
GET /api/repos/:owner/:repo/diff?a=<ref>&b=<ref>
GET /api/repos/:owner/:repo/diff?from=<ref>&to=<ref>

Compares two refs. Both a/b and from/to parameter names are accepted. If b/to is omitted, diffs against the parent commit.

{
"entries": [
{ "path": "feature.ts", "status": "added", "newSha": "abc..." },
{ "path": "old.ts", "status": "deleted", "oldSha": "def..." },
{ "path": "main.ts", "status": "modified", "oldSha": "ghi...", "newSha": "jkl..." }
]
}

Add &content=true to include unified diff patches and size information:

GET /api/repos/:owner/:repo/diff?a=<ref>&b=<ref>&content=true
{
"entries": [
{
"path": "main.ts",
"status": "modified",
"oldSha": "ghi...",
"newSha": "jkl...",
"oldSize": 120,
"newSize": 145,
"patch": "--- a/main.ts\n+++ b/main.ts\n@@ -1,3 +1,5 @@\n..."
},
{
"path": "image.png",
"status": "modified",
"oldSha": "mno...",
"newSha": "pqr...",
"binary": true
}
]
}

Binary files are detected automatically (null byte in first 8KB) and flagged with "binary": true instead of a patch. When PACK_WORKER is configured, diff computation fans out to the compute pool for large changesets.

GET /api/repos/:owner/:repo/grep?pattern=<regex>&ref=<ref>&context=<n>

Searches blob content at the given ref using a regular expression. Returns matching lines with surrounding context.

ParameterDefaultDescription
pattern (or q)requiredRegex pattern to search for
refHEADBranch, tag, or commit SHA
context2Lines of context before/after each match (max 10)
{
"matches": [
{
"path": "src/index.ts",
"lines": [
{ "num": 5, "text": "import { createHandler } from 'gitmode';", "match": true },
{ "num": 6, "text": "", "match": false }
]
}
]
}

When PACK_WORKER is configured, grep fans out to the compute pool for repos with many files.

POST /api/repos/:owner/:repo/merge
{
"target": "main",
"source": "feature",
"author": "Alice",
"email": "alice@example.com",
"message": "Merge feature into main"
}

Returns the merge strategy used:

{ "sha": "abc...", "strategy": "fast-forward" }

or for a three-way merge:

{ "sha": "abc...", "strategy": "merge" }

Conflicts are resolved automatically (takes theirs for conflicting files).

POST /api/repos/:owner/:repo/cherry-pick
{
"commit": "<sha>",
"target": "main",
"author": "Alice",
"email": "alice@example.com"
}

Applies the changes from the specified commit onto the target branch using three-way merge.

POST /api/repos/:owner/:repo/revert
{
"commit": "<sha>",
"target": "main",
"author": "Alice",
"email": "alice@example.com"
}

Creates a new commit that undoes the changes introduced by the specified commit.

POST /api/repos/:owner/:repo/reset
{ "ref": "main", "target": "<sha>" }

Moves the branch ref to point at a different commit.

GET /api/repos/:owner/:repo/rev-parse?ref=HEAD

Resolves a ref to a commit SHA. Supports: branch names, tag names, HEAD, HEAD~N, HEAD^, HEAD^2, raw SHAs.

{ "sha": "abc..." }
GET /api/repos/:owner/:repo/contributors

Aggregates author statistics from the commit index:

{
"contributors": [
{ "name": "Alice <alice@example.com>", "commits": 42, "lastCommit": 1700000000 },
{ "name": "Bob <bob@example.com>", "commits": 17, "lastCommit": 1699000000 }
]
}
GET /api/repos/:owner/:repo/stats?ref=main

Returns repository statistics:

{
"commits": 42,
"branches": 3,
"tags": 5,
"files": 28,
"size": 145920
}

size is total uncompressed file content in bytes.

GET /api/repos/:owner/:repo/show?sha=<sha>

Reads a raw git object:

{ "type": "commit", "size": 234, "content": "tree abc...\nparent ..." }

For blob objects with binary content (null byte in first 8KB), the response includes base64 encoding:

{ "type": "blob", "size": 1024, "content": "iVBOR...", "encoding": "base64", "binary": true }