gitcaskDocsGitHub

Migrating from Gitea

Copy the Git history, branches, tags and LFS objects of every repository of one Gitea owner into gitcask, without touching Gitea.

What moves

The migrator writes straight to the bucket through the same WAL import path as gitcask import. No gitcask server needs to be running.

Gitea
mirror clone
WAL import into the bucket
LFS objects
recorded complete
Gitea, then a mirror clone on the migration host, then the WAL import into the bucket, then LFS objects.

Prerequisites

Gitea token
read:repository and read:user, plus read:organization for an organization owner. Test it against private repositories first.
Tools
git on PATH, and git-lfs when any source repository uses LFS.
gitcask config
A config file with access to the destination S3 bucket.
Disk
Room for about the largest repositories processed at once: each worker holds one mirror clone plus its pack cache. Default concurrency is 2.
Network and state
Access to both Gitea and S3, and durable local storage for the state file.

Procedure

  1. Preview

    Lists destination names and Gitea-reported sizes. Nothing is cloned or written.

    export GITEA_TOKEN='<token>'
    gitcask --config gitcask.toml migrate gitea \
      --url https://git.example.com \
      --owner acme \
      --to-owner acme \
      --dry-run

    Repeat --repo to select repositories.

    gitcask --config gitcask.toml migrate gitea \
      --url https://git.example.com \
      --owner acme \
      --repo api --repo web \
      --dry-run
  2. Run

    Without --to-owner, the destination owner is the Gitea owner. Without --state, the state file is ./gitcask-migrate-state.json. One failed repository does not stop the others; any failure exits nonzero with a list of reasons.

    gitcask --config gitcask.toml migrate gitea \
      --url https://git.example.com \
      --owner acme \
      --to-owner imported-acme \
      --concurrency 2 \
      --state /var/lib/gitcask-migration/acme.json
  3. Resume

    Run the exact same command with the same state path. Completed repositories are skipped; do not edit the state file by hand.

  4. Verify

    Keep Gitea read-only. The show-ref diff must be empty and the commit counts must match.

    git clone --mirror https://git.example.com/acme/api.git gitea-api.git
    git clone --mirror https://gitcask.example.com/imported-acme/api.git gitcask-api.git
    
    git -C gitea-api.git show-ref | sort > /tmp/gitea-api.refs
    git -C gitcask-api.git show-ref | sort > /tmp/gitcask-api.refs
    diff -u /tmp/gitea-api.refs /tmp/gitcask-api.refs
    
    git -C gitea-api.git rev-list --all --count
    git -C gitcask-api.git rev-list --all --count
    git -C gitcask-api.git fsck --full
  5. Cut over

    Change client or platform routing only after verification. To roll back, route clients back to Gitea; no reverse conversion is needed.

What is not migrated

Platform data
Issues, pull requests, reviews, releases, packages, wiki, Actions, users, teams, permissions, hooks and repository settings.
Other refs
Only refs/heads/*, refs/tags/* and the symbolic HEAD target. Pull-request refs, notes and remote-tracking refs stay behind.
Large LFS objects
An object above lfs.max_object_bytes fails that repository.
Names
Must satisfy gitcask’s ASCII naming rules; no rewriting.
SSH
Only the Gitea HTTP clone URL is used.
Submodules
Copied as Git content; referenced repositories and URLs are not migrated.
One migrator
Never run two migrators with the same state file or overlapping destinations.