Skip to content

Import Repositories to Harness Code

atefehmohseni edited this page Aug 31, 2026 · 3 revisions

Migrate Code Repositories to Harness Code

This guide explains how developers and customers use the Harness CLI to migrate git repositories: including pull requests, comments, labels, webhooks, and branch rules, from any supported SCM into Harness Code.


Setup commands

harness install cli
harness install plugin migrate
harness auth login
harness auth setscope --org <org> --project <project>
harness get module migrate

Table of contents

  1. Setup commands
  2. What gets migrated
  3. Supported source providers
  4. Prerequisites
  5. Install the CLI and migrate plugin
  6. Migration overview
  7. Selective export/import flags
  8. Step 1 — Authenticate to Harness (import only)
  9. Step 2 — Export from your SCM
  10. Step 3 — Map user emails (optional)
  11. Step 4 — Import into Harness Code
  12. Step 5 — Verify the migration
  13. Provider-specific reference
  14. Advanced scenarios
  15. Command quick reference
  16. Troubleshooting

What gets migrated

A full migration can include:

Entity Export Import
Git repository (all branches and tags)
Git LFS objects ✓ (requires git-lfs)
Repository visibility (public/private)
Pull requests / merge requests
PR comments and review comments
PR reviewers
Labels
Webhooks
Branch protection / branch rules

Use --no-* flags on export or import to skip specific entity types (see Command quick reference).


Supported source providers

SCM Export command --from identifies
GitHub (cloud or Enterprise) migrate github_organization:scm_bundle GitHub organization
GitLab (cloud or self-managed) migrate gitlab_group:scm_bundle GitLab group
Bitbucket Cloud migrate bitbucket_workspace:scm_bundle Bitbucket workspace
Bitbucket Server (Stash) migrate stash_project:scm_bundle Bitbucket Server project

All exports write the same scm_bundle format. A single import command consumes bundles from any provider:

harness migrate scm_bundle:repository --from ./harness

Prerequisites

Tools

Tool Required for Notes
Harness CLI (harness) All steps See Install the CLI and migrate plugin
migrate plugin Export and import Installed separately via harness install plugin migrate
git Export and import Must be on PATH
git-lfs Repos with LFS objects Must be on PATH; skip with --no-lfs if not needed

Source SCM tokens

Create a personal access token on your source SCM with read access to the org/group/workspace/project you are migrating. Minimum scopes vary by provider — see Token permissions.

You can pass tokens via command flags (--github-token, --gitlab-token, etc.) or environment variables where supported.

Harness token (import only)

The export phase does not require a Harness login. The import phase requires a Harness API token (PAT or SAT) with permission to create repositories in the target org/project.

Export runs entirely against your source SCM. Import creates resources under the account/org/project in your active CLI profile.


Install the CLI and migrate plugin

Install or upgrade the CLI

harness install cli

For scripting/CI, see docs/manual-install.md.

Install the migrate plugin

harness install plugin migrate

Check availability without installing:

harness install plugin migrate --check

Confirm both are loaded:

harness list module

You should see code (builtin) and migrate (plugin, installed).

Discover migrate commands

harness get module migrate
harness migrate --help
harness get noun scm_bundle

Migration overview

Migration is deliberately two phases separated by a bundle on disk:

┌─────────────────┐     export      ┌──────────────┐     import      ┌─────────────────┐
│  Source SCM     │ ──────────────► │  scm_bundle  │ ──────────────► │  Harness Code   │
│  (GitHub, etc.) │  (no Harness    │  ./harness/  │  (Harness auth  │  repositories   │
│                 │   login needed) │  harness.zip │   required)     │  + PR metadata  │
└─────────────────┘                 └──────────────┘                 └─────────────────┘
                                           │
                                           ▼
                              update scm_bundle:users  (optional)
                              rewrite emails in bundle

Why two steps?

  • Org-scale exports can run for hours; checkpoints and --resume let you recover from interruptions.
  • The bundle can be inspected, backed up, or edited (e.g. user email mapping) before anything is created in Harness.
  • Export can run on a machine with SCM access but no Harness credentials (e.g. inside your corporate network or on the SCM server itself).

Selective export/import flags

Before migrating in bulk, decide how much metadata you actually need. Source SCM API rate limits are hit often on org/group-scale exports, so for larger repositories it is usually better to migrate one repository at a time with --repo, and skip metadata you don't need.

Flag Effect
--no-pr Skip pull requests and PR comments
--no-pr-metadata Skip PR comments and reviewers (keep PR shells)
--no-comment Skip PR comments
--no-label Skip labels
--no-webhook Skip webhooks
--no-rule Skip branch protection rules
--no-lfs Skip LFS objects

These flags work on both export (<provider>:scm_bundle) and import (scm_bundle:repository) commands.


Step 1 — Authenticate to Harness (import only)

Skip this step if you are only exporting. Come back here before running the import.

Interactive login

harness auth login

The wizard prompts for API URL, token, org, and project.

Non-interactive login (CI / automation)

harness auth login \
  --api-url https://app.harness.io \
  --api-token "$HARNESS_API_KEY" \
  --org <org_id> \
  --project <project_id>

For self-hosted Harness, set --api-url to your instance URL.

Set or change default scope

Repositories are created under the profile's org/project:

harness auth setscope --org <org_id> --project <project_id>

Or override per command:

harness migrate scm_bundle:repository --from ./harness --org <org_id> --project <project_id>

Verify auth

harness auth status
harness list repository

Step 2 — Export from your SCM

Pick the command that matches your source provider. Each command:

  • Reads repositories and metadata from the live SCM API
  • Writes a local bundle to ./harness by default (override with --to)
  • Produces harness.zip inside the output folder
  • Supports --resume to continue an interrupted export
  • Supports --repo to export a single repository instead of the whole org/group/project

GitHub

harness migrate github_organization:scm_bundle \
  --from <github_org> \
  --github-token <token> \
  --github-user <username> \
  --to ./harness

GitHub Enterprise:

harness migrate github_organization:scm_bundle \
  --from <github_org> \
  --github-host https://github.example.com \
  --github-token <token> \
  --github-user <username>

Single repository:

harness migrate github_organization:scm_bundle \
  --from <github_org> \
  --repo <repo_name> \
  --github-token <token> \
  --github-user <username>

GitLab

harness migrate gitlab_group:scm_bundle \
  --from <group_path> \
  --gitlab-token <token> \
  --gitlab-user <username> \
  --to ./harness

Self-managed GitLab:

harness migrate gitlab_group:scm_bundle \
  --from <group_path> \
  --gitlab-host https://gitlab.example.com \
  --gitlab-token <token> \
  --gitlab-user <username>

Include nested subgroups:

harness migrate gitlab_group:scm_bundle \
  --from <group_path> \
  --include-subgroups \
  --gitlab-token <token> \
  --gitlab-user <username>

Single project:

harness migrate gitlab_group:scm_bundle \
  --from <group_path> \
  --repo <project_name> \
  --gitlab-token <token> \
  --gitlab-user <username>

Bitbucket Cloud

harness migrate bitbucket_workspace:scm_bundle \
  --from <workspace> \
  --bitbucket-token <token> \
  --to ./harness

Single repository:

harness migrate bitbucket_workspace:scm_bundle \
  --from <workspace> \
  --repo <repo_slug> \
  --bitbucket-token <token>

Bitbucket Server (Stash)

harness migrate stash_project:scm_bundle \
  --from <project_key> \
  --stash-host https://bitbucket.example.com \
  --stash-token <token> \
  --stash-user <username> \
  --to ./harness

Single repository:

harness migrate stash_project:scm_bundle \
  --from <project_key> \
  --repo <repo_slug> \
  --stash-host https://bitbucket.example.com \
  --stash-token <token> \
  --stash-user <username>

Resume an interrupted export

If export stops partway through, re-run the same command with --resume:

harness migrate github_organization:scm_bundle \
  --from <github_org> \
  --github-token <token> \
  --github-user <username> \
  --to ./harness \
  --resume

Export output

After a successful export, expect:

./harness/
  harness.zip    # bundle ready for import
  ...            # checkpoint and intermediate files

No Harness resources are created during export.


Step 3 — Map user emails (optional)

Harness matches PR authors, commenters, reviewers, and branch-rule members by email. If a source SCM email does not match any Harness user, the import stops.

Fix this before import by rewriting emails in the bundle:

Create a mapping file

users.json:

{
  "alice@old-company.com": "alice@new-company.com",
  "bob@github-noreply.com": "bob@harness.example.com"
}

Apply the mapping

harness update scm_bundle:users ./harness --user-mapping users.json

This rewrites the bundle in place (the original is replaced only after success).

Alternatively, skip strict user matching at import time (see Import with unmapped users).


Step 4 — Import into Harness Code

With Harness auth configured and the bundle ready:

harness migrate scm_bundle:repository --from ./harness

You can pass the folder (./harness) or the zip directly (./harness/harness.zip).

Import a single repository from the bundle

harness migrate scm_bundle:repository \
  --from ./harness \
  --repo <org_or_group>/<repo_name>

Large repositories

Raise the temporary git push size limit (default 100 MB):

harness migrate scm_bundle:repository \
  --from ./harness \
  --file-size-limit 500000000

API payload size (413 errors)

Lower the PR batch size:

harness migrate scm_bundle:repository \
  --from ./harness \
  --batch-size 50

Import with unmapped users

To continue when some emails have no Harness match (PRs/comments/rules are attributed to your profile's account):

harness migrate scm_bundle:repository \
  --from ./harness \
  --skip-users

Use a service account profile when using --skip-users, so unmapped history is not credited to a personal account.

Commit authors always come from git objects in the bundle, not from the importing identity.

Long-running imports

Org-scale imports can take hours. Disable the timeout:

harness migrate scm_bundle:repository --from ./harness --timeout 0

Step 5 — Verify the migration

Use the built-in code module to confirm repositories and metadata landed correctly.

List migrated repositories

harness list repository
harness list repository --org <org_id> --project <project_id>

Inspect a repository

harness get repository <repo_id>

Check branches, tags, and commits

harness list branch <repo_id>
harness list tag <repo_id>
harness list commit <repo_id> --branch main

Check pull requests

harness list pr <repo_id>
harness list pr <repo_id> --state open
harness get pr <repo_id>/<pr_number>

Check PR activity, comments, and checks

harness list pr_activity <repo_id>/<pr_number>
harness list pr_comment <repo_id>/<pr_number>
harness list pr_check <repo_id>/<pr_number>

Check labels

harness list repo_label <repo_id>
harness list pr_label <repo_id>/<pr_number>

Provider-specific reference

Token permissions by provider

Provider Token type What you need, and for what
GitHub Classic PAT repo scope for the git data and pull requests. The GitHub REST API docs require the repo's Admin role specifically to read branch protection rules, and repo webhooks require Admin role as well. Without Admin, skip both with --no-rule --no-webhook.
GitHub Enterprise Same as above Same requirements as GitHub.
GitLab PAT read_api + read_repository for the git data and merge requests. Reading protected branches and webhooks requires the Maintainer role on the group/project. Without it, skip both with --no-rule --no-webhook.
Bitbucket Cloud App password / PAT Repository Read
Bitbucket Server HTTP access token Repository Read on target project
Harness (import) PAT or SAT repo_create — create the repository. repo_push — import pull requests. repo_edit — import webhooks, branch rules, and labels; skip these with --no-webhook --no-rule --no-label if your token doesn't have it. repo_delete — optional, lets the CLI clean up a partially-created repo automatically if the import fails partway, so a retry doesn't hit a "repo already exists" error.

Host URL flags

Provider Flag Example
GitHub Enterprise --github-host https://github.example.com
Self-managed GitLab --gitlab-host https://gitlab.example.com
Bitbucket Server --stash-host https://bitbucket.example.com

Bitbucket Cloud uses the public API by default; --bitbucket-host is available for non-standard endpoints.


Advanced scenarios

Incremental PR import (--no-git)

When a repository already exists in Harness Code and you only need additional PR metadata:

harness migrate scm_bundle:repository \
  --from ./harness \
  --no-git

This skips git push operations and imports only pull requests, comments, and related metadata. The CLI calculates PR number offsets to avoid conflicts with existing PRs.

Example: if the source GitHub repo has PRs #1–100, and the target Harness Code repo (same repo, migrated earlier) already has PRs #1–50, the CLI offsets the incoming PRs by 50 before importing. GitHub PR #1 becomes Harness Code PR #51, and GitHub PR #100 becomes Harness Code PR #150. Any new PR created afterward in Harness Code continues from #151.

Requirements:

  • Target repository must already exist in Harness Code
  • You must have write permission on the target repository

Export without PR metadata (git only)

Useful for a first pass or when PR export is slow.

harness migrate github_organization:scm_bundle \
  --from <org> \
  --no-pr --no-webhook --no-rule --no-label \
  --github-token <token> \
  --github-user <username>

Then run a second export with --no-git on import, or export PRs separately.

Run export near the SCM server

For repos behind a firewall, run export on a host that has direct SCM access (your laptop on VPN, a jump box, or the SCM server itself). Copy the ./harness folder to a machine with Harness access for import:

# On SCM-accessible host — export only, no Harness credentials needed
harness migrate github_organization:scm_bundle \
  --from <org> \
  --github-token <token> \
  --github-user <username> \
  --to /data/migration-bundle

# Copy /data/migration-bundle to import host, then:
harness migrate scm_bundle:repository --from /data/migration-bundle

Automate in CI/CD

Typical pipeline stages:

  1. Export job — SCM credentials only; artifact the ./harness folder
  2. Optional transform jobharness update scm_bundle:users
  3. Import job — Harness credentials; harness migrate scm_bundle:repository

Use non-interactive auth:

export HARNESS_API_KEY=<token>
export HARNESS_ACCOUNT=<account_id>
export HARNESS_ORG=<org_id>
export HARNESS_PROJECT=<project_id>

harness migrate scm_bundle:repository --from ./harness --timeout 0

See docs/auth.md for env-var mode details.


Command quick reference

Export commands (source → local bundle)

# GitHub
harness migrate github_organization:scm_bundle --from <org> [--to <folder>] [--repo <name>] [--resume] \
  [--github-token <token>] [--github-user <user>] [--github-host <url>]

# GitLab
harness migrate gitlab_group:scm_bundle --from <group> [--to <folder>] [--repo <name>] [--resume] [--include-subgroups] \
  [--gitlab-token <token>] [--gitlab-user <user>] [--gitlab-host <url>]

# Bitbucket Cloud
harness migrate bitbucket_workspace:scm_bundle --from <workspace> [--to <folder>] [--repo <name>] [--resume] \
  [--bitbucket-token <token>] [--bitbucket-host <url>]

# Bitbucket Server
harness migrate stash_project:scm_bundle --from <project> [--to <folder>] [--repo <name>] [--resume] \
  [--stash-host <url>] [--stash-token <token>] [--stash-user <user>]

Transform command (bundle editing)

harness update scm_bundle:users <folder-or-zip> --user-mapping users.json

Import command (bundle → Harness Code)

harness migrate scm_bundle:repository --from <folder-or-zip> [--repo <org/repo>] \
  [--skip-users] [--no-git] [--batch-size <n>] [--file-size-limit <bytes>] [--timeout 0]

Post-migration verification (code module)

harness list repository
harness get repository <repo_id>
harness list pr <repo_id>
harness list branch <repo_id>
harness list repo_label <repo_id>

Troubleshooting

unknown command "migrate"

The migrate plugin is not installed:

harness install plugin migrate
harness list module    # migrate should show Installed: yes

Import fails on unknown user email

Option A — map emails before import:

harness update scm_bundle:users ./harness --user-mapping users.json
harness migrate scm_bundle:repository --from ./harness

Option B — skip strict matching (attributes unmapped users to your profile):

harness migrate scm_bundle:repository --from ./harness --skip-users

These options are not mutually exclusive — you can pair them. Provide a users.json mapping for the users you can match (e.g. from a HR/IT export), and add --skip-users on top so any user not covered by that mapping (for example, someone who has since left the org and no longer has a Harness account) doesn't block the import.

Export interrupted mid-run

Re-run with --resume and the same --to folder:

harness migrate github_organization:scm_bundle --from <org> --to ./harness --resume ...

HTTP 413 during import

Reduce batch size:

harness migrate scm_bundle:repository --from ./harness --batch-size 25

Large file push failures

Increase file size limit:

harness migrate scm_bundle:repository --from ./harness --file-size-limit 1000000000

LFS objects missing

git and git-lfs need to be installed on the machine running the CLI to migrate LFS objects. If git-lfs isn't found, it's automatically skipped. You can also skip it explicitly with --no-lfs.

Wrong org/project after import

Import scope comes from the active profile or --org/--project flags. Set scope before import:

harness auth setscope --org <org> --project <project>
harness migrate scm_bundle:repository --from ./harness

Discover command flags at any time

harness migrate <provider>:scm_bundle --help
harness migrate scm_bundle:repository --help
harness update scm_bundle:users --help

Related documentation

Clone this wiki locally