Mirror a GitHub repository
A mirror is a read-only copy of a repository that syncs from its source on a schedule. Code, branches, and tags stay up to date. If the source goes offline, the mirror keeps serving.
This is not the same as a one-time import. An import creates an independent repo and cuts ties to the source. A mirror stays connected and pulls changes automatically. Use a mirror when you want a live copy; use an import when you are moving permanently.
Set up a mirror
Section titled “Set up a mirror”There are two ways to create a mirror: the GitHub App (recommended) or a personal access token.
Option A: GitHub App (recommended)
Section titled “Option A: GitHub App (recommended)”No token to manage. Codebahn mints a short-lived, repo-scoped token on each sync. Nothing is stored except the installation ID, which is not a secret.
- Sign in to Codebahn
- Click + > Import repository > GitHub
- On the Connect GitHub tab, click Connect GitHub account
- Authorize the Codebahn app on GitHub. If this is your first time, install it on your account or organization and grant access to the repos you want to mirror
- Check This repository will be a mirror. Metadata checkboxes (issues, PRs, etc.) are disabled because mirrors are git-only
- Select the repos to mirror
- Choose an owner and click Import selected
The 30-minute connection window applies to the initial setup only. Once the mirror is created, syncs run unattended.
Option B: Personal access token
Section titled “Option B: Personal access token”If you cannot install the GitHub App (e.g. an account where you lack admin rights), use a token instead.
- Create a fine-grained personal access token with Contents: Read-only. Set a long expiration (90 days or the maximum your org allows). If the token expires, syncs stop until you update it in mirror settings
- Click + > Import repository > GitHub
- Switch to the Personal access token tab
- Paste the HTTPS clone URL, e.g.
https://github.com/your-org/your-repo.git - Paste the token in the Access token field
- Check This repository will be a mirror
- Choose an owner and confirm the repo name
- Click Migrate repository
You can convert a token mirror to the GitHub App later from the mirror’s settings page, which removes the stored token.
What syncs
Section titled “What syncs”Mirrors pull all Git refs: branches, tags, and commits. Every sync is a full git remote update.
Mirrors are git-only. Issues, pull requests, labels, milestones, and releases are not imported, even if those options appear in the form. If you need issue history alongside the mirror, do a one-time import first, then delete it and create the mirror into the same name.
Sync interval
Section titled “Sync interval”The default sync interval is eight hours. You can change it per repo:
- Go to Settings > Repository on the mirror repo
- Under Mirror Settings, set the interval (minimum ten minutes)
- Click Save
A shorter interval means fresher data but more traffic to GitHub. For active repos where you want near-real-time redundancy, 15 to 30 minutes works well.
You can also click Synchronize Now on the mirror settings page to trigger an immediate sync.
Change authentication method
Section titled “Change authentication method”You can convert a token-based mirror to the GitHub App without deleting and re-importing. Stars, forks, webhooks, and the repo URL are preserved.
Switch from token to GitHub App
Section titled “Switch from token to GitHub App”- Go to Settings > Repository on the mirror repo
- Under Mirror Settings, click Connect GitHub App
- Complete the GitHub authorization flow
- The stored token is removed. Future syncs mint short-lived tokens automatically
Reconnect a broken GitHub App mirror
Section titled “Reconnect a broken GitHub App mirror”If you uninstall the Codebahn app from GitHub or change its repository access, syncs fail with a notice. To fix it:
- Reinstall the app on GitHub (or update its repository access)
- Go to Settings > Repository on the mirror repo
- Click Reconnect GitHub App
- Authorize on GitHub
Working with a mirror
Section titled “Working with a mirror”A mirror repo looks and works like any other Codebahn repo for reading: browse code, view commit history, compare branches, download archives. CI workflows do not run on mirror repos.
The one difference: you cannot push to a mirror. Git operations are read-only. If you clone the mirror locally and try to push, you get a rejection.
If the source goes down
Section titled “If the source goes down”When GitHub is unreachable, mirror syncs fail and retry on the next interval. The mirror keeps serving whatever it had at the last successful sync.
If you need to push (because GitHub is down and work cannot wait), convert the mirror to a regular repository:
- Go to Settings > Repository on the mirror repo
- Scroll to Danger Zone
- Click Convert to regular repository
- Confirm
This removes the mirror link and makes the repo writable. You can push, open pull requests, and run CI. Your .github/workflows/ files run on Codebahn’s runners without changes. See CI workflows for what works and what to watch for.
After converting: reconcile with GitHub
Section titled “After converting: reconcile with GitHub”When GitHub comes back online, you will have commits on Codebahn that GitHub does not have. To reconcile:
# Add both remotesgit remote add codebahn git@codebahn.net:your-org/your-repo.gitgit remote add github git@github.com:your-org/your-repo.git
# Pull from Codebahn (where you pushed during the outage)git pull codebahn main
# Push to GitHubgit push github mainIf both sides have new commits (someone pushed to GitHub after it recovered, before you reconciled), you will need to merge or rebase as with any diverged branch.
Mirror an entire organization
Section titled “Mirror an entire organization”To mirror many repos at once, use the migration API with a personal access token:
# For each repo, POST to the migration endpointcurl -X POST "https://codebahn.net/api/v1/repos/migrate" \ -H "Authorization: token YOUR_CODEBAHN_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "clone_addr": "https://github.com/your-org/repo-name.git", "auth_token": "YOUR_GITHUB_TOKEN", "repo_name": "repo-name", "repo_owner": "your-codebahn-org", "service": "github", "mirror": true }'Repeat for each repository. The Codebahn CLI does not yet have a bulk mirror command, but the API call above can be scripted.
The GitHub App flow does not support the migration API. For scripted bulk mirrors, use a token.
Limitations
Section titled “Limitations”- Issues and PRs are not included. Mirrors import git refs only. No issues, PRs, labels, milestones, or releases.
- Wiki is not mirrored. Codebahn does not enable wikis.
- LFS objects sync if configured. Set the LFS endpoint in mirror settings if the source repo uses Git LFS.
- Token mirrors: the token must stay valid. If it expires or is revoked, syncs fail. Update the token in Settings > Repository > Mirror Settings. Consider converting to the GitHub App to avoid token rotation entirely.
- GitHub App mirrors: the app must stay installed. If you uninstall the Codebahn app from GitHub, syncs fail. Reinstall the app and click Reconnect in mirror settings.
- CI does not run on mirror repos. Convert to a regular repo first. After conversion,
.github/workflows/files run on Codebahn’s runners.

