gitlab to forgejo migrator script; mod of
Go to file
2024-03-01 22:26:13 +01:00
.gitignore first commit 2018-12-18 12:28:13 +01:00 Add comment 2019-01-01 11:08:59 +01:00
LICENSE first commit 2018-12-18 12:28:13 +01:00 * various major fixes 2024-03-01 22:17:44 +01:00 + general tips 2024-03-01 22:26:13 +01:00
requirements.txt add requirements.txt 2019-12-16 11:13:47 +01:00

Gitlab to Gitea migration script.

This script uses the Gitlab and Gitea API's to migrate all data from Gitlab to Gitea.

This script support migrating the following data:

  • Repositories & Wiki (fork status is lost)
  • Milestones
  • Labels
  • Issues (no comments)
  • Users (no profile pictures)
  • Groups
  • Public SSH keys

Tested with Gitlab Version 13.0.6 and Gitea Version 1.11.6.


Change items in the config section of the script.

Install all dependencies via python -m pip install -r requirements.txt and use python3 to execute the script.

How to use with venv

To keep your local system clean, it might be helpful to store all Python dependencies in one folder. Python provides a virtual environment package which can be used to accomplish this task.

python3 -m venv migration-env
source migration-env/bin/activate
python3 -m pip install -r requirements.txt

Then start the migration script python3

2024 addendum

things that i fixed:

  • events are posted as the correct user
  • issue comments
  • weird unicode problems with usernames
  • option to disable the buggy joining algo
  • users are properly made admins now

things that don't work but i don't care (incomplete list xD):

  • downloading media from issues

other tips and tricks:

  1. for backcompat, copy /etc/gitlab/*ssh* onto forgejo's ssh directory; for me it's data/ssh/ (docker)
  2. I wrote those nginx rules to make link rot a bit better:
    location ~ /(.*)/(.*)/-/tree/(.*) {
        return 301$1/$2/src/branch/$3;

    location ~ /(.*)/(.*)/-/commits/(.*) {
        return 301$1/$2/commits/branch/$3;

    location ~ /(.*)/(.*)/-/merge_requests {
        return 301$1/$2/pulls;

    location ~ /(.*)/(.*)/-/(.*) {
        return 301$1/$2/$3;

YMMV. didn't test them much.

  1. every user created with this script will have the password reset flag set, even if you set them to login through oauth2. I fixed that through psql: UPDATE public."user" SET must_change_password = 'f';
  2. check this link if in general doubt