Enterprise live migrations (ELM)
May 19, 2026 ยท View on GitHub
The az devops migrations command group (Preview) manages enterprise live migrations for repositories.
Availability may be limited (for example, to 1P/allowlisted users).
Prerequisites
- Azure DevOps CLI with the Azure DevOps extension installed.
- Sign in using
az loginoraz devops login. - Configure a default org once to avoid repeating
--org:
az devops configure --defaults organization=https://dev.azure.com/myorg
- You can still override per command with
--org. - If your current git remote points to another org, add
--detect falseto avoid auto-detect choosing the wrong organization.
Migration lifecycle model
Typical active stages:
queued -> validation -> synchronization -> cutover
Key fields in status output:
statusRequested: Desired state requested by the CLI (for example,active,suspended).status: Service-reported status (for example,succeeded,failed).stage: Current running stage while active.
Use all three fields together when troubleshooting state transitions.
Required inputs
--repository-idis the Azure Repos repository GUID.--target-repositoryis the target repository URL.--github-tokenis optional for create. If not provided, the CLI checksELM_GITHUB_TOKENand then runs GitHub device flow.--target-owner-user-idis deprecated and ignored when server-side token ownership resolution is enabled.--agent-poolis optional for create.--cutover-date/--datemust be ISO 8601, for example:2030-12-31T11:59:00Z.--skip-validationaccepts either comma-separated policy names or a non-negative integer bitmask.
Validation enforced by the CLI:
--target-repositorymust start withhttp://orhttps://.--repository-idmust be a valid GUID.--skip-validationpolicy names must be recognized values.
How to find --repository-id
az repos show --repository MyRepo --project MyProject --query id -o tsv
Command reference
list: List migrations for the org. Use--include-inactiveto include completed/failed/suspended migrations. Use--projectto filter by project name or ID.status: Show migration status for a repository GUID.create: Create a migration. Use--validate-onlyfor pre-migration checks only.pause: Pause an active migration.resume: Resume a stopped (paused, failed) migration. Optional flags are--validate-only(resume in validate-only mode) and--migration(promote a succeeded validate-only migration to full migration by settingvalidateOnly=falseandstatusRequested=active). If a migration is currently active, pause it before resuming or switching mode.cutover set/cutover cancel: Schedule or cancel cutover.abandon: Abandon and delete a migration.
Status fields
statusRequested: Desired state requested by client.status: Current overall status reported by service.stage: Current active stage (for example, validation, synchronization, cutover).
If a command is blocked, inspect all three fields from status output to understand whether the migration is active, terminal, or promotable.
Promotion semantics
When validation succeeds in validate-only mode, promotion does not create a new migration.
Promotion command:
az devops migrations resume --org https://dev.azure.com/myorg \
--repository-id 00000000-0000-0000-0000-000000000000 --migration
What this does:
- Sends an update (PUT) to the existing migration.
- Sets
validateOnly=false. - Sets
statusRequested=active.
Common workflows
List migrations
az devops migrations list --org https://dev.azure.com/myorg
List migrations for a project
az devops migrations list --org https://dev.azure.com/myorg --project MyProject
List all migrations including inactive
az devops migrations list --org https://dev.azure.com/myorg --include-inactive
Check migration status
az devops migrations status --org https://dev.azure.com/myorg \
--repository-id 00000000-0000-0000-0000-000000000000
Create a migration
az devops migrations create --org https://dev.azure.com/myorg \
--repository-id 00000000-0000-0000-0000-000000000000 \
--target-repository https://example.ghe.com/OrgName/RepoName \
--agent-pool <your-agent-pool>
Create a validate-only migration
az devops migrations create --org https://dev.azure.com/myorg \
--repository-id 00000000-0000-0000-0000-000000000000 \
--target-repository https://example.ghe.com/OrgName/RepoName \
--agent-pool <your-agent-pool> \
--validate-only
Create a migration using explicit token or PAT
az devops migrations create --org https://dev.azure.com/myorg \
--repository-id 00000000-0000-0000-0000-000000000000 \
--target-repository https://example.ghe.com/OrgName/RepoName \
--github-token <token>
Create a migration with skip-validation
Recommended form using policy names:
az devops migrations create --org https://dev.azure.com/myorg \
--repository-id 00000000-0000-0000-0000-000000000000 \
--target-repository https://example.ghe.com/OrgName/RepoName \
--skip-validation AgentPoolExists,MaxFileSize
Advanced form using integer bitmask:
az devops migrations create --org https://dev.azure.com/myorg \
--repository-id 00000000-0000-0000-0000-000000000000 \
--target-repository https://example.ghe.com/OrgName/RepoName \
--skip-validation 132
Pause and resume
az devops migrations pause --org https://dev.azure.com/myorg \
--repository-id 00000000-0000-0000-0000-000000000000
az devops migrations resume --org https://dev.azure.com/myorg \
--repository-id 00000000-0000-0000-0000-000000000000
az devops migrations resume --org https://dev.azure.com/myorg \
--repository-id 00000000-0000-0000-0000-000000000000 --validate-only
az devops migrations resume --org https://dev.azure.com/myorg \
--repository-id 00000000-0000-0000-0000-000000000000 --migration
Promote a succeeded validate-only migration
After validation succeeds, run:
az devops migrations resume --org https://dev.azure.com/myorg \
--repository-id 00000000-0000-0000-0000-000000000000 --migration
This promotes the same migration record (no new migration is created).
If you receive an active-state error, pause first and retry:
az devops migrations pause --org https://dev.azure.com/myorg \
--repository-id 00000000-0000-0000-0000-000000000000
Schedule or cancel cutover
az devops migrations cutover set --org https://dev.azure.com/myorg \
--repository-id 00000000-0000-0000-0000-000000000000 \
--date 2030-12-31T11:59:00Z
az devops migrations cutover cancel --org https://dev.azure.com/myorg \
--repository-id 00000000-0000-0000-0000-000000000000
Abandon a migration
az devops migrations abandon --org https://dev.azure.com/myorg \
--repository-id 00000000-0000-0000-0000-000000000000
Troubleshooting
- Error: migration is active. Pause first, then retry resume or mode changes.
az devops migrations pause --org https://dev.azure.com/myorg \
--repository-id 00000000-0000-0000-0000-000000000000
-
Error: validation already succeeded. Use
resume --migrationto promote instead of re-running validate-only. -
Error:
--target-repositorymust be valid. Ensure it is a fully qualified URL starting withhttp://orhttps://. -
Error: missing GitHub token or device-flow setup. Pass
--github-token, setELM_GITHUB_TOKEN, or complete the interactive GitHub device-flow prompt shown by CLI. -
Error:
--skip-validationcontains unsupported policy names. Use supported names such asAgentPoolExists,MaxFileSize, or pass a non-negative integer bitmask. -
Error: requests are sent to the wrong org. Use
--org <url> --detect false, and verify defaults viaaz devops configure -l. -
Error: migration already succeeded. Use
abandonto reset before creating a new migration. -
Error: active migration already exists for repository. The create command returns:
"An active migration already exists for repository <GUID>. Delete (abandon) the existing migration before creating a new one."This means a non-terminal migration already exists for that repository GUID. Abandon it first, then retry create.
az devops migrations abandon --org https://dev.azure.com/myorg \
--repository-id 00000000-0000-0000-0000-000000000000
az devops migrations create --org https://dev.azure.com/myorg \
--repository-id 00000000-0000-0000-0000-000000000000 \
--target-repository https://example.ghe.com/OrgName/RepoName