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

# Import from Perforce

> How to import a Perforce depot, with its history, into a new Diversion repository

You can import a Perforce depot into a new Diversion repository, history included.
The import runs on a machine you provide, called the **import host**, which needs network access to your Perforce server.
Your Perforce password stays on the import host; Diversion never receives it.

The Diversion app creates the repository and an API token and generates the configuration file the import host needs.
A script on the import host then runs the import in Docker, checking in with Diversion every 5 minutes.

<Note>
  If you can't run the import yourself (for example, your machines run only Windows), [request a managed import](#request-a-managed-import) instead.
</Note>

## Requirements for the import host

* A Unix machine with `bash` and `cron`
* Docker Engine 20.10 or newer, with the Docker Compose plugin 2.17 or newer
* Network access to your Perforce server and to Diversion over HTTPS
* Optional: `curl` and the AWS CLI. Without them, the script runs them from a container image instead.

## Set up the import in the Diversion app

<Steps>
  <Step title="Open the Perforce import page">
    In the Diversion app, click **New repository** and choose **Import from P4**. You can also choose **Import from Perforce** at the bottom of the repository menu in the breadcrumbs.

    <img src="https://mintcdn.com/diversion-2/1TVJoD7AdabMtZcG/images/p4-import/new-repository-menu.png?fit=max&auto=format&n=1TVJoD7AdabMtZcG&q=85&s=c4cffbe2666cb9ca86b069f931d8f688" alt="New repository menu with Import from P4" style={{width: 'auto', maxWidth: '90%', borderRadius: '1.5rem', border: '.3rem solid #555', boxShadow: '0 0 1rem #888' }} width="359" height="156" data-path="images/p4-import/new-repository-menu.png" />

    <Note>On self-hosted installs, **Import from P4** opens a request form instead, and the Diversion team runs the import for you.</Note>
  </Step>

  <Step title="Download the import script">
    Click **Download p4\_import\_bootstrap.sh**. The script is the same for every import, and you can download it from this page at any time.
  </Step>

  <Step title="Name the new repository">
    The repository name is filled in from the depot name; change it if you like.
    The repository must belong to an organization. If you don't have one yet, you can create it here.
  </Step>

  <Step title="Fill in the import settings">
    See [Import settings](#import-settings) below for what each field does.

    <img src="https://mintcdn.com/diversion-2/1TVJoD7AdabMtZcG/images/p4-import/import-form.png?fit=max&auto=format&n=1TVJoD7AdabMtZcG&q=85&s=44e0b8aa1c9ffeb2578ae3813f4ed3a9" alt="Import from Perforce page with the repository and import settings filled in" style={{width: '90%', borderRadius: '1.5rem', border: '.3rem solid #555', boxShadow: '0 0 1rem #888' }} width="1007" height="1214" data-path="images/p4-import/import-form.png" />
  </Step>

  <Step title="Click 'Create repository and import files'">
    Diversion creates the repository, an API token, and your import configuration.
  </Step>

  <Step title="Download local.env">
    Click **Download local.env**. The file contains the API token, your repository ID and the setup steps.

    <img src="https://mintcdn.com/diversion-2/1TVJoD7AdabMtZcG/images/p4-import/import-result.png?fit=max&auto=format&n=1TVJoD7AdabMtZcG&q=85&s=4f79aecd2e6b9f5772bc65116c6fad0f" alt="API token, Download local.env button and import host setup steps" style={{width: '90%', borderRadius: '1.5rem', border: '.3rem solid #555', boxShadow: '0 0 1rem #888' }} width="1003" height="1146" data-path="images/p4-import/import-result.png" />

    <Warning>
      The API token is shown only once. Download `local.env` before you leave the page — if you leave without it, see [Recover a lost local.env](#recover-a-lost-local-env).
    </Warning>
  </Step>
</Steps>

### Import settings

| Field | What it does |
| - | - |
| **Depot to import** | The whole depot, as `//depot/...`. No spaces, `#` or `@`. To import only some branches, use **Branches to import**. |
| **Depot type** | **Stream depot** if branches are streams; **Local (classic) depot** if branches are defined by path. |
| **Branch name depth** | Local depots only, and only when **Branches to import** is empty. Leave empty to find branches from the depot's branch specs. Otherwise, every folder this many levels below the depot root becomes a branch: with `1`, `//depot/main/...` is the branch `main`; with `2`, `//depot/dev/feature/...` is the branch `dev/feature`. Use `0` to import the whole depot as one branch. |
| **Is there more than one mainline in the depot?** | A Diversion repository holds one mainline and its descendants. If the depot has several, answer **Yes** and name the one to import in **Mainline branch**. Each other mainline needs its own repository. |
| **Branches to import** | Optional. Comma-separated branch names with no spaces, such as `main,dev`. All names must have the same depth. Leave empty to import all branches. |
| **Path to exclude** | Optional. A depot path prefix, such as `//depot/builds/`. Files under it are not imported. |

## Protect local.env

`local.env` holds an API token with **admin access to your Diversion account**.
Treat it like a password:

* Keep it only on the import host, readable only by the user that runs the import (`chmod 600 local.env`, as in the steps below).
* Don't commit it to version control, share it in chat or email, or copy it to other machines.

## Run the import on the import host

Run these steps as the user that will run the import — a user with access to Docker. Don't use `sudo`: it would install the schedule in root's crontab.

<Steps>
  <Step title="Put both files in one directory">
    Copy `p4_import_bootstrap.sh` and `local.env` into the same directory on the import host, for example `/opt/dv-p4-import`, and `cd` into it.
  </Step>

  <Step title="Make the script executable">
    ```bash theme={null}
    chmod +x p4_import_bootstrap.sh
    ```
  </Step>

  <Step title="Fill in your Perforce settings">
    Open `local.env` and fill in the Perforce connection at the bottom of the file:

    ```bash theme={null}
    P4PORT=perforce.example.com:1666
    P4USER=import-user
    P4PASSWD=...
    ```

    Leave `API_DOMAIN`, `API_TOKEN` and `REPO_ID` as generated.
  </Step>

  <Step title="Protect local.env">
    ```bash theme={null}
    chmod 600 local.env
    ```
  </Step>

  <Step title="Run the script once to check the setup">
    ```bash theme={null}
    ./p4_import_bootstrap.sh
    ```

    A successful first run downloads your import configuration, pulls the Diversion import image and starts it.
    The output includes a line like `Remote env changed -- recreating: ...`, and `docker ps` shows the import container running.
    The first run can take a few minutes while images download.
  </Step>

  <Step title="Schedule the import">
    ```bash theme={null}
    ./p4_import_bootstrap.sh --install-cron
    ```

    This adds a crontab entry that runs the script every 5 minutes from this directory and appends its output to `bootstrap.log`.
    Each run restarts the import if it stopped and applies any change to its configuration.
  </Step>
</Steps>

## Follow the import's progress

Open the new repository in Diversion. Until the import finishes, the repository page shows its progress through three stages: **Reading history**, **Preparing history** and **Uploading files**.
Commits, branches and files appear once history is ready. Files open as soon as their contents are uploaded.

Large depots take a long time to import. The import host must stay on and connected until it finishes.

## Stop or remove the import

The crontab entry keeps the import running until you remove it.

<Note>
  Keep the crontab entry if you need continuous import from Perforce, or export back to it, after the initial import. [Contact support](mailto:support@diversion.dev) to enable continuous import or export.
</Note>

When the import is done and you don't need it to continue:

1. Run `crontab -e` and delete the line containing `p4_import_bootstrap.sh`.
2. Delete `local.env` from the import host.

## Troubleshooting

The script writes errors to its output and, once scheduled, to `bootstrap.log` in the import directory.

| Message or symptom | What to do |
| - | - |
| `Local config not found at ./local.env` | Run the script from the directory that holds `local.env`. |
| `Missing required variable in ./local.env: ...` | Fill in the named value in `local.env`. |
| `API_TOKEN must be an API token from the account page (starts with dvk_)` | `API_TOKEN` was changed or truncated. Restore the generated value. |
| `docker compose >= 2.17 required` | Upgrade to Docker Engine 20.10+ with the Docker Compose plugin 2.17+. |
| `crontab already has a p4_import_bootstrap.sh entry` | The import is already scheduled. To move it to another directory, delete the old entry with `crontab -e` first. |
| `... returned HTTP 401` | The API token was revoked or is invalid. The import stops until you fix it. [Generate a new token](/ci-cd#generate-an-api-token) and replace `API_TOKEN` in `local.env`. |
| `... returned HTTP 403` | The token's user no longer has admin access to the repository. The import stops until that's restored. |
| `... returned HTTP 404` | Check that `REPO_ID` in `local.env` matches the repository. If it does, contact support. |
| `... did not include an ETag` | Something on your network, such as a proxy, strips response headers. Check your proxy settings, or contact support. |
| `Another bootstrap run is in progress -- skipping this tick` | Normal now and then, such as while the first run downloads images. If it repeats for hours, check `bootstrap.log` for a stuck run. |
| The import page says **This repository already has an import configuration** | The settings for this repository can't be changed from the page. Contact support to change them. |
| The repository page stays on **Waiting for the import to start** | Check that the crontab entry exists (`crontab -l`) and that `bootstrap.log` shows no errors. |
| **No progress in 30 min** | Large depots can pause here. If it continues, check that the import host is running and the import container is up (`docker ps`). |
| **Import stopped** | Check that the import host is running and look at the container's output with `docker logs`. If the import doesn't resume, contact support. |

### Recover a lost local.env

If you left the **Import from Perforce** page before downloading `local.env`, don't start a new import: the repository and its import settings already exist. Recreate the file instead.

<Steps>
  <Step title="Create local.env">
    On the import host, create `local.env` next to `p4_import_bootstrap.sh` with this content:

    ```bash local.env theme={null}
    # Generated by the Diversion web app. Setup steps, in order:
    #   1. Put this file next to p4_import_bootstrap.sh on the import host.
    #   2. Make the script executable:            chmod +x p4_import_bootstrap.sh
    #   3. Fill in the Perforce settings below.
    #   4. Protect this file:                     chmod 600 local.env
    #   5. Check the setup, once:                 ./p4_import_bootstrap.sh
    #   6. Install the import (every 5 minutes):  ./p4_import_bootstrap.sh --install-cron
    #
    # To remove it later, run `crontab -e` and delete the p4_import_bootstrap.sh line.
    # To stop it for good, also revoke the API token below, under Settings > Integrations.
    API_DOMAIN=https://api.diversion.dev
    API_TOKEN=
    REPO_ID=

    # Perforce connection. The password stays on this host; Diversion never sees it.
    P4PORT=
    P4USER=
    P4PASSWD=
    ```
  </Step>

  <Step title="Fill in REPO_ID">
    In the Diversion app, click the repository name in the breadcrumbs to open the list of your organization's repositories. Hover over the row of the new repository and click the **Copy repo ID** button that appears. Paste the ID as `REPO_ID`.

    <img src="https://mintcdn.com/diversion-2/1TVJoD7AdabMtZcG/images/p4-import/copy-repo-id.png?fit=max&auto=format&n=1TVJoD7AdabMtZcG&q=85&s=76930bb8ced0bb5c471c1fc253deca97" alt="Repository menu in the breadcrumbs with the Copy repo ID button" style={{width: 'auto', maxWidth: '90%', borderRadius: '1.5rem', border: '.3rem solid #555', boxShadow: '0 0 1rem #888' }} width="514" height="362" data-path="images/p4-import/copy-repo-id.png" />
  </Step>

  <Step title="Fill in API_TOKEN">
    If you copied the token from the import page, paste it as `API_TOKEN`.

    If you didn't, generate a new one:

    1. Click your avatar (top-right) and choose **Integrations** from the menu.
    2. Click **Generate a new API token**, give it a name, and click **Generate token**. Generate it while signed in as the user who created the repository, so the token has admin access to it.
    3. Copy the token and paste it as `API_TOKEN`. It's shown only once.

    <img src="https://mintcdn.com/diversion-2/1TVJoD7AdabMtZcG/images/p4-import/integrations-token.png?fit=max&auto=format&n=1TVJoD7AdabMtZcG&q=85&s=43883eda778ca33081baeb47ab200183" alt="Integrations page with the Generate a new API token button" style={{width: '90%', borderRadius: '1.5rem', border: '.3rem solid #555', boxShadow: '0 0 1rem #888' }} width="1034" height="225" data-path="images/p4-import/integrations-token.png" />
  </Step>

  <Step title="Continue the setup">
    Follow [Run the import on the import host](#run-the-import-on-the-import-host) from the start.
  </Step>
</Steps>

## Request a managed import

If you can't meet the requirements above, we can run the import for you. Use **Request a managed import** at the bottom of the **Import from Perforce** page, or contact us at [support@diversion.dev](mailto:support@diversion.dev).


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.