Bitbucket Cloud Repository Mirroring to an External Git Host
Use Bitbucket Cloud mirroring to keep a read-only copy of repositories on GitHub or GitLab for disaster recovery, with commit-hash checks and dedicated credentials.
21 Jul 2025, 17:14 UTC

Problem and design constraint
You run production code in Bitbucket Cloud and need a disaster-recovery copy on another Git host, such as GitHub or GitLab, so a cross-platform CI pipeline or an outage recovery runbook has a reachable repository. The constraint is that you must not maintain two writable sources of truth. Divergent histories, duplicate pull requests, and split issue tracking make the copy useless for recovery and dangerous for deployments.
The useful takeaway: enable Bitbucket's built-in repository mirroring, point it at a dedicated target repository, authenticate with a non-personal credential, and treat the target as strictly read-only. Monitor the target's latest commit hash against Bitbucket's source hash to detect silent failures.
Requirements
- Bitbucket Cloud repository with administrator access.
- Target Git repository on an external host (GitHub, GitLab, or similar) created ahead of time.
- A credential the mirror can use: a personal access token (PAT) or an SSH public/private key pair.
- Network path from Bitbucket's mirroring service to the target host over HTTPS or SSH.
- A way to read the latest commit hash from the target host, typically its REST API.
Smallest suitable design
Use Repository Settings → Mirroring in Bitbucket Cloud. Enter the target repository's Git URL (HTTPS or SSH), supply the credential, and enable the mirror. Bitbucket pushes every new commit to the target automatically. This is the smallest viable design because it requires no separate scheduler, no custom scripts, and no additional infrastructure.
Configure one mirror per source repository. Do not share a single target repository across multiple Bitbucket sources unless you intentionally want merged histories, which complicates recovery and access control.
Example configuration
# Run from a local terminal or CI runner with repository admin rights.
# Placeholders: replace values in angle brackets.
# 1. Create a PAT on the target host with repository read/write scope.
# 2. In Bitbucket, open Repository Settings → Mirroring.
# 3. Target URL: https://github.com//.git
# 4. Authentication: PAT or SSH key stored as a repository variable.
# 5. Enable mirroring and confirm the status changes to active.
Risk: an incorrect URL or over-privileged credential can write to the wrong repository or expose a developer's personal account. Use a dedicated service account and a credential with the narrowest scope that allows pushing.
Trust and data boundaries
| Boundary | Behavior |
|---|---|
| Source of truth | Bitbucket Cloud repository. All writes, merges, and branch protections happen here. |
| Mirror target | Read-only copy. Never push directly to the target; direct writes create divergence that the mirror may not overwrite cleanly. |
| Credential boundary | Mirror credential is stored separately from developer accounts. Rotate it independently. |
| Data scope | Git objects (commits, branches, tags) only. Issues, pull requests, wiki pages, and branch permissions are not mirrored. |
Operational checks
- After enabling the mirror, push a test commit to a feature branch in Bitbucket.
- Wait for the mirroring interval, then check the target repository's web UI or API for the same commit hash.
- Set up a scheduled check that compares the source's latest commit hash on the default branch with the target's latest commit hash. Alert when they differ beyond an expected lag.
- Review Bitbucket mirroring logs for authentication errors, 404 responses, or push rejections.
Diagnostic command example
# Run from any machine with network access to the target host.
# Requires a target-host token with read access to the repository.
curl -s -H "Authorization: token " \
"https://api.github.com/repos///commits/" \
| jq -r '.sha'
Expected check: the returned SHA matches the latest commit SHA in the Bitbucket source repository. If it does not, the mirror has either not run yet or has failed. Do not treat a short delay as failure; mirroring is eventually consistent, not instantaneous.
Failure modes
- Network outage: Bitbucket cannot reach the target host. Pushes queue or fail depending on the mirroring implementation; health checks should flag missing commits after a defined window.
- Authentication failure: PAT expires, is revoked, or the SSH key is removed. The mirror stops pushing and the target grows stale.
- Target quota or rate limit: The external host rejects pushes because of storage limits, API rate limits, or required two-factor verification on the service account.
- Target repository deleted: Bitbucket reports a 404 or equivalent error and stops pushing new commits.
- Direct write to target: Someone pushes to the external repository. Future mirror pushes may fail or create conflicting refs.
Rollback
Enabling mirroring changes state by writing commits to an external system. To roll back:
- In Bitbucket, open Repository Settings → Mirroring and disable the mirror.
- Revoke the PAT or remove the SSH key from the target host account.
- Optionally delete the target repository if it is no longer needed.
Disabling the mirror does not delete commits already pushed to the target. It only stops future pushes.
Conditions that would change the design
- If you need issues, pull requests, or permissions replicated, mirroring is insufficient; use a separate issue exporter or a platform migration tool.
- If you need bidirectional synchronization or active-active use of both hosts, a simple mirror is the wrong design; consider a distributed Git topology with conflict resolution.
- If you use Bitbucket Server or Data Center rather than Bitbucket Cloud, its smart mirror feature reduces clone latency for local users but does not push to an external Git host in the same way; the architecture here applies to Cloud repository mirroring.
- If regulatory policy prohibits storing source code on a third-party host outside your network, an external mirror is not acceptable regardless of technical feasibility.
Practical verification
- Create a test repository in Bitbucket and a matching empty repository on the target host.
- Enable mirroring with a dedicated credential.
- Push a commit to Bitbucket and confirm the same commit appears on the target through its web UI.
- Revoke the credential and confirm Bitbucket logs an authentication error and the target repository remains unchanged.
- Delete the target repository and confirm Bitbucket's mirroring UI reports a not-found error and stops pushing.
These steps verify the happy path, the credential boundary, and the failure signal without modifying production repositories.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.