Mirroring

Mirror between GitHub, GitLab, Bitbucket and self-hosted

Any source to any destination, in any direction — including your own Git server and your own object storage.

01 — The matrix

Every direction is supported

Pick any provider or self-hosted server as the source, and any provider, self-hosted server, or object-storage bucket as the destination.

Source ↓ / Destination → GitHub GitLab Bitbucket Self-hosted Object storage
GitHub
GitLab
Bitbucket
Self-hosted / custom

Destination repositories are created automatically on providers that support it. On a custom Git server, the destination repository must already exist before the first sync runs.

02 — Common pairs

The pairs teams set up most

The mechanics are the same for every combination — here's what's specific to the ones teams actually run.

GitHub → GitLab

Connect both accounts over OAuth. Use a GitHub App installation on the source side and its single webhook covers every repository the App can see, so a newly added repository starts mirroring without any extra setup.

GitLab → GitHub

Connect a GitLab account as the source and a GitHub account as the destination. GitReplica creates the destination repository automatically if it doesn't exist, then keeps it current on every push from the GitLab side.

Bitbucket → GitHub

Bitbucket connects over OAuth. Because one Bitbucket account can belong to several workspaces, you pick which workspace a binding reads repositories from when you connect it.

Any provider → self-hosted

GitHub, GitLab or Bitbucket as the source, any Git server reachable over HTTPS or SSH as the destination — authenticated with a token or an SSH key. The source still decides the trigger: a provider source keeps syncing on push even when the destination is self-hosted.

03 — What's mirrored

All refs, minus the ones providers reject

A mirror binding uses the same semantics as a bare Git clone, with two narrow, deliberate exceptions.

Branches, tags and notes

A mirror replicates the full ref set and commit graph — every branch, every tag, commit notes — using the same semantics as git clone --mirror. Nothing is filtered by branch name, age, or activity.

Hidden refs are excluded

refs/pull/*, refs/merge-requests/* and refs/pull-requests/* are provider-internal — every provider rejects a push to them. GitReplica strips these refs before pushing rather than let the sync fail on them.

LFS pointers only

Git LFS pointer files mirror like any other tracked file. The large object content they point to does not — plan on syncing LFS storage separately if a repository uses it.

04 — Setup

Four steps to a running mirror

No infrastructure to run. Connect accounts, pick repositories, and the first mirror starts immediately.

Connect both accounts

Authorize the source and the destination — OAuth for GitHub, GitLab and Bitbucket, or a host and credential pair for a self-hosted server.

Create a binding

Pick the source account, the destination account, and the repositories to mirror.

Choose how it triggers

Provider sources sync on every push by default. Self-hosted and custom sources run on a schedule — hourly, daily or weekly — or whenever you trigger a sync by hand.

The first sync runs immediately

GitReplica doesn't wait for the next push. The initial mirror starts as soon as the binding is created, and you can watch it progress in the sync log.

05 — Beyond Git hosts

A mirror doesn't have to be another Git host

The same binding can write into object storage instead of — or alongside — a live Git remote.

Object storage as a destination

The same binding, writing a timestamped zip archive into your S3 or S3-compatible bucket instead of pushing to a Git remote — no separate tool to configure.

Both at once

One repository can feed more than one binding — a live mirror on a second Git host, and an archive destination in your own storage. Neither binding changes how the other runs.

See how archive destinations work →

FAQ

Mirroring questions

Can I mirror a GitHub repository to GitLab?

Yes. Connect a GitHub account and a GitLab account, then create a binding with the GitHub repository as the source and the GitLab repository as the destination. GitReplica creates the destination repository automatically if it doesn't already exist, and registers a webhook on the GitHub side so every push mirrors within seconds.

Does mirroring include all branches and tags?

Yes. A mirror binding replicates the full ref set — every branch, every tag, commit notes, and the complete commit graph — using the same semantics as git clone --mirror. The only refs excluded are provider-internal ones like pull request refs, which providers reject pushes to anyway.

Are pull requests mirrored?

No. Pull requests, issues and reviews live in the provider's database, not inside the Git repository, so a git push has nothing to carry them with. If you need a copy, an object-storage destination can optionally capture them as a JSON snapshot alongside the code — see Git backup archives.

Can I mirror to a self-hosted Git server?

Yes. Any Git server reachable over HTTPS or SSH can be a destination — authenticate with a token or an SSH key. The destination repository needs to exist there first; GitReplica can auto-create destinations on GitHub, GitLab and Bitbucket, but not on a plain Git server.

Mirror your first repository today.

Connect two accounts and create a binding — the first sync runs immediately. Free for open source and private non-commercial use.

Get started free