A CLI utility to migrate your GitHub user data, organizations, repositories, public keys, and more, to an instance of Gitea.
You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Devin W. Leaman 0e14eb1dd1 feat: updated start script to use doppler for secret management 11 months ago
data feat: added some more data regarding my GitHub repos 11 months ago
src feat: added src code and data files 11 months ago
.gitignore feat: updated .gitignore 11 months ago
.prettierignore feat: added some base files 11 months ago
.prettierrc feat: added some base files 11 months ago
LICENSE Initial commit 11 months ago
README.md chore: added requirements section and updated usage in README 11 months ago
doppler.yaml feat: added doppler config file to manage secrets 11 months ago
package.json feat: updated start script to use doppler for secret management 11 months ago
pnpm-lock.yaml chore: updated pnpm-lock.yaml 11 months ago
template.env feat: added the missing variables to template.env 11 months ago
tsconfig.json feat: updated tsconfig 11 months ago



A small utility written in TypeScript that processes a data file containing repos on GitHub and migrates them to a Gitea instance.


To use the migrator tool, you need the following pieces of information for the .env file. Rename the template.env file to just .env and then fill in the values as needed, with the GH_API_BASE_URL being the only optional value.

    • The base API URL for the instance of Gitea you're migrating your repositories to.
    • Example: https://git.4lch4.io/api/v1
    • An application token generated in the Settings/Applications page of your Gitea instance.
    • An optional URL for the GitHub API, defaults to the regular "https://api.github.com".
    • I'm not too sure why this is available, but it's an option just in case something changes in the future.
    • An authentication token for the GitHub API. It requires the following scopes, and I'll explain why each scope is necessary for which function of the migration process:
      • Repo (All)
        • Grants access to all private and public repositories so they can be listed and migrated.
        • Specifically used with the repos.listForAuthenticatedUser endpoint.
      • admin:org -> read:org
        • Gitea supports the creation of orgs, so this scope enables us to use the [orgs] endpoint to list the orgs you're a part of and recreate those orgs in Gitea, along with their repos.
      • admin:public_key -> read:public_key
        • Your SSH public keys can be migrated over to your Gitea instance, and this scope grants us access to read the SSH public keys you have saved to your account so we can do the migration.
      • admin:repo_hook -> read:repo_hook
        • As Gitea supports webhooks and hooks for repos, similar to GitHub, being able to read the hooks on each repo enables the utility to copy/migrate those over to Gitea as well.
      • user -> read:user
        • Lets us read all the information about the user so we can copy it over to their account on Gitea.
      • project -> read:project
        • Lets us list all GitHub projects so we can copy them over to Gitea as well.


In order to use the tool, you must rename the template.env file to .env and fill it with the information mentioned above. Once the .env file is ready to go, you can transpile the code and run it like so:

# Transpile the TypeScript to JavaScript.

# Begin execution of the utility.
node ./dist/index.js

!!!note Default Sleep Timer Depending on the amount of repos you have on GitHub, this can take quite some time to execute. By default, each time a new repository is gonna be migrated a message is displayed and a 5 second sleep is started, then the migration is actually started. This is specifically so the user can cancel the utility while it's running without causing a migration error.

If you cancel the app while it's migrating a repository then the migration will fail and you'll have to restart it, this is why there's the 5 second sleep. To disable it, set `DISABLE_SLEEP=true` in the `.env` file.