What breaks when you move a GitHub repo
By Matthew Gray on Oct 6, 2026
Transferring a repository to another GitHub organization looks like a single button, and for history, issues and pull requests it is. What breaks is everything outside the repository that refers to it by owner and name: cloud logins, tokens, infrastructure code and deployment controllers. The fix is to find those references first and change them in the right order, so nothing fails on transfer day.
We are planning a move like this now, for two repositories with live CI/CD into several environments. This post describes the pattern, not a finished result. The dependencies below came from a read-only scan of the repository before anything moved, which is the step we would recommend to anyone.
What GitHub carries over, and what it does not
A transfer keeps git history, issues, pull requests, and repository- and environment-level secrets and variables, and GitHub redirects the old URL to the new one. That is a lot, and it makes the move feel safe.
What it cannot carry is anything that lives at the organization level, or anything in another system that names the old owner. Organization rulesets, organization secrets and variables, installed GitHub Apps and organization runners belong to the source organization and stay there. And every external trust relationship that was written as old-owner/repo is now pointing at a name that no longer matches.
The hidden dependencies
| Dependency | Symptom after the move | Fix |
|---|---|---|
OIDC federated credentials in your cloud, subject repo:<owner>/<repo>:environment:<env> | Every cloud login step in CI fails | Add new subjects before the move; remove old ones after verification |
| Personal or organization-scoped access tokens used by workflows | Runner management, infrastructure applies and API calls fail | Replace with a GitHub App installed on the new organization, scoped to the repositories it needs |
Terraform or OpenTofu GitHub provider with a literal owner | Plan targets the wrong owner and wants to recreate environments, variables and secrets | Make the owner a variable; review the plan; use state moves or imports instead of replacement |
Argo CD repoURL pointing at the old path | Works through the redirect, until it doesn’t | Update repoURL and repository credentials explicitly |
| Hard-coded owner/repo in CI scripts and tests | Scripts call the API at the old path | Derive from GITHUB_REPOSITORY or one variable |
| Self-hosted runners | Jobs queue with no runner | Confirm after the move; re-register if they did not follow |
| Organization rulesets, secrets, variables and Apps | Protections and integrations silently absent | Inventory beforehand; re-create or re-install |
| Other clouds’ federation subjects | Deploys to that cloud fail | Update the subject the same way as the first cloud |
OIDC subjects: add first, remove last
Workload identity federation is the right way to let GitHub Actions sign in to a cloud, because there is no stored secret. But the trust is pinned to the subject claim GitHub puts in the token, and that claim includes the owner:
repo:<owner>/<repo>:environment:<env>
After the transfer, the token carries the new owner and the cloud rejects it. The safe sequence is to add a federated credential for the new subject in every environment while the repository is still in the old organization. Both subjects are trusted for a short window. Once the moved repository has signed in successfully everywhere, delete the old subjects. If you manage identities with infrastructure code, parameterize the owner so the change is a variable, not an edit in several places.
Check every cloud. A second provider with its own federation, such as a container platform on another cloud, has its own subject naming the old owner and will fail the same way.
Tokens: replace them with a GitHub App
Workflows that manage runners, environments or secrets often use a personal access token created by someone in the old organization. After the move, that token either stops working or, worse, keeps working and keeps the old organization’s access to the new one’s resources.
Create the replacement in the new organization before the move. A GitHub App installed on the new organization is preferable to a personal token: it is not tied to a person, its permissions can be limited to exactly what the workflows use (for example Actions, runner administration, environments, secrets and variables), and it can be installed on only the repositories that need it. Stage it as a new secret, switch workflows over on the day, then revoke the old token.
Infrastructure code: read the plan before you trust it
If the repository manages its own GitHub settings with Terraform or OpenTofu, the GitHub provider’s owner is often a literal string. Change it, and the provider looks for environments and secrets in a different organization, does not find them, and plans to create new ones while the old state entries plan to be destroyed.
Make the owner a variable, then run a plan in every environment with the new owner before the transfer and read every github_* change. Where the plan wants to replace something that will exist after the move, reconcile state instead:
# re-point state at the resource as it will exist after the move
tofu state rm 'github_repository_environment.this["prd"]'
tofu import 'github_repository_environment.this["prd"]' '<repo>:prd'
Use tofu state mv where only the address changes. The goal is a drift run after the move that shows no GitHub replacements at all.
Argo CD: don’t rely on the redirect
Argo CD will keep syncing from the old URL because GitHub redirects it. That is fragile for two reasons. The redirect disappears if anyone creates a repository with the old name at the old owner. And Argo CD matches repository credentials by URL, so a credential registered for the new URL will not be used for the old one. Update repoURL in each application explicitly, update the credential, and sync a non-production environment first.
Hand over artifacts, not source access
Sometimes a moved repository builds something from source that belongs to the old organization, such as a shared identity service. Keeping that build means leaving a credential to the old organization’s source inside the new one, which is usually the opposite of what the move is for.
The cleaner pattern is to hand over deployable artifacts. The source organization signs its images in CI with keyless cosign and grants a pull-only token scoped to that one registry repository, with a deliberate expiry date. The receiving pipeline pulls by digest and verifies the signature against the expected signer before deploying:
cosign verify \
--certificate-identity "https://github.com/<owner>/<repo>/.github/workflows/<sign>.yml@refs/heads/main" \
--certificate-oidc-issuer "https://token.actions.githubusercontent.com" \
<registry>/<image>@sha256:<digest>
Check the identity once against a real signed image before relying on it, because a small difference in workflow path or ref will fail verification.
Transfer day and verification
Freeze merges and pause any automation that merges or reviews. Transfer, switch workflows to the new credential, set the new owner variable, update Argo CD, re-create the organization-level items from your inventory, and confirm the runners. Then verify with real work: a trivial pull request runs CI green, a deploy to a non-production environment succeeds, an infrastructure drift run is clean, and the new organization holds no credential to anything it should not reach. Only then remove the old OIDC subjects and revoke the old token.
How we can help
We plan and run platform moves like this one, starting with a read-only scan for every place the platform names itself. See our services for how we scope platform reliability work.