Open a merge request 
Merge requests let you propose changes from a fork descendant back to an upstream project without write access on the target.
Build the prerequisites interactively
Use the live docs flows to produce the source state that a merge request depends on:
The merge-request flow itself remains protocol-documented here while the interactive fork and ref-update steps above give you the concrete source state needed for MERGE_REQUEST_ADD.
How it works
The full lifecycle is:
- fork the upstream project with
FORK - push commits and update refs on your fork
- open a merge request with
MERGE_REQUEST_ADD, targeting the upstream project - the upstream maintainer reviews the proposal
- the maintainer merges by submitting
COMMIT_BUNDLEandREF_UPDATEon the target project, then closes the request withMERGE_REQUEST_REMOVE
You can also withdraw your own merge request at any time with MERGE_REQUEST_REMOVE.
The protocol records the proposal — merge resolution is application-layer. The protocol does not define a "merged" or "rejected" state.
Message body
MERGE_REQUEST_ADD
| Field | Constraint |
|---|---|
project_id | Target (upstream) project ID, 32 bytes |
source_project_id | Source fork-descendant project ID, 32 bytes |
source_ref | Branch or ref name in the fork, 1–254 bytes, no null bytes |
source_commit_hash | Head commit of proposed changes, 32 bytes |
target_ref | Suggested target ref in upstream, 1–254 bytes, no null bytes |
title | Short description, 1–200 UTF-8 bytes |
source_project_id must be in the target project's retained fork lineage within MAX_FORK_LINEAGE_DEPTH = 256 hops. source_project_id must not equal project_id — you cannot open a merge request from a project to itself.
source_ref must resolve exactly to source_commit_hash at execution time — the hash is authoritative, the ref name is advisory for humans.
target_ref is advisory only and does not constrain the maintainer performing the merge.
The merge request identity is content-addressed: request_id = Message.hash. Two messages with different timestamps produce different request_id values, so the same requester can open multiple merge requests against the same project.
MERGE_REQUEST_REMOVE
| Field | Constraint |
|---|---|
project_id | Target project ID, 32 bytes |
request_id | Content-addressed MR ID (original MERGE_REQUEST_ADD message hash), 32 bytes |
Authorization
Opening a merge request
MERGE_REQUEST_ADD requires SIGNING scope. The target project must be Active (not Archived or Removed). The requester does not need any permission on the target project if it is public. Private targets require READ+ access.
The source project must not be Removed, and the requester must be the source owner or have READ+ access on a private source project.
Closing a merge request
MERGE_REQUEST_REMOVE has dual authorization — the first message type with this pattern:
- Requester withdrawal — the original requester can close without any target-project membership
- Maintainer closure — the target project owner or any collaborator with
WRITE+permission can close
The target project must not be Removed. Closure is allowed on Archived projects so maintainers can clean up.
V2 semantics
- merge requests are a tombstone-backed 2P set — same pattern as collaborators, links, and reactions
- merge request state is stored under the target project's namespace at prefix
0x1B, with a requester reverse index at0x1C ProjectState.merge_request_counttracks the number of active merge requests per project- the target project owner funds merge-request capacity:
20 + storage_units × 20per project - both active entries and tombstones count toward quota; oldest entries are pruned first
- closed merge requests return
NOT_FOUND— closure attribution is available only from finalizedMERGE_REQUEST_REMOVEmessage history, not from canonical state MERGE_REQUEST_ADDandMERGE_REQUEST_REMOVEare storage-sensitive message types using tombstone-backed 2P-set semantics: remove wins on add/remove timestamp ties, and equal-timestamp add/add remains last-inclusion-wins
Learn more
- Protocol messages
- Protocol state model
- Protocol storage limits
- Protocol submit pipeline
- API examples
- Fork a project
Next steps
- Fork a project — create the source fork lineage
- Contribute to a project — push the commits referenced by the merge request