GitHub
Open Source · MIT License

Mirror GitHub repos to GitLab,
automatically.

Don't keep all your code in one place. This tool backs up every repository from your GitHub account to GitLab — private stays private, public stays public.

What it does

🔒

Visibility-safe

Private repos are never created as public. Defaults to private when in doubt.

♻️

Idempotent

Safe to re-run. Existing GitLab repos receive incremental pushes, not duplicates.

🌿

Full mirror

All branches and tags are transferred via git clone --mirror.

🔍

Dry-run mode

Preview every action before a single write happens.

🎯

Selective backup

Filter repos by glob pattern — back up only what you need.

🪟

Works on Windows

Handles read-only .git files. Tested on Windows 10 / PowerShell.

Quick Start

1

Prerequisites

Python 3.11+, Git in your PATH, and SSH keys registered on both GitHub and GitLab.

2

Create API tokens

GitHub token with repo scope  ·  GitLab token with api scope

3

Clone, configure, run

# Clone the repo
git clone git@github.com:paladini/backup-github-to-gitlab.git
cd backup-github-to-gitlab

# Install dependencies
pip install -r requirements.txt

# Copy and edit the config files
cp config.example.yaml config.yaml   # set github.username and gitlab.username
cp .env.example .env                  # set GITHUB_TOKEN and GITLAB_TOKEN

# Preview — no changes made
python backup.py --dry-run

# Run the backup
python backup.py

Usage

# Back up all personal repositories
python backup.py

# Preview what would happen — no writes
python backup.py --dry-run

# Back up only repos matching a pattern
python backup.py --filter "myproject-*"

# Include forks (skipped by default)
python backup.py --include-forks

# Verbose output (useful for debugging SSH issues)
python backup.py --verbose

# Use a different config file
python backup.py --config /path/to/config.yaml

Configuration

Copy config.example.yamlconfig.yaml and set your usernames:

github:
  username: your-github-username

gitlab:
  username: your-gitlab-username
  url: https://gitlab.com        # change only for self-hosted GitLab

backup:
  include_forks: false           # default: false
  include_archived: true         # default: true
  temp_dir: ./tmp

Tokens go in .env — never in the config file, never in logs.

Known Limitations

Feature Status
Git LFS LFS objects are not transferred (git clone --mirror skips them)
Organization repos Not included in v1 — planned for v2 with --include-orgs
GitLab pull mirroring Requires GitLab Premium for private repos — GitHub Actions alternative planned for v2