DevSecOps & Platform

Large-Scale Migration from GitLab to GitHub Operations

How EasyLauncher engineered a zero-downtime migration of 520+ mission-critical repositories, 1,200+ complex CI/CD pipelines, and enterprise security policies from self-hosted GitLab to GitHub Enterprise without interrupting daily release velocity.

7 min read
Large-Scale Migration from GitLab to GitHub Operations

Executive Summary

As enterprises scale past thousands of engineers, source code management and continuous integration systems evolve into foundational utilities. For a high-growth technology enterprise supporting over 2,000 active software engineers and 520+ production repositories, managing a heavily customized, self-hosted GitLab cluster had become an operational bottleneck.

The organization experienced escalating runner infrastructure costs, frequent maintenance outages during cluster upgrades, and fragmented tooling across engineering pods. Leadership made the strategic decision to standardize on GitHub Enterprise Cloud to unlock native AI developer tooling (GitHub Copilot), reduce self-hosted runner overhead, and align with modern cloud-native standards.

“A migration across 500+ microservices cannot rely on a weekend prayer. It requires automated transpilation, continuous delta replication, and deterministic validation before a single developer is cut over.”

EasyLauncher DevOps & Platform Architecture Practice

EasyLauncher was engaged to design and execute an end-to-end migration program. The non-negotiable requirement: zero developer downtime, zero code freezes during sprint deliverables, complete preservation of commit SHAs and audit history, and turnkey conversion of over 1,200 .gitlab-ci.yml pipeline definitions into production-ready GitHub Actions workflows.

Scale and Pre-Migration Risk Analysis

Migrating source code at enterprise scale involves far more than running git push. Prior to developing automation scripts, EasyLauncher conducted a deep architectural risk analysis across four operational dimensions:

Repository Complexity

520+ Repositories & 1.8 TB of Data

Spanned multi-branch poly-repos and dense monorepos with gigabytes of Git LFS (Large File Storage) artifacts, historical release tags, and deep reflogs that could not afford corruption.

CI/CD Pipeline Entanglement

1,200+ Active Pipeline Definitions

Deeply nested include: templates, multi-project downstream trigger pipelines, custom Docker-in-Docker runners, and intricate artifact sharing between build stages.

Release Train Continuity

12,000+ Daily Pipeline Executions

High deploy velocity meant engineering release trains could not halt for a multi-day freeze. Dual operations were required during the validation phase.

Security & Compliance

SOC 2 & ISO 27001 Protections

Required audit trail preservation for 45,000+ merge requests and conversion of 350+ branch protection rules and CODEOWNERS approvals into GitHub Rulesets.

The 4-Phase Migration Architecture

To eliminate human error and maintain predictability, EasyLauncher designed an automated 4-phase framework executing parallel data synchronization alongside deterministic code transpilation.

1Phase 1: Automated Discovery & Profiling

We built an automated crawler using the GitLab REST and GraphQL APIs that inspected every group, subgroup, and project across the enterprise instance. The scanner generated a structured catalog classifying repositories into three migration tiers:

  • Tier 1 (Standard): Standalone microservices with linear CI pipelines (build, test, deploy). (65% of repos)
  • Tier 2 (Artifact-Heavy): Services utilizing Git LFS, container registry caching, and multi-stage matrix testing. (25% of repos)
  • Tier 3 (Complex / Monorepo): Monorepos with cross-project trigger tokens, shared pipeline template includes, and custom runner hardware tags. (10% of repos)

This profiling allowed the migration team to establish parallel migration waves, tackling standardized repositories through automated pipelines while focusing specialized platform engineering on Tier 3 monorepos.

2Phase 2: CI/CD Pipeline Transpilation Engine

Manually rewriting 1,200+ .gitlab-ci.yml files into GitHub Actions would have taken months and introduced substantial syntax bugs. EasyLauncher engineered an automated Abstract Syntax Tree (AST) transpiler tailored to the client's pipeline patterns:

  • Mapped GitLab stages and needs into GitHub Actions jobs with explicit directed acyclic graph (DAG) dependencies.
  • Converted shared include: templates into modular GitHub Reusable Workflows (workflow_call) and Composite Actions.
  • Replaced static GitLab runner tags with custom GitHub Actions runner labels and GitHub-hosted large runners for resource-intensive compilation steps.
  • Integrated automatic linting with actionlint to validate generated YAML syntax before committing to migration branches.

3Phase 3: Continuous Asynchronous Delta Mirroring

The critical mechanism enabling zero downtime was our continuous delta mirroring architecture. Rather than executing a one-time high-risk transfer, EasyLauncher deployed a distributed sync cluster running inside AWS:

  1. Baseline Mirror Clones: Executed git clone --mirror across all 520+ repositories, capturing branches, tags, and commit refs into bare git mirrors.
  2. Dedicated Git LFS S3 Conduit: Streamed heavy Git LFS binaries directly into GitHub Enterprise LFS storage via parallel multipart transfers, bypassing client network choke points.
  3. Scheduled Delta Sync Cron: Polled GitLab for new commits every 30 minutes, pushing incremental changes directly to corresponding GitHub destination repositories.

Because the synchronization operated continuously in the background for two weeks prior to cutover, the final cutover delta was reduced from 1.8 TB down to mere megabytes of last-minute commits.

4Phase 4: Zero-Friction Cutover & Remote Switch

The final cutover took place on a scheduled Saturday morning within a targeted 45-minute window:

  • Toggled source GitLab projects into read-only archive mode via API automation to prevent diverging commits.
  • Triggered the final delta synchronization pass, syncing the final batch of commits in under 12 minutes.
  • Activated production GitHub Actions workflows and updated webhooks for ArgoCD, Jira, and monitoring collectors.
  • Distributed a lightweight CLI switcher tool (easylauncher-git-switch) that automatically detected active branches and re-pointed developer git remotes from GitLab to GitHub with a single terminal command.

Architecture Comparison: GitLab vs. GitHub Enterprise

The transition modernized core development infrastructure across key operational areas:

DimensionSelf-Hosted GitLabGitHub EnterpriseOperational Impact
CI/CD EngineGitLab Runner cluster (self-managed VMs)GitHub Actions (hosted + ephemeral self-hosted)-38% run duration, auto-scaled
Authentication & SecretsLong-lived static AWS secret keys in CI varsOIDC Federation with AWS IAM & HashiCorp VaultZero static long-lived credentials
Branch GovernanceManual per-repo branch protection settingsOrganization-wide GitHub Repository Rulesets100% policy enforcement across 520+ repos
Identity GovernanceDirect LDAP sync with periodic driftEnterprise Managed Users (EMU) via Okta SCIMReal-time offboarding & team sync
Platform Maintenance2 FTEs dedicated to PostgreSQL/Gitaly clusterZero cluster maintenance overhead$240,000 annual maintenance savings

CI/CD Transpilation Blueprint: From GitLab CI to GitHub Actions

The core technical challenge during migration was converting complex .gitlab-ci.yml patterns into idiomatic GitHub Actions without degrading developer experience. Below is a representative before-and-after blueprint from a high-throughput microservice:

Legacy: .gitlab-ci.yml (Self-Hosted Runner & Static Credentials)YAML
stages:
  - build
  - test
  - deploy

variables:
  DOCKER_DRIVER: overlay2

default:
  before_script:
    - npm ci --prefer-offline

compile_and_test:
  stage: test
  image: node:20-alpine
  script:
    - npm run test:coverage
    - npm run build
  artifacts:
    paths:
      - dist/
    expire_in: 1 week
  rules:
    - if: '$CI_COMMIT_BRANCH == "main"'

deploy_production:
  stage: deploy
  needs: ["compile_and_test"]
  image: amazon/aws-cli:latest
  script:
    - aws configure set aws_access_key_id $AWS_ACCESS_KEY_ID
    - aws configure set aws_secret_access_key $AWS_SECRET_ACCESS_KEY
    - aws s3 sync dist/ s3://enterprise-prod-assets/
  rules:
    - if: '$CI_COMMIT_BRANCH == "main"'
Modernized: .github/workflows/deploy.yml (OIDC Authentication & Caching)YAML
name: Build and Production Deployment

on:
  push:
    branches: [ main ]

permissions:
  id-token: write  # Enables secure OIDC authentication with AWS IAM
  contents: read

jobs:
  test-and-build:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout Code
        uses: actions/checkout@v4

      - name: Setup Node.js 20
        uses: actions/setup-node@v4
        with:
          node-version: 20
          cache: 'npm'

      - name: Install & Run Test Suite
        run: |
          npm ci
          npm run test:coverage
          npm run build

      - name: Archive Production Artifacts
        uses: actions/upload-artifact@v4
        with:
          name: production-dist
          path: dist/
          retention-days: 7

  deploy:
    needs: test-and-build
    runs-on: ubuntu-latest
    environment: production
    steps:
      - name: Download Build Artifacts
        uses: actions/download-artifact@v4
        with:
          name: production-dist
          path: dist/

      - name: Configure AWS Credentials via OIDC (Zero Static Keys)
        uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: arn:aws:iam::123456789012:role/GitHubActionsProductionDeploy
          aws-region: us-east-1

      - name: Deploy Assets to S3
        run: aws s3 sync dist/ s3://enterprise-prod-assets/ --delete

Notice key modernizations: static credentials (AWS_ACCESS_KEY_ID) were replaced with short-lived OpenID Connect (id-token: write) authentication, and dependency caching was streamlined via actions/setup-node, cutting execution time by nearly 40%.

Enterprise Governance, Secrets & OIDC Authentication

Security and audit compliance were paramount throughout the migration. EasyLauncher established an automated governance framework that exceeded previous internal controls:

  • OpenID Connect (OIDC) Federation: We eliminated over 400 static cloud credentials previously stored in GitLab CI variables. By configuring OIDC federation between GitHub Actions and AWS IAM / HashiCorp Vault, workflows now request short-lived, cryptographically signed JWT tokens with 15-minute expirations.
  • Organization-Wide Rulesets: Rather than configuring branch protection rules per repository, we instituted centralized GitHub Enterprise Rulesets. Every repository inherited requirements for signed commits (GPG/SSH), linear commit history, mandatory vulnerability scanning before merge, and approval from designated CODEOWNERS.
  • Identity & SCIM Provisioning: Configured Enterprise Managed Users (EMU) linked directly to Okta. Role-based access control (RBAC) was mapped seamlessly: engineering managers and platform leads received administrative delegation, while developer groups were synced automatically with zero manual onboarding tickets.

Verified Outcomes & Infrastructure ROI

Following the final cutover and workstation configuration roll-out, the organization transitioned 100% of its engineering operations to GitHub with immediate measurable benefits:

0 Minutes
Developer Downtime

Engineers pushed code until Friday evening on GitLab and resumed on Monday morning on GitHub without interrupted releases or broken local branches.

38% Faster
Average CI/CD Execution

Workflow parallelization, native dependency caching, and modern GitHub runner sizing reduced average build and test cycles from 14 minutes down to 8.6 minutes.

$240,000+
Annual Cost Reduction

Eliminated dedicated runner VM fleets, GitLab cluster maintenance contracts, and redundant backup infrastructure.

100% Parity
Commit SHA & Ref Integrity

Every historical commit, tag, branch, and Git LFS binary preserved exact byte-for-byte cryptographic parity across all 520+ repositories.

With the migration successfully executed, the enterprise immediately enabled GitHub Copilot across all 2,000+ developers, accelerating feature delivery and unifying code review, security scanning, and deployments into a single cohesive developer platform.

Frequently Asked Questions

Key architectural and operational questions engineering leaders face when planning large-scale repository migrations:

How do you preserve Git commit histories, tags, and commit SHAs during a GitLab to GitHub migration?

We utilize bare mirror clones via git clone --mirror combined with raw ref updates. Because Git commit SHAs are cryptographic hashes of tree contents, parent SHAs, commit messages, and author timestamps, bare repository mirroring guarantees 100% byte-for-byte SHA preservation. In addition, Git LFS objects are copied directly to GitHub LFS storage via batch API sync without rewriting git history.

How are complex .gitlab-ci.yml pipelines with multiple stages and includes converted to GitHub Actions?

We built an automated transpilation engine that parses GitLab CI abstract syntax trees (AST). GitLab stages and needs directives are compiled into GitHub Actions jobs with explicit dependency graphs. Reusable templates (include:project) are converted into GitHub Reusable Workflows (workflow_call) and Composite Actions, preserving modularity and eliminating pipeline code duplication.

How do you achieve zero developer downtime without freezing development for weeks?

Rather than enforcing a prolonged code freeze, we establish an asynchronous delta mirroring pipeline. An initial baseline sync mirrors all 520+ repositories in the background. An automated sync runner then continuously replays incremental branch updates, new tags, and pull request refs every 30 minutes. During the final 45-minute weekend cutover window, GitLab write access is locked, the final delta is pushed, and developers re-point their remotes on Monday with zero lost productivity.

How are GitLab CI/CD environment variables and credentials migrated securely?

We audited all GitLab CI variables to eliminate hardcoded long-lived cloud credentials. During migration, we replaced static AWS and cloud access keys with temporary OpenID Connect (OIDC) authentication between GitHub Actions and cloud IAM roles. Any remaining sensitive secrets were programmatically encrypted and injected into GitHub Actions Repository Secrets and Environment Secrets with restricted branch scoping.

How does user access and team permissions map between GitLab Groups and GitHub Organizations?

GitLab hierarchical groups and subgroups are mapped into GitHub Enterprise Teams backed by SCIM and SAML SSO integration with the enterprise Identity Provider (such as Okta). Branch protection rules and CODEOWNERS policies are automatically translated into GitHub Repository Rulesets, ensuring strict compliance with SOC 2 and ISO 27001 policies from day one.

DevOps & Platform Architecture

Planning an Enterprise Source Code or Cloud Migration?

EasyLauncher engineers automated, zero-downtime migration pipelines for complex codebases, databases, and CI/CD ecosystems. Explore our specialized services or talk with our migration architects.