A GitHub gh CLI extension for exporting Bitbucket Cloud
repositories into a format compatible with GitHub Enterprise migrations.
Caution
Breaking changes have been introduced in version v3.0.0
- The CLI now uses subcommands:
exportfor exporting only, andmigratefor export + import
This extension helps you migrate repositories from Bitbucket Cloud to GitHub Enterprise Cloud, GitHub Enterprise Cloud Managed Users, and GitHub Enterprise Cloud with data residency by creating an export archive that matches the format expected by GitHub Enterprise Importer (GEI).
The exporter creates a complete migration archive containing:
- Repository metadata
- Git objects (commits, branches, tags)
- Pull requests with comments
- Pull request reviews
- User information
gh extension install katiem0/gh-bbc-exporterFor more information: gh extension install.
- GitHub CLI installed and authenticated
- Bitbucket Cloud workspace administration access
- Go 1.19 or higher (if building from source)
Bitbucket Cloud provides two authentication methods for their API:
- API Tokens (recommended)
- Workspace Access Tokens (premium membership)
- Basic Authentication with App Passwords (deprecated, will be discontinued after September 9, 2025)
Important
The extension uses the following authentication priority order:
- Workspace Access Token (
--access-token/BITBUCKET_ACCESS_TOKEN) - API Token with Email (
--api-token+--email/BITBUCKET_API_TOKEN+BITBUCKET_EMAIL) - API Token with header auth (
--api-token/BITBUCKET_API_TOKEN) - Username and App Password (
--user+--app-password/BITBUCKET_USERNAME+BITBUCKET_APP_PASSWORD)
If multiple methods are provided, a warning is displayed and the highest priority method is used.
API tokens are the recommended authentication method and will replace app passwords. To create an API token:
- Log in to Bitbucket Cloud
- Click on your profile avatar in the top right
- Select Atlassian account settings
- In the top navigation section, select Security
- Click Create and manage API tokens
- Select Create API token with scopes
- Give your token a name and expiration date
- Select Bitbucket API token app and select the following permissions:
read:accountread:pullrequest:bitbucketread:repository:bitbucketread:workspace:bitbucket
- Click Next, review scopes and click Create
- Copy the token immediately as you won't be able to see it again
Warning
App passwords will be discontinued after September 9, 2025. Creation of new app passwords will stop after that date, and existing app passwords will stop working on June 9, 2026. Please migrate to API tokens instead.
For basic authentication with this tool your account username and an app password are needed. Your Bitbucket username can be found by following:
- On the sidebar, click on the Profile picture
- Select View profile
- Click on "Settings"
- Find Username under Bitbucket profile settings
- Under Personal settings, select Personal Bitbucket settings.
- On the left sidebar, select App passwords.
- Select Create app password.
- Give the App password a name.
- Select the following permissions:
Account: ReadWorkspace Membership: ReadRepositories: ReadPull Requests: Read
- Select the Create button. The page will display the New app password dialog.
A workspace-level access token is required to ensure a list of users is retrieved to be able to associate metadata with their GitHub account.
The access token will require the following permissions:
Account: ReadRepositories: ReadPull Requests: Read
The gh-bbc-exporter extension supports the retrieval of repositories or migrating repositories
with GitHub-Owned Storage from Bitbucket Cloud:
gh bbc-exporter -h
Export and migrate repositories from Bitbucket Cloud to GitHub
Usage:
bbc-exporter [command]
Available Commands:
export Export repository and metadata from Bitbucket Cloud
migrate Export from Bitbucket and import to GitHub
Flags:
--help Show help for command
Use "bbc-exporter [command] --help" for more information about a command.The export command exports a repository from Bitbucket Cloud and creates a local migration archive:
gh bbc-exporter export -h
Export repository and metadata from Bitbucket Cloud for GitHub Cloud import.
Usage:
bbc-exporter export [flags]
Flags:
-a, --bbc-api-url string Bitbucket API to use (default "https://api.bitbucket.org/2.0")
-t, --access-token string Bitbucket workspace access token for authentication (env: BITBUCKET_ACCESS_TOKEN)
--api-token string Bitbucket API token for authentication (env: BITBUCKET_API_TOKEN)
-e, --email string Atlassian account email for API token authentication (env: BITBUCKET_EMAIL)
-u, --user string Bitbucket username for basic authentication (env: BITBUCKET_USERNAME)
-p, --app-password string Bitbucket app password for basic authentication (env: BITBUCKET_APP_PASSWORD)
-w, --workspace string Bitbucket workspace name
-r, --repo string Name of the repository to export from Bitbucket Cloud
--temp-dir string Temporary directory for cloning (env: BITBUCKET_TEMP_DIR)
-o, --output string Output directory for exported data (default: ./bitbucket-export-TIMESTAMP)
--open-prs-only Export only open pull requests and ignore closed/merged ones
--prs-from-date string Export pull requests created on or after this date (format: YYYY-MM-DD)
--skip-commit-lookup Skip Bitbucket API lookups to retrieve commit SHAs (use local lookup only)
-d, --debug Enable debug logging
Global Flags:
--help Show help for command# Export using API token with email (recommended)
gh bbc-exporter export -w your-workspace -r your-repo --api-token your-api-token --email your-email@example.com
# Export using workspace access token
gh bbc-exporter export -w your-workspace -r your-repo -t your-workspace-token
# Export using basic authentication (deprecated)
gh bbc-exporter export -w your-workspace -r your-repo -u your-username -p your-app-password
# Export only open pull requests
gh bbc-exporter export -w your-workspace -r your-repo -t your-token --open-prs-only
# Export pull requests from a specific date
gh bbc-exporter export -w your-workspace -r your-repo -t your-token --prs-from-date 2024-01-01The migrate command combines export and import into a single operation, exporting from
Bitbucket Cloud and importing directly to GitHub Enterprise Cloud using GitHub-Owned Storage:
gh bbc-exporter migrate -h
Migrate a repository from Bitbucket Cloud to GitHub Enterprise.
Usage:
bbc-exporter migrate [flags]
Flags:
-a, --bbc-api-url string Bitbucket API to use (default "https://api.bitbucket.org/2.0")
-t, --access-token string Bitbucket workspace access token for authentication (env:
BITBUCKET_ACCESS_TOKEN)
--api-token string Bitbucket API token for authentication (env: BITBUCKET_API_TOKEN)
-e, --email string Atlassian account email for API token authentication (env:
BITBUCKET_EMAIL)
-u, --user string Bitbucket username for basic authentication (env:
BITBUCKET_USERNAME)
-p, --app-password string Bitbucket app password for basic authentication (env:
BITBUCKET_APP_PASSWORD)
-w, --workspace string Bitbucket workspace name
-r, --repo string Name of the repository to export from Bitbucket Cloud
--temp-dir string Temporary directory for cloning (env: BITBUCKET_TEMP_DIR)
-o, --output string Output directory for exported data (default:
./bitbucket-export-TIMESTAMP)
--open-prs-only Export only open pull requests
--prs-from-date string Export pull requests created on or after this date (format:
YYYY-MM-DD)
--skip-commit-lookup Skip Bitbucket API lookups to retrieve commit SHAs (use local
lookup only)
--target-org string Target GitHub organization (required)
--target-repo string Target repository name (defaults to source repo name)
--github-target-pat string GitHub Personal Access Token (env: GITHUB_PAT)
--target-api-url string The URL of the target API, if not migrating to github.com.
Defaults to https://v-api-github-com.adclosenn.dev (default
"https://api.github.com")
--target-repo-visibility <internal|private|public> The visibility of the target repo. Defaults to private. Valid
values are public, private, or internal. (default private)
-d, --debug Enable debug logging
Global Flags:
--help Show help for command# Migrate repository to GitHub (uses gh CLI authentication by default)
gh bbc-exporter migrate -w bitbucket-workspace -r source-repo \
--target-org github-org -t your-bitbucket-token
# Migrate with custom target repository name
gh bbc-exporter migrate -w bitbucket-workspace -r source-repo \
--target-org github-org --target-repo new-repo-name -t your-token
# Migrate with specific visibility
gh bbc-exporter migrate -w bitbucket-workspace -r source-repo \
--target-org github-org --target-repo-visibility internal \
-t your-token
# Migrate and keep the archive for inspection
gh bbc-exporter migrate -w bitbucket-workspace -r source-repo \
--target-org github-org -t your-token
# Migrate using explicit GitHub PAT
gh bbc-exporter migrate -w bitbucket-workspace -r source-repo \
--target-org github-org --github-target-pat ghp_xxxxx \
-t your-bitbucket-tokenFor migrations to a GHE.com instance, use the --target-api-url flag:
gh bbc-exporter migrate -w bitbucket-workspace -r source-repo \
--target-org github-org \
--target-api-url https://api.your-slug.ghe.com \
--github-target-pat ghp_xxxxx \
-t your-bitbucket-tokenNote
GitHub Enterprise Cloud with data residency (GHE.com) requires the --target-api-url flag
pointing to your instance's API endpoint. The uploads URL is automatically derived from the
API URL. GitHub Enterprise Server (GHES) is not supported.
The --skip-commit-lookup flag can be used to improve export performance by skipping
Bitbucket API calls for resolving full commit SHAs. When enabled:
- The tool will only attempt to resolve commit SHAs from the locally cloned repository
- If a full SHA cannot be resolved locally, the short SHA will be preserved
- This can significantly reduce API calls and speed up exports for large repositories with many pull request comments
When to use this flag:
- When experiencing rate limiting issues with the Bitbucket API
- For large repositories with many pull request review comments
- When you're confident the local repository clone contains all referenced commits
Note
Some GitHub import operations may require full 40-character commit SHAs. Only use this flag if you're certain that shortened SHAs won't cause issues with your migration, or if the local repository contains all the necessary commit history.
# Export with skip commit lookup enabled
gh bbc-exporter export -w your-workspace -r your-repo --skip-commit-lookup -t your-token
# Migrate with skip commit lookup enabled
gh bbc-exporter migrate -w your-workspace -r your-repo --target-org github-org --skip-commit-lookup -t your-tokenThis tool supports the use of environment variables instead of command-line flags:
# API token authentication with email (recommended)
export BITBUCKET_API_TOKEN="your-api-token-here"
export BITBUCKET_EMAIL="your-atlassian-email@example.com"
gh bbc-exporter export -w your-workspace -r your-repo
# Workspace token authentication
export BITBUCKET_ACCESS_TOKEN="your-workspace-token-here"
gh bbc-exporter export -w your-workspace -r your-repo
# Basic authentication (soon to be deprecated)
export BITBUCKET_USERNAME="your-username"
export BITBUCKET_APP_PASSWORD="your-app-password"
gh bbc-exporter export -w your-workspace -r your-repo
# GitHub PAT for migrate command
export GITHUB_PAT="ghp_your-github-pat"
gh bbc-exporter migrate -w your-workspace -r your-repo --target-org github-org -t your-bitbucket-token# Using API token with email (recommended)
gh bbc-exporter export -w your-workspace -r your-repo --api-token your-api-token --email your-atlassian-email@example.com
# Using workspace access token
gh bbc-exporter export -w your-workspace -r your-repo -t your-workspace-token
# Using basic authentication (soon to be deprecated)
gh bbc-exporter export -w your-workspace -r your-repo -u your-username -p your-app-passwordFor migrations from BitBucket Data Center or Server, please see GitHub's Official Documentation.
The exporter creates a directory or archive with the following structure:
bitbucket-export-YYYYMMDD-HHMMSS/
├── schema.json
├── repositories_000001.json
├── users_000001.json
├── organizations_000001.json
├── pull_requests_000001.json
├── issue_comments_000001.json
├── pull_request_review_comments_000001.json
├── pull_request_review_threads_000001.json
├── pull_request_reviews_000001.json
└── repositories/
└── <workspace>/
└── <repository>.git/
├── objects/
├── refs/
└── info/
├── nwo
└── last-sync
After generating the migration archive with the export command, you can import it to
GitHub Enterprise Cloud using GitHub owned storage and GEI. Detailed documentation can
be found in Importing Bitbucket Cloud Archive to GitHub Enterprise Cloud.
Alternatively, use the migrate command to perform both export and import
in a single operation.
A sample GitHub Actions workflow is available to automate the export and import process. See the sample workflow for an example of how to orchestrate the migration.
- API rate limits may affect large exports
- Wiki content is not included in the export
- Issues are not exported (Bitbucket issues have a different structure from GitHub issues)
- Repository and Pull request labels have not been implemented
- User information is limited to what's available from Bitbucket API
- Archives larger than 40 GiB are not supported by GitHub-owned storage
- GitHub Enterprise Server (GHES) is not supported as a migration target
When exporting repositories with special characters in their names:
- The tool will preserve capitalization in repository names (e.g.,
RepositoryUIName) - If a repository name contains special characters that aren't allowed in GitHub repository names
(e.g.,
@group-test/ui), the tool will use the Bitbucket slug (e.g.,group-test-ui) for compatibility - Repository slugs are always used for directory names and internal references to ensure consistency
The exporter validates Git references (branch and tag names) to prevent ambiguous references that could cause issues during GitHub import. The following validations are performed:
- Ambiguous references: Branch or tag names that are exactly 40 hexadecimal characters are rejected, as they could be mistaken for commit SHAs
- Invalid characters: References containing special characters like spaces,
~,^,:,?,*,[,\,..,@{, or//are flagged - Invalid formats: References that start or end with
.,/, or end with.lockare considered invalid
If any ambiguous references are detected, the export will fail with a clear error message indicating which references need to be renamed in Bitbucket before attempting the export again.
- Authentication Errors Make sure your Bitbucket app password has the necessary permissions to access repositories.
- Export Fails with Network Errors
Bitbucket API may have rate limits. Try running the export with the
--debugflag to see detailed error messages. - Empty Repository Export If the repository can't be cloned, the exporter creates an empty repository structure. Check that the repository exists and is accessible.
- Migration Fails in GitHub Enterprise Importer Check the error logging repository that's created during migration for detailed information about any failures.
- Export Fails Due to Ambiguous Git References
If your repository has branches or tags with names that are exactly 40
hexadecimal characters (e.g.,
1234567890abcdef1234567890abcdef12345678), the export will fail. These references are ambiguous because Git cannot determine if they refer to a branch/tag name or a commit SHA. To resolve:- Rename the problematic branches/tags in Bitbucket to use non-ambiguous names
- Re-run the export after renaming
- GitHub CLI Authentication Issues
If using
ghCLI authentication and you receiveGraphQL: <user> does not have the correct permissions to execute, it is likely due to auth permissions from the CLI. Seegh auth loginfor details on--scopes.
-
Clone the repository:
git clone https://github.com/katiem0/gh-bbc-exporter.git cd gh-bbc-exporter -
Build the extension:
go build -o gh-bbc-exporter
-
Install locally for testing:
gh extension install .
go test ./...Contributions are welcome! Please feel free to submit a Pull Request.
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add some amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request