Getting startedIntroduction
Introduction
joflux moves a GitHub organization's repositories into Forgejo or Codeberg in five stages, each leaving JSON you can read.
joflux moves the repositories of a GitHub organization into a Forgejo-compatible instance such as Codeberg. It exports an inventory of the organization, has Forgejo migrate every repository in it, confirms they arrived, checks what came across, and archives the GitHub originals once you’re happy with the result.
Each of those steps is its own command, and each one writes what it did as JSON in
migration_output/. You can read exactly what happened, re-run a stage, and keep the files as the
record of the move. The default install needs nothing beyond the Python 3.11+ standard library.
What it doesn’t do
Section titled “What it doesn’t do”joflux copies each repository once. It sends Forgejo a normal migration rather than a mirror, so the copy doesn’t keep following GitHub afterwards, and changes pushed to GitHub after the migration stay there. It never deletes anything on GitHub either: the last stage archives the originals rather than removing them.
How a run works
Section titled “How a run works”-
exportreads the organization from GitHub and saves the list asrepos-inventory.json. Nothing changes on either side, so it’s the safe first step. -
migratereads that inventory and has Forgejo migrate each repository, waiting for each import to finish and logging what happened inmigration-log.json. -
monitorrechecks any migration Forgejo didn’t answer for in time, and records what it can tell about each inmigration-status.json. -
verifychecks every repository in the inventory on the target and writes its size, its issue, pull request, label and release counts, and whether it has a wiki toverification-report.json. -
archiveasks you to confirm, then archives the GitHub originals thatverifyrecorded as verified and logs each one inarchive-log.json.
Every stage after export works from the files the earlier stages wrote, so you can stop between
stages, read the JSON, and carry on when you’re ready. A stage that only partly worked exits with
code 1, which lets a script stop at the first one that didn’t go cleanly.