← All playbooks
Code hosting migration

GitHub → Azure DevOps

Import a GitHub repo into Azure Repos with a clone URL. You get commits, branches, tags, and files. Issues, pull request discussion, Actions secrets, and pipeline history stay in GitHub.

Typical timeline3 to 10 days10 to 24 hours active work
Statusneeds review
Source profileGitHub Actions secrets docs reviewed 2026-11-03
Destination profileAzure DevOps import-a-Git-repository docs reviewed 2026-11-03
Documentation date
Review window
Evidence3 sources
This route needs review.Use it as a planning baseline, then verify the dated sources and test with representative data before production.
Before you migrate

Should you make this move?

Both platforms have a case. Compare what you gain with what you give up before scheduling the cutover.

Current platform

GitHub

Reasons to stay
  • The largest developer ecosystem combines collaboration, automation, and public discovery
  • Repository-centered workflows keep code, review, and automation close together
Reasons to leave
  • Enterprise planning and governance can require several overlapping GitHub products
  • Advanced governance and automation can become configuration-heavy
New platform

Azure DevOps

What gets better
  • Repos, boards, pipelines, artifacts, and enterprise controls are tightly integrated
  • Repository-centered workflows keep code, review, and automation close together
What gets worse
  • The interface and administration model can feel heavy outside Microsoft-centric organizations
  • Advanced governance and automation can become configuration-heavy
Best of the move

Azure DevOps: Repos, boards, pipelines, artifacts, and enterprise controls are tightly integrated. This removes a major source-side concern: Enterprise planning and governance can require several overlapping GitHub products.

Worst of the move

What you lose: The largest developer ecosystem combines collaboration, automation, and public discovery. What you inherit: The interface and administration model can feel heavy outside Microsoft-centric organizations.

Jump to a section
01At a glance

Know the shape of the move.

Transfer outcome11 features audited
Transfer outcome distributionClean transfer: 0, Partial transfer: 2, Manual rebuild: 6, Not transferred: 3.
Clean0
Partial2
Manual6
Lost3
Mapping route9 of 9 fields have a destination path

This timeline assumes

  • You are moving Git repos into Azure DevOps Services, and Repos is enabled on the project.
  • The importer is a project admin, or has Git project-level Create repository set to Allow.
  • Private GitHub repos can be read with a personal access token. The Azure CLI reads it from AZURE_DEVOPS_EXT_GIT_SOURCE_PASSWORD_OR_PAT.
  • The site already documents GitHub → GitLab and GitHub → Bitbucket.
02What transfers

What survives the move.

“Partial” and “manual” are not footnotes. They are work that must be scheduled and verified.

ItemOutcomeImpactWhat happensMitigation
Git historypartialcriticalAzure DevOps imports a Git repo from a clone URL. Microsoft documents GitHub as a source, along with Bitbucket, GitLab, and other Git hosts. When the import finishes, a branch named main becomes the default. Otherwise the first branch in alphabetical order does.Compare branches and a few commit SHAs after import. Rename the default branch if alphabetical order surprised you.
Private authmanualcriticalFor a private repo, az repos import create needs --requires-authorization and the token in AZURE_DEVOPS_EXT_GIT_SOURCE_PASSWORD_OR_PAT. The target repo must already exist and be empty. Microsoft says to prefer Microsoft Entra tokens when you can.Use a fine-grained token that can read the repo. Revoke it after the import.
Issues and pull requestslostcriticalAzure DevOps imports a Git clone URL. GitHub's backup doc treats a mirror clone as a backup of the Git repository. Issues and pull request conversation are not in that clone, so they stay on GitHub.Export issues if you still need them and map them into Boards as its own project. Do not tell the team that history came with the clone.
Workflow filespartialhigh.github/workflows is just files, so it arrives with the repo. Azure Pipelines will not run those workflows until you create a pipeline.Add a pipeline that points at the YAML you intend to keep, or translate it.
Actions secretslostcriticalGitHub's list-secrets API returns repository, environment, and organization secret names and does not reveal the encrypted values. Those values are not in the Git history Azure DevOps imports.Recreate secrets in Azure Pipelines from the password manager. Do not try to extract them from GitHub.
Actions run historylostmediumLogs and artifacts from past workflow runs stay in GitHub. A clone does not include them.Download any log you still need for an audit before you archive the GitHub repo.
Branch policies and permissionsmanualhighGitHub rulesets and required reviewers do not become Azure DevOps policies. Microsoft's import article is about Git data. Permissions on the new repo are whatever the project already applies.Rebuild required reviewers and build validation before you let the team push.
GitHub Apps and webhooksmanualhighApps installed on the GitHub repo do not follow the clone. Service connections in Azure DevOps are new objects.List webhooks. Recreate the ones that should fire on Azure Repos.
Wikis and packagesmanualmediumA GitHub wiki is its own Git repo when you use the wiki git endpoint. Packages in GitHub Packages are not commits in the source repo.Import the wiki repo separately if you use it. Republish packages.
Empty-repo rulemanualhighImport into an existing repo only works when that repo is empty. Import into a new repo is the other path, from Repos > Files > Import repository.Create a new repo, or confirm the target has no commits.
People and licensesmanualhighGitHub users are not Azure DevOps users. Microsoft says private-project readers need at least Basic access, and contributors need the Contributors group or equivalent.Add the team and check access before you change the remote.
03Field and feature mapping

Where each thing goes.

SourceDestinationMethodNotes
Clone URLImported Azure RepoautomaticPublic repos can import from the URL. Private repos need a token.
Branch mainDefault branchautomaticMicrosoft sets main as default when that branch exists.
Other branches and tagsBranches and tagsautomaticThey are part of the Git import. Verify the list.
CommitCommitautomaticCompare a SHA from GitHub with Azure Repos.
.github/workflows fileFile in the repo, not a running pipelinetransformThe YAML arrives with the Git data. Create the Azure Pipeline yourself.
Actions secretPipeline secretmanualGitHub will not show you the value. Enter it from your vault.
Issue or pull requestAzure Boards work itemmanualNot included in the Git clone.
RulesetBranch policymanualRebuild required checks.
WebhookService hookmanualRecreate it and send a test event.
04Before you begin

Make the move recoverable.

Backup procedure

Create the source-of-truth backup

Keep GitHub as the remote of record until Azure Repos matches the branches you need.

  1. List repos, default branches, and which ones are private.
  2. Write down rulesets, environments, and secret names. You cannot export secret values.
  3. Clone --mirror to a machine you control for the repos that matter.
  4. Export issues if Boards must carry them.
  5. Leave GitHub unlocked until developers have pushed once to Azure Repos.

Proof to capture: A mirror clone exists, and secret names are listed without values.

Transformation · Repos > Import repository, or az repos import

Repo import

Copy Git data into an empty Azure Repo.

  1. Create the Azure DevOps project and an empty repo if you are using the CLI.
  2. Paste the HTTPS clone URL. For a private repo, set the token env var and pass --requires-authorization.
  3. Wait until the import finishes.
  4. Check the default branch. If there was no main, Azure picks the first name alphabetically.

Proof to capture: Save the input, output, command or tool settings, warnings, and final item counts.

Transformation · Azure Pipelines and branch policies

Pipeline and policy

Make the imported YAML actually run, with secrets and reviewers.

  1. Create a pipeline pointed at the YAML you are keeping.
  2. Add secrets from the vault. GitHub cannot display the old values.
  3. Add branch policies that match the rulesets you still want.
  4. Run the pipeline once on a non-production branch.

Proof to capture: Save the input, output, command or tool settings, warnings, and final item counts.

05Handle with care

The things most likely to hurt.

These are operating limits. Treat every “Stop if” condition as a blocked migration, not a suggestion.

Cutover

The team thinks issues moved

criticallikely likelihood

The repo import succeeds and someone archives GitHub.

Consequence
Issue and pull request history is stuck in an archived GitHub repo.
Mitigation
Say, in the announcement, that Git data moved and issues did not.

Stop if: GitHub is about to be archived and Boards is empty.

Pilot

Secrets are assumed to copy

criticallikely likelihood

The pipeline YAML references secret names that Azure does not have.

Consequence
The first run fails, or worse, someone pastes a secret into a yaml file.
Mitigation
Enter secrets in the pipeline UI. Fail the run on a staging branch first.

Stop if: A secret value is committed to the repo.

Pilot

Default branch is not the one you ship

highpossible likelihood

The repo has no branch named main.

Consequence
Azure DevOps checks out the alphabetically first branch.
Mitigation
Look at the default branch before anyone clones.

Stop if: The default branch is not the one you release from.

06Precise timeline

Do the work in this order.

Estimate forA handful of GitHub repos, private or public, whose issues can stay in GitHub or move later
Total elapsed3 to 10 days
Active work10 to 24 hours
BufferAdd time when every issue and pull request must land in Boards, or when dozens of secret names have no vault entry.
01
Days 1 to 2Repos, secrets, rules1 to 2 days
02
Days 2 to 3Mirrors1 day
03
Days 3 to 6One repo2 to 3 days
04
Days 6 to 8Remotes1 to 2 days
05
Days 8 to 15Leave GitHub readable7 days
  1. Days 1 to 2 · inventory

    Repos, secrets, rules

    3 to 6 hours active1 to 2 days elapsedOwners name the systems of record waiting
    • List repos and default branches.
    • List secret names and rulesets. Decide where issues live.

    Depends on: GitHub admin and Azure DevOps project admin

    Stop / go checkpoint

    Import Git?

    Go when: Issues have a home that is not 'they come with the clone'.

    Stop when: Nobody can create a repo in the project.

  2. Days 2 to 3 · backup

    Mirrors

    2 to 4 hours active1 day elapsedClone waiting
    • git clone --mirror the important repos.
    • Export issues if Boards needs them.

    Depends on: Inventory

    Stop / go checkpoint

    Import to Azure?

    Go when: The mirror has the branches you listed.

    Stop when: A private repo clone failed auth.

  3. Days 3 to 6 · pilot

    One repo

    4 to 8 hours active2 to 3 days elapsedImport waiting
    • Import one repo.
    • Check SHAs and the default branch.
    • Create a pipeline and a secret. Run it.

    Depends on: Empty target repo

    Stop / go checkpoint

    Import the rest?

    Go when: SHA sample matches and the pipeline ran without a committed secret.

    Stop when: The default branch is wrong or the token was too broad to revoke.

  4. Days 6 to 8 · cutover

    Remotes

    2 to 5 hours active1 to 2 days elapsedDeveloper clones waiting
    • Import remaining repos.
    • Tell people the new remote.
    • Turn on branch policies.

    Depends on: Pilot

    Stop / go checkpoint

    Azure Repos is the remote?

    Go when: A pull request policy blocks a direct push, if that is what you wanted.

    Stop when: Issues were supposed to move and Boards is empty.

  5. Days 8 to 15 · observe

    Leave GitHub readable

    2 to 4 hours active7 days elapsedThe team pushes waiting
    • Watch failed pipelines.
    • Keep GitHub readable.

    Depends on: Remotes updated

    Stop / go checkpoint

    Archive GitHub?

    Go when: A week of commits landed in Azure Repos and secret runs succeeded.

    Stop when: Someone still opens pull requests only on GitHub.

07The point of change

Cut over with a way back.

Go live

Cutover

Developers push to Azure Repos. GitHub stays readable until you archive it on purpose.

Recommended window: The start of a day when the team can update remotes, not the middle of a release.

  1. Finish imports and check default branches.
  2. Put secrets in Pipelines.
  3. Enable branch policies.
  4. Change the documented remote.
  5. Stop opening new GitHub pull requests. Leave the old ones readable.

Proof to capture: New commits appear in Azure Repos, policies are on, and GitHub was not archived.

Return to safety

Rollback

Make GitHub the remote again. The import did not delete it.

Deadline: Before you archive the GitHub org or delete the mirror.

  1. Tell the team to push to GitHub.
  2. Cherry-pick or push any Azure-only commits back to GitHub.
  3. Disable the Azure pipeline if it is deploying from the wrong history.
  4. Leave the imported repo in place until you delete it deliberately.
  5. Revoke the GitHub token either way.

Proof to capture: GitHub has the latest commits you care about and Azure is not deploying them by accident.

Rollback immediately when
  • Default branch is wrong
  • A secret was committed
  • Issues were assumed to have moved
  • The import token is still valid after cutover
  • Branch policy blocks a release you still have to ship from GitHub
08Verification report

Prove the migration worked.

Every blocking check must pass. Capture the evidence before cleanup begins.

0%
Interactive report preview0 / 8 checks passed
PassIDCheckMethodExpected resultEvidence
V-01BlockingSHA sampleCompare five commit SHAs, including the tip of the release branch.They match GitHub.SHA list.
V-02BlockingDefault branchRead the default branch in Azure Repos.It is the branch you release from, not an alphabetical accident.Repo settings.
V-03BlockingRelease tagsList tags on both hosts.The tags you ship are present.Tag list.
V-04BlockingPipeline runRun the pipeline on a non-production branch.Secrets resolve and none are in the Git commit.Pipeline log with secrets masked.
V-05BlockingDirect pushTry a push that should be blocked.The policy rejects it.Push error.
V-06BlockingBoards expectationOpen Boards and GitHub issues side by side.The team knows which one is the system of record.Announcement.
V-07BlockingToken revokedConfirm the GitHub token used for import is revoked or expired.It cannot read the repo.Token list.
V-08BlockingA contributorClone as a user who is not a project admin.They can clone and push within policy.Clone test.
09Post-migration cleanup

Remove the scaffolding safely.

Safe after: A week of commits in Azure Repos and a revoked import token.

  1. Revoke the GitHub token.
  2. Archive GitHub only after issues and old pull requests have a stated home.
  3. Delete empty failed import repos.
  4. Remove the mirror from laptops that should not keep a second copy.
  5. Store pipeline secrets only in Azure Pipelines.
  6. Review branch policies when the next repo is imported.
Sources and evidence

Verify against the primary material.

Platform behavior changes. Check these sources and the review dates above before executing a production migration.

  1. Azure DevOps: import a Git repositoryAccessed 2026-11-03
  2. GitHub REST: Actions secretsAccessed 2026-11-03
  3. GitHub: back up a repositoryAccessed 2026-11-03