Created
December 29, 2025 14:07
-
-
Save gglanzani/d3d3830b0c90826eda120560ab9d024a to your computer and use it in GitHub Desktop.
Migrate bitbucket repositories to GitHub
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/usr/bin/env bash | |
| set -euo pipefail | |
| # usage (assuming the `gh` CLI is installed and you're authenticated): | |
| # | |
| # | |
| # BB_WORKSPACE=your_bitbucket_workspace \ | |
| # GH_OWNER=your_github_username \ | |
| # ./migrate-bitbucket.sh repos.txt | |
| # ---------------------------- | |
| # Config (edit these) | |
| # ---------------------------- | |
| DEFAULT_PRIVATE="true" # true/false | |
| REPO_LIST_FILE="${1:-repos.txt}" | |
| # Optional: use a specific ssh key / host alias by configuring ~/.ssh/config. | |
| # e.g., BITBUCKET_HOST="bitbucket-work" if you set Host bitbucket-work -> bitbucket.org | |
| BITBUCKET_HOST="bitbucket.org" | |
| GITHUB_HOST="github.com" | |
| create_github_repo() { | |
| local repo="$1" | |
| gh repo create $repo --private | |
| echo "✅ Created GitHub repo: ${GH_OWNER}/${repo}" | |
| } | |
| migrate_repo() { | |
| local repo="$1" | |
| local tmpdir | |
| tmpdir="$(mktemp -d)" | |
| # SSH clone URLs | |
| # Bitbucket: git@bitbucket.org:WORKSPACE/repo.git | |
| local bb_url="git@${BITBUCKET_HOST}:${BB_WORKSPACE}/${repo}.git" | |
| # GitHub: git@github.com:OWNER/repo.git | |
| local gh_url="git@${GITHUB_HOST}:${GH_OWNER}/${repo}.git" | |
| echo | |
| echo "==============================" | |
| echo "Migrating: ${repo}" | |
| echo " From: ${bb_url}" | |
| echo " To: ${gh_url}" | |
| echo "==============================" | |
| create_github_repo "$repo" | |
| echo "⬇️ Cloning from Bitbucket (mirror over SSH)..." | |
| git clone --mirror "$bb_url" "${tmpdir}/${repo}.git" | |
| echo "⬆️ Pushing to GitHub (mirror over SSH)..." | |
| (cd "${tmpdir}/${repo}.git" && git push --mirror "$gh_url") | |
| echo "✅ Done: ${repo}" | |
| rm -rf "$tmpdir" | |
| } | |
| # ---------------------------- | |
| # Main | |
| # ---------------------------- | |
| if [[ ! -f "$REPO_LIST_FILE" ]]; then | |
| echo "Repo list file not found: $REPO_LIST_FILE" | |
| echo "Usage: $0 repos.txt" | |
| exit 1 | |
| fi | |
| : "${BB_WORKSPACE:?BB_WORKSPACE must be set (export BB_WORKSPACE=...)}" | |
| : "${GH_OWNER:?GH_OWNER must be set (export GH_OWNER=...)}" | |
| # Basic SSH sanity checks (won't fail the script if your server prints banners) | |
| echo "🔐 Checking SSH connectivity (non-fatal)..." | |
| ssh -o BatchMode=yes -o ConnectTimeout=5 "git@${BITBUCKET_HOST}" -T >/dev/null 2>&1 || true | |
| ssh -o BatchMode=yes -o ConnectTimeout=5 "git@${GITHUB_HOST}" -T >/dev/null 2>&1 || true | |
| echo "Found repositories to migrate:" | |
| found_any=false | |
| while IFS= read -r repo; do | |
| # Skip blank lines and comments | |
| [[ -z "$repo" || "$repo" =~ ^[[:space:]]*# ]] && continue | |
| found_any=true | |
| migrate_repo "$repo" | |
| done < "$REPO_LIST_FILE" | |
| if [[ "$found_any" != "true" ]]; then | |
| echo "No repositories found in $REPO_LIST_FILE" | |
| exit 0 | |
| fi | |
| echo | |
| echo "🎉 All migrations complete." |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment