Skip to content

Latest commit

 

History

8 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

GitHub Migration Suite

Enterprise‑grade migration toolkit for GitHub → GitHub organization transfers

This suite provides a complete, scriptable, menu‑driven, and automated solution for migrating repositories and all associated work items between GitHub organizations.

It supports:

  • Repository mirroring (all branches, tags, refs)
  • Issues, labels, milestones, PR metadata (via gh-migrate)
  • Classic Projects (Projects v1) — full backlog:
    • Projects
    • Columns
    • Cards (issue cards + note cards)
    • Ordering
  • Projects v2 (GraphQL-based)
  • Projects v1 → v2 cross-migration (Classic → Projects v2)
  • Discussions (export + import)
  • Secure credential storage using Windows DPAPI
  • Python and PowerShell orchestration
  • GitHub Actions workflows for CI/CD migration
  • Modular architecture (PSM1 modules + Python modules)
  • Auto-detection of source / target project versions
  • Interactive project selection and confirmation prompts
  • Non-interactive (auto-yes) mode for CI/automation

📁 Folder Structure

github-migration-suite/
├── python/
│   ├── migrate_python.py
│   ├── config.json
│   ├── requirements.txt
│   ├── modules/
│   │   ├── repo.py
│   │   ├── issues.py
│   │   ├── projects.py
│   │   ├── projects_v1.py
│   │   └── discussions.py
│   └── utils/
│       ├── logger.py
│       └── shell.py
├── powershell/
│   ├── menu.ps1
│   ├── migrate-github.ps1
│   ├── config.json
│   ├── readme.md
│   └── modules/
│       ├── repo.psm1
│       ├── issues.psm1
│       ├── projects.psm1
│       ├── projectsV1.psm1
│       └── discussions.psm1
├── templates/
│   ├── project-migrator.json
│   ├── discussions-export.json
│   └── discussions-import.json
├── examples/
│   ├── sample-log.txt
│   ├── sample-export.json
│   └── sample-import.json
└── .github/
    └── workflows/
        ├── python-migration.yml
        └── powershell-migration.yml

🚀 Features

✔ Repository Migration

  • Full mirror (--mirror)
  • All branches, tags, refs
  • Recreates repo in target org automatically

✔ Issues, PRs, Labels, Milestones, Releases

Migrated via:

gh migrate repo

Supports:

  • Issue bodies
  • Comments
  • Labels
  • Milestones
  • PR metadata
  • Releases

✔ Classic Projects (Projects v1)

Full backlog migration:

  • Project metadata
  • Columns
  • Cards (issue cards + note cards)
  • Ordering preserved
  • Backlog views reconstructed

✔ Projects v2

Migrated via project-migrator:

  • Fields
  • Iterations
  • Statuses
  • Items
  • Views (implicitly reconstructed)

✔ Projects v1 → v2 Cross-Migration

When your source org uses Classic Projects (v1) and the target uses Projects v2:

  • Reads v1 columns, cards, and issue/PR links via REST API
  • Creates equivalent V2 projects in the target org via GraphQL API
  • Maps v1 column names to V2 Status field options
  • Links issues/PRs as V2 items
  • Converts note cards to V2 draft issues

✔ Auto-Detection of Project Versions

When projects_auto_detect is enabled (default), the suite will:

  1. Query the source org to see if it uses v1 (Classic), v2, or both projects
  2. Query the target org the same way
  3. Decide the appropriate migration route:
Source Target Action
v1 only v1 only v1 → v1 migration
v2 only v2 only v2 → v2 migration
v1 v2 Cross-migration v1 → v2 (with prompts)
v2 v1 Skipped (downgrade not supported)

✔ Interactive Project Selection & Confirmation

The migration script will:

  • Show the user a numbered list of all detected projects
  • Let the user pick: a single number, comma-separated numbers, or A for all
  • Ask for a final y/n confirmation before any mutation occurs

To skip the prompts in CI/automation contexts, set projects_v1_to_v2.auto_yes / ProjectsV1ToV2.AutoYes to true in the config file.

✔ Discussions

Migrated via discussions-migration:

  • Categories
  • Threads
  • Comments
  • Authors (mapped)

✔ Secure Credential Storage (DPAPI)

Tokens stored at:

%LOCALAPPDATA%\GitHubMigrationSuite\creds.dat

Encrypted with:

ProtectedData.Protect(..., CurrentUser)

✔ PowerShell Menu System

Interactive menu:

1. Mirror Repository
2. Migrate Issues / PRs / Labels / Milestones / Releases
3. Migrate Projects v2 (source v2 -> target v2)
4. Migrate Discussions
5. Run FULL Migration (all enabled)
6. Update Stored Credentials
7. Migrate Projects v1 -> v1 (Classic, full backlog)
8. Migrate Projects v1 -> v2 (Classic -> Projects v2)
9. Detect and migrate Projects (auto v1/v2, with prompts)
0. Exit

✔ GitHub Actions Support

Two workflows included:

  • Python migration
  • PowerShell migration

🔧 Requirements

GitHub CLI

gh auth login
gh extension install github/gh-migrate

Project Migrator

npm install -g @github/migration-toolkit-projects

Discussions Migrator

npm install -g @github/discussions-migration

Python

pip install -r python/requirements.txt

PowerShell

  • PowerShell 7+
  • Windows DPAPI (Windows only)

🔐 Required Credentials, Tokens & Secrets

A successful migration requires the following credentials to be configured. Read this section carefully — the wrong setup is the most common cause of silent or failed migrations.

1. Source-Org Token (GH_SOURCE_TOKEN)

The source token is used to:

  • Mirror the source repository (git clone --mirror over HTTPS with token authentication)
  • Read Classic Projects (v1) and their columns / cards (REST + inertia-preview header)
  • Read Projects v2 (GraphQL)
  • Read issues, PRs, milestones, labels, releases (via gh-migrate)

Required scopes (fine-grained PAT recommended):

Resource Access
Source org → repositories Read
Source org → projects (v1 & v2) Read

2. Target-Org Token (GH_TARGET_TOKEN)

The target token is used to:

  • Create the target repository (gh repo create)
  • Push the mirror to the target (git push --mirror)
  • Create V2 projects and items (GraphQL mutations)
  • Create issues / PRs / labels / milestones / releases (via gh-migrate)

Required scopes (fine-grained PAT recommended):

Resource Access
Target org → repositories Read and Write
Target org → projects (v1 & v2) Read and Write
Target org → members / teams (optional) Read

3. Token Storage on the Local Machine

  • PowerShell menu: tokens are encrypted with DPAPI (Windows-only) and stored at %LOCALAPPDATA%\GitHubMigrationSuite\creds.dat. The CurrentUser scope means the file is only readable by your Windows account on that machine.
  • Python pipeline: tokens are read from environment variables. The pipeline does not persist them to disk.
  • Tokens in config: the config file contains only the names of the environment variables (e.g. GH_SOURCE_TOKEN), never the tokens themselves.

4. Token Storage on GitHub Actions (CI)

When you run the suite from a GitHub Actions workflow, the tokens must be stored as encrypted repository or organisation secrets:

  1. Open the repository (or org) on GitHub

  2. SettingsSecrets and variablesActions

  3. Click New repository secret (or New organization secret)

  4. Create two secrets:

    Secret name Value
    GH_SOURCE_TOKEN The PAT (or installation token) for the source org
    GH_TARGET_TOKEN The PAT (or installation token) for the target org
  5. In your workflow file (.github/workflows/python-migration.yml or .github/workflows/powershell-migration.yml), reference the secrets as env: values:

    jobs:
      migrate:
        runs-on: ubuntu-latest
        steps:
          - uses: actions/checkout@v4
    
          - name: Set up Python
            uses: actions/setup-python@v5
            with:
              python-version: "3.11"
    
          - name: Install dependencies
            working-directory: ./python
            run: pip install -r requirements.txt
    
          - name: Run migration
            working-directory: ./python
            env:
              GH_SOURCE_TOKEN: ${{ secrets.GH_SOURCE_TOKEN }}
              GH_TARGET_TOKEN: ${{ secrets.GH_TARGET_TOKEN }}
            run: python migrate_python.py
  6. The workflow input repo_name lets you choose which repo to migrate at dispatch time; the runner substitutes it into config.json before executing the script.

Security notes for GitHub Actions:

  • Never echo the secrets in run: blocks
  • Mask the tokens in any debug output (the workflows above do not log them)
  • Prefer fine-grained PATs over classic tokens so that each migration only has the minimum required scopes
  • Rotate the tokens after the migration is complete

5. Pre-Migration Checklist

Before running a migration, verify:

  • The source token can read the source org's projects
  • The target token can create repositories, projects, and issues in the target org
  • For v1 → v2 cross-migration, both Classic Projects and Projects v2 are enabled in the target org's settings
  • The source repo's default branch name matches the local default
  • The work directory (default ../work) has enough disk space for the mirror

🧩 Configuration

Edit:

  • python/config.json
  • powershell/config.json

Example:

{
  "Source": {
    "TokenEnv": "GH_SOURCE_TOKEN",
    "Org": "old-org"
  },
  "Target": {
    "TokenEnv": "GH_TARGET_TOKEN",
    "Org": "new-org"
  },
  "Repository": {
    "Name": "example-repo",
    "Mirror": true
  },
  "Projects": {
    "Enabled": true,
    "ProjectNumbers": [1, 2]
  },
  "ProjectsV1": {
    "Enabled": false
  },
  "ProjectsV1ToV2": {
    "Enabled": true,
    "AutoYes": false
  },
  "ProjectsAutoDetect": true,
  "Discussions": {
    "Enabled": true,
    "Repo": "example-repo"
  }
}
Key Purpose
Source.TokenEnv Name of the env var that holds the source token
Source.Org Source organisation / user name
Target.TokenEnv Name of the env var that holds the target token
Target.Org Target organisation / user name
Repository.Name Repository to migrate
Repository.Mirror If true, push a full git mirror first
Projects.Enabled Enable Projects v2 migration (when applicable)
ProjectsV1.Enabled Enable Classic Projects v1 → v1 migration
ProjectsV1ToV2.Enabled Enable Classic Projects v1 → v2 cross-migration
ProjectsV1ToV2.AutoYes Skip interactive prompts (use in CI)
ProjectsAutoDetect Auto-detect v1/v2 and pick the right route
Discussions.Enabled Enable discussions migration
GhMigrate.* gh-migrate flags to pass through

▶ Running the Migration

PowerShell (recommended)

cd powershell
pwsh ./menu.ps1

The menu has 9 options. Option 9 is the smart entry point — it auto-detects the project versions and routes you to the right migration.

Python script

cd python
python migrate_python.py

GitHub Actions

The included workflows (.github/workflows/python-migration.yml and .github/workflows/powershell-migration.yml) can be triggered manually via workflow_dispatch. Provide the repository name when prompted.

The workflow:

  1. Checks out the migration suite
  2. Sets up Python / PowerShell
  3. Installs dependencies
  4. Reads the two secrets (GH_SOURCE_TOKEN, GH_TARGET_TOKEN)
  5. Overrides the repository.name in config.json with the supplied input
  6. Runs the migration

🛡 Security

  • Tokens never stored in plaintext (DPAPI encryption on Windows; env vars only elsewhere)
  • No external transmission of credentials
  • Logs do not contain tokens
  • Secrets are only ever read at the moment of an API call and never echoed back

🧪 Testing

Use the examples/ folder for:

  • Sample logs
  • Sample exports
  • Sample imports

📝 Notes

  • GitHub Projects v1 API is in "inertia-preview" mode; headers are included automatically.
  • Views in Projects v1 are reconstructed implicitly by preserving column/card order.
  • Cross‑repo project cards are supported if issues exist in target org.
  • Auto-detection is non-destructive: it only queries the source and target orgs to learn which project versions they use, then chooses the right migration path. The actual migration still asks for confirmation (unless auto_yes is enabled).

About

Migrate from Github Organization to Github Organization - selection of contents of choice to migrate/clone

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages