Find a file
2026-05-20 15:37:46 -06:00
.idea Add migration scripts and initial project setup: 2025-10-11 18:07:47 +03:00
.gitignore Add migration scripts and initial project setup: 2025-10-11 18:07:47 +03:00
migrate_docker_skopeo.py feat: add package pagination, --dry-run and --delete-before-migrate flags, enhance help output 2026-05-17 21:33:10 -06:00
migrate_gitea_to_forgejo.py fix: use gitea migration mode, add a --delete-before-migrate flag 2026-05-17 21:26:05 -06:00
README.md docs: update readme to record changes made 2026-05-20 15:37:46 -06:00

Gitea to Forgejo Migrator

This repository contains two migration scripts:

  • migrate_gitea_to_forgejo.py — migrate users/organizations and repositories from a Gitea instance to a Forgejo instance via REST API.
  • migrate_docker_skopeo.py — migrate container images between registries (e.g., Gitea/Forgejo registries) using skopeo and the OCI API.

Both scripts support pagination, dry-run mode, and delete-before-migrate for re-running migrations.

Attribution: These scripts and this documentation were generated with the assistance of AI Grok.

Quick setup (dependencies)

  • Create and activate a virtual environment (recommended):
    • Windows (PowerShell):
      • python -m venv .venv
      • .venv\Scripts\Activate.ps1
    • Linux/macOS:
      • python3 -m venv .venv
      • source .venv/bin/activate
  • Install Python dependencies:
    • pip install --upgrade pip
    • pip install requests
  • Install external tools required by migrate_docker_skopeo.py:
    • skopeo
      • Linux (Debian/Ubuntu): sudo apt-get update && sudo apt-get install -y skopeo
      • Linux (RHEL/CentOS/Fedora): sudo dnf install -y skopeo
      • macOS (Homebrew): brew install skopeo
      • Windows: https://github.com/passcod/winskopeo/releases
  • Verify installations: skopeo --version

1) migrate_gitea_to_forgejo.py

Migrate repositories from a source Gitea to a target Forgejo. It can:

  • Migrate all organizations and their repositories.
  • Migrate repositories for a specific user (owner).
  • Ensure the target user/organization exists (creating organizations if missing, and falling back to the current authenticated user if the specified target user is absent).
  • Migrate issues, pull requests, releases, labels, milestones, wiki, and LFS data (requires service: gitea — the default).

Prerequisites

  • Python 3.8+
  • requests library (pip install requests)
  • API tokens for both source (Gitea) and target (Forgejo) instances.
  • Network access between the machine running the script and both instances.

Usage

python migrate_gitea_to_forgejo.py <source_url> <source_token> <target_url> <target_token> <owner_name> <target_owner> [--include-sql] [--dry-run] [--delete-before-migrate]

Positional arguments

Argument Description
source_url Base URL of the Gitea instance (e.g., https://gitea.example.com)
source_token Gitea API token with permissions to list orgs/users and read repositories
target_url Base URL of the Forgejo instance (e.g., https://forgejo.example.com)
target_token Forgejo API token with permissions to create orgs/repos and perform migrations
owner_name Source owner (username) to migrate user repos from. If empty, this step is skipped.
target_owner Target username in Forgejo. Falls back to the token's current user if not found.

Optional flags

Flag Description
--include-sql Generate update_timestamps.sql to restore original updated_at timestamps in the Forgejo database. Run the SQL against Forgejo's database after migration (stop Forgejo first).
--dry-run Verify connections and list all repos with details (branch, size, issues, PRs, etc.) without migrating anything.
--delete-before-migrate Delete existing repos on Forgejo before re-migrating them. Useful when re-running with corrected settings (e.g., after switching from service: git to service: gitea).

Help output

usage: migrate_gitea_to_forgejo.py [-h] [--include-sql] [--dry-run]
                                   [--delete-before-migrate]
                                   source_url source_token target_url
                                   target_token owner_name target_owner

Migrate repositories from Gitea to Forgejo.

positional arguments:
  source_url            Base URL of the Gitea instance
  source_token          Gitea API token
  target_url            Base URL of the Forgejo instance
  target_token          Forgejo API token
  owner_name            Source owner (username) to migrate user repos from.
                        Empty to skip.
  target_owner          Target username in Forgejo.

options:
  -h, --help            show this help message and exit
  --include-sql         Generate SQL file to restore original updated_at
                        timestamps in Forgejo database
  --dry-run             Verify connections and list repos without migrating
                        anything
  --delete-before-migrate
                        Delete existing repos on Forgejo before re-migrating
                        them

Example

python migrate_gitea_to_forgejo.py https://gitea.example.com <GITEA_TOKEN> https://forgejo.example.com <FORGEJO_TOKEN> alice alice

Behavior:

  • If user "alice" exists in Forgejo, her ID is used as the migration target.
  • If user "alice" does not exist, the script falls back to the current user associated with <FORGEJO_TOKEN>.
  • After user repos, the script migrates all organizations and their repositories. Organizations are created if missing.

Dry-run example

python migrate_gitea_to_forgejo.py https://gitea.example.com <GITEA_TOKEN> https://forgejo.example.com <FORGEJO_TOKEN> alice alice --dry-run

Lists all repos with details like:

Processing repository: my-repo from alice
  Default branch: main | Size: 1.2 MB | Language: Python
  Issues: 3 open
  Pull requests: 5 open
  Stars: 5 | Forks: 2 | Watchers: 1
  Created: 2024-01-15T10:30:00Z | Last pushed: 2024-03-20T14:22:00Z

Re-migrating with corrected settings

If you already ran the migration and repos exist on Forgejo but are missing issues/PRs (because the initial run used service: git), re-run with --delete-before-migrate:

python migrate_gitea_to_forgejo.py https://gitea.example.com <GITEA_TOKEN> https://forgejo.example.com <FORGEJO_TOKEN> alice alice --delete-before-migrate

This deletes each existing repo on Forgejo and re-migrates it with the correct service: gitea setting, which fetches issues, PRs, releases, labels, and milestones via the Gitea API.

Restoring timestamps

With --include-sql, the script generates update_timestamps.sql. After migration:

systemctl stop forgejo
psql -d forgejo -f update_timestamps.sql
systemctl start forgejo

This restores the original updated_at timestamps from Gitea, which otherwise get set to the migration time.


2) migrate_docker_skopeo.py

Migrate container images (all repos and their tags) from one registry to another using skopeo. The script uses the OCI API to list repositories and tags, then performs skopeo copy for each tag.

Prerequisites

  • Python 3.8+
  • requests library (pip install requests)
  • skopeo installed and available in PATH
  • Valid credentials for both source and target registries (username + token)
  • Network access between the machine running the script and both registries

If your registries use self-signed certificates, the script passes --src-tls-verify=false and --dest-tls-verify=false. Remove those flags for production-grade TLS verification.

Usage

python migrate_docker_skopeo.py <source_url> <source_user> <source_token> <target_url> <target_user> <target_token> [--dry-run] [--delete-before-migrate]

Positional arguments

Argument Description
source_url Base URL of the source registry (e.g., https://git.example.com)
source_user Username for source registry auth
source_token Token/password for source registry
target_url Base URL of the target registry (e.g., https://forgejo.example.com)
target_user Username for target registry auth
target_token Token/password for target registry

Optional flags

Flag Description
--dry-run List all images and tags without copying anything.
--delete-before-migrate Delete existing images on target before re-copying them.

Help output

usage: migrate_docker_skopeo.py [-h] [--dry-run] [--delete-before-migrate]
                                source_url source_user source_token target_url
                                target_user target_token

Migrate container images from Gitea to Forgejo using skopeo.

positional arguments:
  source_url            Base URL of the source Gitea instance (e.g.,
                        https://git.example.com)
  source_user           Username for source registry authentication
  source_token          Token/password for source registry authentication
  target_url            Base URL of the target Forgejo instance (e.g.,
                        https://forgejo.example.com)
  target_user           Username for target registry authentication
  target_token          Token/password for target registry authentication

options:
  -h, --help            show this help message and exit
  --dry-run             List all images without copying anything
  --delete-before-migrate
                        Delete existing images on target before re-copying
                        them

Example

python migrate_docker_skopeo.py https://git.example.com alice SRC_TOKEN https://forgejo.example.com alice DST_TOKEN

The script will:

  • Fetch the repositories catalog via /v2/_catalog (paginated)
  • For each repository, fetch tags via /v2/<repo>/tags/list (paginated)
  • For each tag, run skopeo copy from source to target
  • Print progress and a final summary with copied/skipped/failed counts

Troubleshooting

  • Ensure tokens are valid and have required permissions (read on source, write on target).
  • If you get TLS/SSL errors, review whether to keep or remove the --*-tls-verify flags. For self-signed setups, they may be necessary.
  • Make sure skopeo is installed and discoverable (skopeo --version works in your shell).
  • If using Windows, run from a shell that can execute skopeo (e.g., PowerShell with skopeo in PATH).

Development notes

  • All console output and comments are in English.
  • Both scripts paginate API responses (50 items per page for Gitea/Forgejo REST API, 100 for OCI registry catalog/tags).
  • The repo migration uses service: gitea to ensure issues, PRs, releases, labels, and milestones are fetched via the Gitea API (not just git data).