Skip to main content
Skip to content

Migrating repositories between two data-resident enterprises

You can use the GitHub Enterprise Importer (GEI) extension for GitHub CLI to migrate repositories between two instances of Nube de GitHub Enterprise con residencia de datos.

About migrations between data-resident enterprises

Migrations between two data-resident enterprises use the standard GEI archive migration flow:

  1. GEI connects to the source GHE.com subdomain.
  2. GEI generates an archive containing the repository data.
  3. GEI uploads the archive to supported migration storage.
  4. GEI starts the repository migration on the destination GHE.com subdomain.
  5. The destination Importer downloads and processes the archive.

In this migration:

  • The source is a GHE.com subdomain, such as https://SOURCE_SUBDOMAIN.ghe.com.
  • The destination is a different GHE.com subdomain, such as https://DESTINATION_SUBDOMAIN.ghe.com.
  • The source and destination organizations can have different names.
  • The migrated repository can have a different name in the destination organization.

The source and destination API endpoints must be specified independently. Do not use the destination API URL for source operations.

Importante

Nube de GitHub Enterprise con residencia de datos API URLs use the format https://api.SUBDOMAIN.ghe.com. This is different from a GitHub Enterprise Server API URL, which typically uses the format https://HOSTNAME/api/v3.

Prerequisites

Before you begin:

  • Confirm that the source and destination are different GHE.com subdomains.
  • In both the source and destination organizations, ensure that you are an organization owner or have been granted the migrator role.
  • Create a personal access token (classic) for the source organization.
  • Create a personal access token (classic) for the destination organization. For required scopes, see Administración del acceso para una migración entre productos de GitHub.
  • Run a trial migration before performing the production migration.

We recommend temporarily stopping work on the source repository during the production migration. GitHub Enterprise Importer does not perform delta migrations, so changes made after the migration starts are not included automatically.

For information about the data migrated and known limitations, see Acerca de las migraciones entre productos de GitHub con GitHub Enterprise Importer.

Install the GitHub CLI and GEI

Install the GitHub CLI, then install the GEI extension:

Bash
gh extension install github/gh-gei

Update the extension before starting a migration:

Bash
gh extension upgrade github/gh-gei

To display the available options:

Bash
gh gei migrate-repo --help

Set environment variables

Set the personal access tokens for both enterprises:

Bash
export GH_SOURCE_PAT="SOURCE_PERSONAL_ACCESS_TOKEN"
export GH_PAT="DESTINATION_PERSONAL_ACCESS_TOKEN"

Set the API URL for each GHE.com subdomain:

Bash
export SOURCE_API_URL="https://api.SOURCE_SUBDOMAIN.ghe.com"
export TARGET_API_URL="https://api.DESTINATION_SUBDOMAIN.ghe.com"

Replace SOURCE_SUBDOMAIN and DESTINATION_SUBDOMAIN with the subdomains of your source and destination enterprise.

For example:

Bash
export SOURCE_API_URL="https://api.source-example.ghe.com"
export TARGET_API_URL="https://api.destination-example.ghe.com"

The GH_SOURCE_PAT token is used for source-side operations, including archive generation. The GH_PAT token is used for destination-side operations.

Configure archive blob storage

GitHub Enterprise Importer exports each project to an archive, then uploads the archive to blob storage that GitHub can read from. You choose the storage backend when you run a migration:

Storage optionHow to select itNotes
GitHub-owned blob storage (recommended)--use-github-storageNo setup required. GitHub deletes the archive automatically after a successful migration, or seven days after a failed migration.
AWS S3--aws-bucket-name (with the AWS_REGION, AWS_ACCESS_KEY_ID, and AWS_SECRET_ACCESS_KEY environment variables, and optionally AWS_SESSION_TOKEN)You own the bucket and its lifecycle. GitHub does not delete archives from your storage.
Azure Blob StorageAZURE_STORAGE_CONNECTION_STRING environment variable (for a single migrate-repo command, you can instead use --azure-storage-connection-string)Only storage-account access-key connection strings are supported (not SAS). GitHub does not delete archives from your storage.

Migrate a single repository

To migrate a single repository, use the gh gei migrate-repo command:

Bash
gh gei migrate-repo \
  --github-source-org SOURCE_ORGANIZATION \
  --source-repo SOURCE_REPOSITORY \
  --github-source-api-url "$SOURCE_API_URL" \
  --github-target-org DESTINATION_ORGANIZATION \
  --target-repo DESTINATION_REPOSITORY \
  --target-api-url "$TARGET_API_URL" \
  --verbose

Replace the placeholders with the following values:

PlaceholderDescription
SOURCE_ORGANIZATIONThe organization that owns the repository in the source enterprise.
SOURCE_REPOSITORYThe name of the repository in the source organization.
DESTINATION_ORGANIZATIONThe organization that will own the migrated repository in the destination enterprise.
DESTINATION_REPOSITORYThe name of the new repository in the destination organization.

For example:

Bash
gh gei migrate-repo \
  --github-source-org source-org \
  --source-repo example-repository \
  --github-source-api-url "$SOURCE_API_URL" \
  --github-target-org destination-org \
  --target-repo example-repository \
  --target-api-url "$TARGET_API_URL" \
  --verbose

If you omit --target-repo, GEI uses the source repository name.

Optional arguments

You can add the following options to the migration command:

ArgumentDescription
--target-repo-visibility TARGET-VISIBILITYSets the visibility of the new repository. Supported values are private and internal.
--skip-releasesMigrates the repository without releases.
--queue-onlyQueues the migration without waiting for it to complete.
--verboseDisplays additional migration output.

For example:

Bash
gh gei migrate-repo \
  --github-source-org source-org \
  --source-repo example-repository \
  --github-source-api-url "$SOURCE_API_URL" \
  --github-target-org destination-org \
  --target-repo example-repository \
  --target-api-url "$TARGET_API_URL" \
  --target-repo-visibility internal \
  --verbose

Migrate multiple repositories

For multiple repositories, use gh gei generate-script.

Bash
gh gei generate-script \
  --github-source-org SOURCE_ORGANIZATION \
  --github-target-org DESTINATION_ORGANIZATION \
  --github-source-api-url "$SOURCE_API_URL" \
  --target-api-url "$TARGET_API_URL" \
  --output migration-script.ps1

Review the generated script before running it. You can:

  • Remove repositories that should not be migrated.
  • Change destination repository names.
  • Change destination repository visibility.
  • Add options such as --skip-releases.
  • Add --download-migration-logs to download logs for each migration.

Run the generated script with PowerShell:

Bash
pwsh ./migration-script.ps1

Check the status of a migration

If you started the migration with --queue-only, use the migration ID printed by GEI to monitor it:

Bash
gh gei wait-for-migration \
  --migration-id MIGRATION_ID \
  --target-api-url "$TARGET_API_URL" \
  --verbose

Replace MIGRATION_ID with the ID returned by gh gei migrate-repo.

Nota:

Include both API URL arguments when checking. The source API URL is required for GEI commands that retrieve source-side migration information and logs.

Download migration logs

To download the migration logs:

Bash
gh gei download-logs \
  --migration-id MIGRATION_ID \
  --github-source-api-url "$SOURCE_API_URL" \
  --target-api-url "$TARGET_API_URL"

Review the logs for warnings and errors even when the migration reports success.

Abort a migration

To abort a queued or running migration:

Bash
gh gei abort-migration \
  --migration-id MIGRATION_ID \
  --github-source-api-url "$SOURCE_API_URL" \
  --target-api-url "$TARGET_API_URL"

Troubleshooting

The source tenant cannot be reached

Verify that:

  • --github-source-api-url is set to the source subdomain.
  • The URL uses the format https://api.SUBDOMAIN.ghe.com.
  • The source token is stored in GH_SOURCE_PAT.
  • The token has access to the source organization and repository.

The destination tenant cannot be reached

Verify that:

  • --target-api-url is set to the destination subdomain.
  • The URL uses the format https://api.SUBDOMAIN.ghe.com.
  • The destination token is stored in GH_PAT.
  • You have permission to create repositories in the destination organization.

The migration fails while generating or uploading the archive

Review the migration output and logs, then verify that:

  • Migration archive storage is configured correctly.
  • The storage provider is accessible to the migration service.
  • The source repository is not being modified during the migration.
  • The source and destination API URLs have not been swapped.

Logs cannot be downloaded

When using download-logs, wait-for-migration, or abort-migration, provide the same source and destination API URLs used to start the migration:

--github-source-api-url "$SOURCE_API_URL" \
--target-api-url "$TARGET_API_URL"

The source URL is rejected

Make sure you are using the GHE.com subdomain API endpoint rather than a GitHub Enterprise Server endpoint.

Use:

https://api.SUBDOMAIN.ghe.com

Do not use:

https://HOSTNAME/api/v3

The /api/v3 format is intended for GitHub Enterprise Server sources and is not the correct format for Nube de GitHub Enterprise con residencia de datos.