Repository forks and mirrors
September 3, 2026 · View on GitHub
Forks
Forks copy Git objects, branches, and tags into a personal namespace or an organization the user administers. Issues, merge requests, members, approvals, webhooks, deploy keys, CI secrets, and mirrors are intentionally not copied. A private source always produces a private fork.
Each fork records both its immediate upstream and root fork-network repository. Network listings include nested forks and are available from every member of the network; a namespace can contain at most one active repository from a network. Deleting an upstream does not erase its descendants' lineage, and deleting an intermediate fork reconnects its children to the nearest surviving ancestor. Users can include every branch or only the default branch. “Sync fork” follows the current upstream default branch when default-only mode is selected and advances branches only when the update is a fast-forward; diverged fork branches are listed as skipped and are never overwritten. This matches the safety expectation of GitLab's forking workflow.
The “Contribute upstream” action compares a fork branch against an upstream base. Gitly fetches the branch into an isolated refs/merge-requests/<id>/head reference in the target repository. Reviews, diffs, merge/squash operations, and approval invalidation use that reference while retaining the source repository and branch identity.
Fork creation, listing, synchronization, and lineage are also available under /api/v1/repos/:owner/:repo/forks.
Mirrors
Repository settings support pull and push mirrors, modeled after GitLab's repository mirroring and pull mirroring:
- Manual updates and a background scheduler, with intervals from 5 to 1440 minutes and explicit pause/resume controls.
- HTTPS basic/token authentication through an ephemeral
GIT_ASKPASShelper. - SSH authentication through an ephemeral private-key file and wrapper. SSH mirrors require a pinned
known_hostsentry and strict host-key checking. - AES-256-GCM encryption at rest for usernames, passwords/tokens, and SSH private keys, derived from
GITLY_STORAGE_SECRETwith a fresh nonce for every field. - Optional protected-branch-only operation.
- Fast-forward-only pull behavior by default. Diverged tags also fail explicitly. “Overwrite diverged branches” enables ref replacement, and each fetched set of local refs is published atomically.
- Push mirrors run immediately after accepted HTTP or SSH pushes as well as on schedule.
- Synchronization uses a database lease to prevent overlapping scheduled, manual, and push-triggered runs; abandoned leases are recovered automatically. Push refsets request atomic remote updates.
- Status, last error, failure count, next update, pause/resume, manual update, and deletion through both settings and API.
Mirror endpoints are revalidated before every network operation. By default they must resolve entirely to public addresses, which blocks loopback, private, link-local, metadata, multicast, and other internal targets. To mirror or import from an explicitly trusted internal Git server, list its exact lowercase hostname in mirror_allowed_hosts or GITLY_MIRROR_ALLOWED_HOSTS (comma-separated). Do not add broad or user-controlled domains.
HTTPS URL query strings and fragments are rejected so credentials cannot be hidden in logged URLs. Embedded HTTPS user information is removed and encrypted separately. SSH URL passwords are rejected; use a private key instead.