These endpoints expose jj-native VCS operations that have no direct GitHub equivalent. They are proxied through the JJHub API to the Rust repo-host which uses jj-lib natively.
jj VCS API
JJHub is a jj-native platform. All version control operations use jj concepts: Change IDs, Bookmarks, Operation Logs, and stacked changes. These endpoints provide direct access to jj VCS operations on repositories.
Bookmarks
Bookmarks are jj’s equivalent of Git branches. Unlike Git branches, bookmarks are explicit pointers that don’t automatically advance - you must explicitly move them.
List Bookmarks
GET /api/repos/{owner}/{repo}/bookmarks
Response:
[
{
"name": "main",
"target": "abc123def456...",
"remote": "origin",
"synced": true
}
]
Create Bookmark
POST /api/repos/{owner}/{repo}/bookmarks
Request:
{
"name": "feature-xyz",
"target": "abc123def456..."
}
Response:
{
"name": "feature-xyz",
"target": "abc123def456...",
"synced": false
}
Get Bookmark
GET /api/repos/{owner}/{repo}/bookmarks/{name}
Update Bookmark
PATCH /api/repos/{owner}/{repo}/bookmarks/{name}
Request:
{
"target": "newchangeid789..."
}
Delete Bookmark
DELETE /api/repos/{owner}/{repo}/bookmarks/{name}
Changes
A Change is jj’s equivalent of a commit, but with a stable Change ID that persists even when the commit is amended or rebased. Every change has:
- A Change ID: a stable identifier (e.g.
wqnwkozp) that never changes
- A Commit ID: the underlying Git commit hash (changes on amend)
- A description: the commit message
- One or more parents: the change’s ancestors
List Changes
Returns the change tree (commit graph) for a repository.
GET /api/repos/{owner}/{repo}/changes
Query parameters:
| Parameter | Type | Description |
|---|
limit | integer | Maximum number of changes to return (default: 100) |
bookmark | string | Filter to changes reachable from a bookmark |
Response:
{
"changes": [
{
"change_id": "wqnwkozpqjlrsurt",
"commit_id": "abc123def456...",
"description": "feat: add webhook retry backoff",
"author": {
"name": "Alice",
"email": "[email protected]"
},
"parents": ["prevchangeid..."],
"is_root": false,
"created_at": "2025-01-15T10:30:00Z"
}
]
}
Get Change
GET /api/repos/{owner}/{repo}/changes/{change_id}
Diffs
Get Change Diff
Returns the diff for a specific change.
GET /api/repos/{owner}/{repo}/changes/{change_id}/diff
Query parameters:
| Parameter | Type | Description |
|---|
format | string | Diff format: unified (default), stat |
context | integer | Lines of context (default: 3) |
Response:
{
"change_id": "wqnwkozpqjlrsurt",
"files": [
{
"path": "internal/routes/webhooks.go",
"status": "modified",
"additions": 42,
"deletions": 7,
"diff": "@@ -1,7 +1,42 @@\n ..."
}
],
"stats": {
"files_changed": 1,
"additions": 42,
"deletions": 7
}
}
Operation Log
The Operation Log is one of jj’s most powerful features. Every jj operation (commit, rebase, undo, etc.) is recorded in the operation log, making any operation undoable. This is analogous to Git’s reflog but for all operations, not just branch moves.
List Operations
GET /api/repos/{owner}/{repo}/oplog
Query parameters:
| Parameter | Type | Description |
|---|
limit | integer | Maximum operations to return (default: 50) |
Response:
{
"operations": [
{
"operation_id": "op123abc...",
"description": "new empty commit",
"user": "alice",
"timestamp": "2025-01-15T10:30:00Z",
"tags": {
"args": "jj new"
}
}
]
}
Stacked Changes
JJHub’s premiere feature is first-class support for stacked changes - a series of changes where each builds on the previous. This enables incremental review and is particularly powerful for AI-assisted development.
A stack looks like:
◉ change-c feat: validate webhook signature
│
◉ change-b feat: add webhook delivery queue
│
◉ change-a feat: add webhook model
│
◉ main
Landing requests can target any change in the stack. The landing queue ensures correct ordering when multiple changes in a stack are landed.
Key Differences from Git
| Concept | Git | jj |
|---|
| Pointer | Branch | Bookmark |
| Commit identity | SHA hash (changes on amend) | Change ID (stable forever) |
| History rewrite | git rebase (creates new commits) | jj rebase (same Change IDs) |
| Undo | Partial (reflog) | Full operation log |
| Staging area | Index | Working copy is always a commit |