> ## Documentation Index
> Fetch the complete documentation index at: https://docs.maia.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Repository Migration API

export const maia = "Maia";

<Badge color="yellow" shape="pill" stroke size="lg">Private preview</Badge>

<Note>
  The Repository Migration API is currently available as a private preview for selected customers. To request access to this feature, contact your Matillion account representative.
</Note>

The Repository Migration API lets you move a project's Git repository to a different repository or Git provider without recreating the project. Use these endpoints to send a single request that starts a migration, then poll a status endpoint until the migration is no longer in progress. {maia} migrates the project's working tree to the target repository you specify and updates your project to use the target repository.

<Warning>
  * Migration is an asynchronous, long-running operation. Only one migration can run for a project at any time.
  * While a migration is in progress, all other Git operations on the project's repository are blocked until the migration is no longer in progress.
</Warning>

***

## Prerequisites

Before you begin, you need:

* An existing project that has an associated Git repository. To associate a repository with a project, see [Initialize Repository](/docs/api-reference/provisioning-a-project#initialize-repository).
* A target repository that already exists on the target Git provider. {maia} does not create the target repository for you. The supported target providers are GitHub, GitLab, and Azure DevOps.

If a repository involved in the migration is hosted on Azure DevOps or GitLab, complete the additional setup described below for that provider before starting the migration.

### Azure DevOps

If either the source or target repository is hosted on Azure DevOps, you must:

1. Install the Maia for Azure DevOps application in the Azure tenant that hosts the repository. If the application is already installed in that tenant—for example, because another user has previously connected an Azure DevOps repository to {maia}—you can skip this step. Otherwise, follow [Installing the Maia app in Azure](/docs/guides/installing-matillion-app-azure-devops).
2. Add the {maia} service principal to the Azure DevOps repository, and grant it explicit Read and Force push (rewrite history, delete branches and tags) permissions.

<Warning>
  Migration requires the {maia} service principal to have explicit Force push permission on the repository, in addition to Read. Read and Contribute permissions alone are not sufficient—without Force push, {maia} can't complete a `MIRROR_PUSH` migration.
</Warning>

For details on Azure DevOps access controls, refer to the Microsoft documentation on [permissions and access](https://learn.microsoft.com/en-us/azure/devops/organizations/security/about-permissions).

### GitLab

If the target repository is hosted on GitLab, provide the personal access token for a GitLab service account using the `Git-Provider-Access-Token` request header.

<Note>
  The `Git-Provider-Access-Token` header is optional, and is only required when the target repository is hosted on GitLab.
</Note>

For information on how to acquire and manage a service account personal access token, see [GitLab](/docs/api-reference/provisioning-a-project#gitlab) in the Project Provisioning API.

If the source repository (the project's currently associated repository) is hosted on GitLab, you don't need to provide a token for it—{maia} already holds a valid, automatically rotated personal access token from when the repository was first associated with the project. If that token has expired and {maia} was unable to rotate it automatically, manually provide a new one using [Manually rotate an expired personal access token](/docs/api-reference/provisioning-a-project#manually-rotate-an-expired-personal-access-token) before starting the migration.

***

## Migration modes

Use the `mode` field to choose how the migration runs. The two modes, `MIRROR_PUSH` and `RECONFIGURE`, are explained in the table below.

| Mode          | Description                                                                                                                                                                                                                                                                                                                                                            |
| ------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `MIRROR_PUSH` | {maia} copies the project's full working tree—including all branches and tags—to the target repository, then updates the project to use the target. Use this mode to move your project history into an empty target repository. The target clone URL must be different from the project's current repository.                                                          |
| `RECONFIGURE` | {maia} updates the project to use the target repository *without* copying any content to the target repository. Use this mode when the target repository already contains the project's history—for example, if you have manually mirrored the repository yourself. The target repository must already contain every branch that exists in the project's working tree. |

***

## Start a repository migration

Use this endpoint to start an asynchronous migration of the project's Git repository to the target repository. This request returns a `migrationId` that you can use to track the progress of this migration.

### Request headers

| Header                      | Required | Description                                                                                                                                                                                  |
| --------------------------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `Authorization`             | Yes      | A bearer token used to authenticate the request.                                                                                                                                             |
| `Git-Provider-Access-Token` | No       | The personal access token for a GitLab service account. Required only if the target repository is hosted on GitLab. Not required for a GitLab source repository—see [GitLab](#gitlab) above. |

### Request fields

| Field                     | Required | Description                                                                                                                                                                                              |
| ------------------------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `mode`                    | Yes      | The [migration mode](#migration-modes), either `MIRROR_PUSH` or `RECONFIGURE`.                                                                                                                           |
| `targetCloneUrl`          | Yes      | The clone URL of the target Git repository to migrate to.                                                                                                                                                |
| `targetProvider`          | Yes      | The Git provider hosting the target repository, one of `github`, `gitlab`, or `azure-devops`.                                                                                                            |
| `targetName`              | Yes      | The display name of the target repository.                                                                                                                                                               |
| `targetEnterpriseOauthId` | No       | The UUID of the enterprise OAuth connection used to authenticate with the target repository (not required for public or personal repositories).                                                          |
| `providerParameters`      | No       | Provider-specific parameters for the target repository, supplied as key/value pairs. Required for some providers—when migrating to Azure DevOps, provide `organization`, `repositoryId`, and `tenantId`. |

### Example request

Base URL: `POST /v1/projects/{projectId}/repository-migration`

Replace `{projectId}` with your {maia} project ID.

Example request header:

```json theme={null}
{
  "Authorization": "Bearer ey.abc.jwt"
}
```

Example request body:

```json theme={null}
{
  "mode": "MIRROR_PUSH",
  "targetCloneUrl": "https://github.com/acme/new-pipelines.git",
  "targetProvider": "github",
  "targetName": "new-pipelines"
}
```

To migrate to an Azure DevOps repository, include the `providerParameters` object with the organization, repository ID, and tenant ID for the target repository:

```json theme={null}
{
  "mode": "MIRROR_PUSH",
  "targetCloneUrl": "https://dev.azure.com/my-azure-organization/my-project/_git/new-pipelines",
  "targetProvider": "azure-devops",
  "targetName": "new-pipelines",
  "providerParameters": {
    "organization": "my-azure-organization",
    "repositoryId": "existing-repo-id",
    "tenantId": "00000000-0000-0000-0000-000000000000"
  }
}
```

If the target repository is hosted on GitLab, include the `Git-Provider-Access-Token` header in your request, in addition to `Authorization`:

```json theme={null}
{
  "Authorization": "Bearer ey.abc.jwt",
  "Git-Provider-Access-Token": "<service-account-personal-access-token>"
}
```

Example success response:

```json theme={null}
HTTP 202 Accepted

{
  "migrationId": "11111111-2222-3333-4444-555555555555"
}
```

***

## Check migration status

Use this endpoint and the `migrationId` returned by the previous request to poll the status of a migration. Repeat this request until the `status` field is no longer `IN_PROGRESS`.

### Example request

Base URL: `GET /v1/projects/{projectId}/repository-migration/{migrationId}`

Replace `{projectId}` with your {maia} project ID and `{migrationId}` with the migration ID returned when you started the migration.

Example request header:

```json theme={null}
{
  "Authorization": "Bearer ey.abc.jwt"
}
```

Example success response:

```json theme={null}
HTTP 200 OK

{
  "migrationId": "11111111-2222-3333-4444-555555555555",
  "status": "IN_PROGRESS",
  "detail": "Cloning source repository"
}
```

The response contains the following fields:

* `migrationId`: The unique identifier of the repository migration.
* `status`: The current status of the migration. The table below explains what each status means.
* `detail`: An optional, human-readable description of the migration's current state, such as a failure reason. This field is only included if this information is available.

| Status        | Description                                                                                                                                                |
| ------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `IN_PROGRESS` | The migration is still running. Continue polling using this endpoint to find out when it finishes.                                                         |
| `COMPLETED`   | The migration finished successfully. The project is now associated with the target repository.                                                             |
| `FAILED`      | The migration did not complete. Check the `detail` field for the reason.                                                                                   |
| `UNKNOWN`     | The migration is in a state that the API does not recognize. Retry your request, and contact your Matillion account representative if the status persists. |

***

## Error responses

If an error occurs, the repository migration endpoints return a `ProblemDetail` response body. The table below explains what the included status code means.

| Status code | Description                                                                                                                                                      |
| ----------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `400`       | The request is invalid—for example, the migration mode or target Git provider is unsupported, or the target repository matches the project's current repository. |
| `403`       | You do not have permission to migrate this project's repository.                                                                                                 |
| `404`       | The project, or the specified migration, could not be found.                                                                                                     |
| `409`       | A repository migration is already in progress for this project. Wait for the existing migration to finish before starting another.                               |
| `500`       | An unexpected error occurred.                                                                                                                                    |
| `504`       | The request timed out.                                                                                                                                           |
