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.
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.
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.
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.
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.
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.
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.
Keep reading
Replicate a Git repository
Keep a live, clonable replica on a second host.
Duplicate a Git repository
Copy a repository with its full history, once or continuously.
Back up a Git repository
Why a clone isn't a backup, and the four ways teams actually do it.
Bitbucket mirroring & backup
Mirror Bitbucket repositories to GitHub, GitLab, self-hosted Git, or your own storage.
GitLab mirroring & backup
Mirror GitLab repositories to GitHub, Bitbucket, self-hosted Git, or cloud storage.
Mirror GitHub to GitLab
Keep an automatic GitLab copy for redundancy, migration readiness, and failover.
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