Migrate from GitHub to Gitea

A practical plan for moving repositories, issues, pull requests and Actions from GitHub to a self-hosted Gitea, with clear notes on what does not carry over.

On this page

How to migrate from GitHub to Gitea without losing project history

If your GitHub renewal, licensing change or residency requirement is pushing you toward self-hosting, Gitea's built-in migration form carries repositories across with their issues and pull requests, provided you supply a GitHub username, and Git history itself moves by clone or mirror. The migration form is the fastest way to bring over metadata, but it is not a full copy of everything GitHub holds, so the work is planning what comes across, what must be rebuilt, and who signs off. In most organizations the platform or DevOps team runs this, sometimes with an implementation partner for the cutover, and it helps to have a security owner review access and secrets before any repository goes live. Start with an inventory: which repositories are active, which have large histories or binary files that GitHub's limits make awkward, and which teams depend on issues, pull requests and review comments. Run a test migration of a representative repository into a non-production Gitea instance and compare what arrived with the source. Plan for two areas of manual work. The first is Actions: Gitea Actions uses the .gitea/workflows directory and is designed to be compatible with GitHub Actions wherever possible, but workflows still need to be moved, reviewed and tested because compatibility is not identical. The second is secrets, which do not export from GitHub, so every value must be re-created by its owner in Gitea. Self-hosted Gitea is a software and support choice, not only a location choice. You take on the upgrades, backups, access control and monitoring that GitHub operates for you, and you choose whether to rely on the community project or on commercial support from CommitGo, which sells Gitea Enterprise. Confirm with the vendor which support and feature tier fits your controls before you commit, and ask any implementation partner for a fixed scope covering migration, testing and cutover in writing.

Which GitHub capabilities map to Gitea and which need rework

This table maps the main GitHub capabilities a team uses to their Gitea equivalents and marks each as clean, needs rework or gap. Read the status column first, then the notes, and confirm the items marked for rework or gap against your own repositories and Gitea version before you schedule the cutover.

CapabilityGitea equivalentStatus and notes
Repositories, branches and Git historyGitea Git hosting with clone or mirror importClean. History moves with a clone or mirror, and the built-in migration form can also import the repository from GitHub.
Pull requests and reviewsGitea pull requests and code reviewNeeds rework. Confirm that review comments, approvals and linked issues import as expected, and test a sample of open pull requests.
Issues, labels and milestonesGitea issue tracker with the GitHub migration optionNeeds rework. Migrating issues requires at least a GitHub username. Check label colors, milestone due dates and issue links after import.
WikisGitea repository wikiNeeds rework. Confirm wiki content migrates for your repositories, and plan a manual copy for any wiki that does not.
Releases and release assetsGitea releasesNeeds rework. Verify that release notes and attached binaries are present, and re-upload large assets if needed.
Actions workflowsGitea Actions using the .gitea/workflows directoryNeeds rework. Gitea Actions is designed to be GitHub Actions compatible where possible, so move or copy workflows and test each one.
Marketplace actions and runnersGitea Actions runners and third-party actionsGap to confirm. Check every action your workflows call and confirm that each one works on Gitea runners before cutover.
Actions secrets and variablesGitea Actions secrets set in the repository or organizationGap. Secrets do not export from GitHub, so every value must be re-created from its source system.
PackagesGitea built-in package registriesNeeds rework. Confirm each registry type you use is supported, and update client configuration and tokens.
Branch protection rulesGitea branch protectionNeeds rework. Recreate rules by branch pattern, and confirm required reviews and status checks match your policy.
Teams and permissionsGitea organizations and teamsNeeds rework. Map GitHub teams to Gitea teams and check repository access levels one organization at a time.
SAML single sign-on, audit logging and IP allowlistingGitea Enterprise, a separate commercial optionGap in the community edition. Gitea Enterprise adds SAML 2.0, audit logging and IP allowlisting. Ask CommitGo and your own compliance team whether these are required.
GitHub Enterprise Server-only featuresNo direct equivalent to confirmConfirm with GitHub before migrating. Check any feature your organization uses that is specific to GitHub Enterprise Server.

What data moves, what stays behind and what to rebuild

A GitHub to Gitea move has three parts: Git history, platform metadata and integrations. Git history moves with a clone or mirror, issues and pull requests move through Gitea's importer, and secrets and integrations stay behind and must be recreated. The cards below separate these so the team can plan each one.

Git history by clone or mirror

Commits, branches and tags move with a mirror clone, which copies every ref in the repository. This is the most reliable part of the move because it does not depend on any platform importer. Check that large files, Git LFS objects and tags are present on the target after the push, since a mirror does not guarantee that LFS content was fetched. Confirm the size of each repository against GitHub's documented limits before the cutover, so that nothing fails on the destination side.

Issues and pull requests via importer

Gitea's built-in migration form imports issues, pull requests and related metadata from GitHub when given a GitHub username and a token with read access to the source repositories. Test one representative repository first and compare issue counts, comments, labels and milestones against the source. Plan for GitHub's REST rate limits on large repositories, because the import reads through the same API that a bulk export would use.

Package registries as a destination

Packages published to GitHub Packages do not move with the repository. Gitea's built-in package registries can receive npm, Maven, container and other package types, but artifacts must be republished, and version identifiers, scopes and consumer configuration files need updating. Decide which packages are still needed, republish them, and update the registry URLs in build files and developer tooling before retiring GitHub as the source.

Secrets and variables must be re-entered

Actions secrets and variables do not export from GitHub. Every value used by a workflow, such as deployment keys, cloud credentials and registry tokens, must be created again in Gitea and tested with a non-production run. Record which secret each workflow expects, rotate credentials where the old value was shared widely, and remove any unused entries so the new instance does not inherit stale access.

Webhooks, deploy keys and SSH keys

Repository webhooks, deploy keys and user SSH keys are configured in GitHub and do not carry over automatically. Recreate each webhook with its target URL and secret, re-add deploy keys with the same read or write scope, and ask developers to register their SSH keys on the new server. Until these are rebuilt, notifications to external systems and automated deployments will silently stop, so verify each one after the cutover.

OAuth apps and external CI or chat hooks

OAuth apps registered in GitHub, along with external CI services and chat integrations, point at GitHub endpoints and must be registered again against the Gitea instance. Inventory every application authorized on the GitHub organization, decide which ones should continue, and update callback URLs. Chat notifications and external pipeline triggers often depend on personal tokens, so confirm the owner of each integration before revoking the old one.

The migration sequence from inventory to decommission

This sequence moves repositories and their metadata from GitHub to a self-hosted Gitea in controlled stages, so each step produces a record the next step depends on. GitHub stays the source of record until the cutover is verified, and it is archived only after the rollback window closes.

  1. Inventory repositories and metadata

    The platform owner and repository leads list every repository in scope, with its owner, default branch, size, open issues and pull requests, Actions workflows, webhooks, GitHub Pages sites, releases, packages and secrets. Repositories that approach large size limits or depend on external integrations are flagged for separate handling. The output is a repository register that assigns each item a migration method and a named owner. The step is done when every repository has a row and every row has an owner who has signed off on it.

  2. Build the Gitea target and access model

    The platform team installs Gitea in the client's own infrastructure, chooses a supported database, configures backups, and sets up organizations, teams and branch protection to mirror the GitHub structure. Identity integration and mandatory two-factor authentication are decided here, along with whether Gitea Enterprise support is needed. Confirm the current release and installation requirements in the Gitea documentation before building. The step is done when a test organization exists, backups have been restored once in a test environment, and the access model is written down.

  3. Run a pilot migration on representative repositories

    The team selects a few repositories that cover the hard cases: a large history, many pull requests with review comments, labels and milestones, a wiki, and Actions workflows. Each is moved with Gitea's built-in migration form using a GitHub token with the access it needs, and the results are compared against the source. Every difference is logged, including items the importer did not carry over. The output is a pilot report with import gaps, each assigned a fix, a manual workaround or an accepted loss. The step is done when the report has been reviewed by the repository owners.

  4. Fix the workflow and secrets plan

    The team converts Actions workflows from the .github/workflows directory into the layout Gitea Actions expects, which is .gitea/workflows, and tests each one against the Gitea runner. Confirm compatibility per workflow, because Gitea documents GitHub Actions compatibility as a goal rather than a guarantee. Secrets are recreated by their owners from their original sources, since GitHub does not export them. The output is a workflow inventory with test results and a secrets list with owners. The step is done when every production workflow has run successfully on a test branch.

  5. Run the parallel period with GitHub read-only

    Migrated repositories go live in Gitea while GitHub is set to read-only for those repositories and remains the source of record for the existing history. Teams work in Gitea, and a mirror or scheduled sync covers any repository that cannot stop receiving changes during the window. Developers, support staff and integrations are checked against the new URLs and access rules. The output is a daily sync log and a list of open discrepancies. The step is done when no discrepancy is open for a repository that will be cut over.

  6. Execute the cutover with a runbook

    The cutover runbook lists, in order, the freeze of GitHub writes, the final sync, the verification of commit hashes and branch heads, the DNS or internal URL changes, and updates to local remotes, CI variables, webhooks and deployment scripts. Each repository has a named person who confirms its checks, and a rollback path is written before the freeze starts. The output is a signed runbook with a timestamped record of each action. The step is done when the cutover checks pass and builds run from Gitea.

  7. Archive the GitHub export and decommission

    Once the rollback window agreed in the runbook has closed, the team takes a final export of the GitHub data, including Git mirrors and the metadata archive, and stores it in an access-controlled location with a retention period set by the client's policy. GitHub repositories are then archived or removed according to the decision recorded in the register, and access tokens and integrations used for the migration are revoked. The output is an archive of the GitHub export and a decommission record. The step is done when the archive has been restored in a test location and the revocations are confirmed.

How the importer and the token fit together

Gitea's built-in migration form pulls from GitHub through a downloader in its migration code, which is one of the importers the go-gitea/gitea repository lists alongside GitLab, Gitea, Gogs and others. The form reads the repository and, when you ask for issues and pull requests, the metadata that goes with them. Git history itself can move by clone or mirror, but the metadata needs this importer. Before the pilot, confirm in Gitea's migration documentation which items the GitHub downloader carries in your Gitea version, because coverage of reviews, attachments and wikis is the detail most likely to differ from what your teams expect.

A GitHub username is required before Gitea can migrate issues and pull requests, so the form cannot be treated as a simple URL copy. The token you supply is what authorizes the reads, and its scope decides which repositories and metadata the importer can see. Confirm the required token scopes in the current GitHub and Gitea documentation, and use a dedicated service account where your policy allows it so the migration does not depend on one engineer's personal access token. Record which account and token were used, and revoke the token when the move is finished.

GitHub allows 5,000 REST requests per hour for personal access tokens, so a large organization with many repositories, issues and comments can exhaust that budget in a single working session. Batch the repositories into groups, run the largest ones overnight or on a weekend, and leave room for retries when a run stops partway. Estimate request volume from your own issue and pull request counts during the pilot, not from a general figure, and check the GitHub rate limit documentation for your token type before scheduling the full move.

How the migration changes by size and starting point

A small team with a few dozen repositories and little or no GitHub Actions usage usually has the simplest path. Gitea's built-in migration form can import each repository with its issues, pull requests and other metadata when given a GitHub username and a token, so the work is mostly a repository-by-repository review rather than a rebuild. The main decisions are which repositories are still active and which history is worth carrying over.

  • Import scope: Migrate active repositories with their issues and pull requests, and archive the rest as read-only mirrors or Git bundles.
  • CI rework: With no workflows to port, the team only needs to confirm that nothing relies on hosted runners or on secrets stored in GitHub.
  • Access model: A few administrators and a short list of team accounts are usually enough, so re-create users and teams by hand and check each one.
  • Developer habits: Update remotes on every working copy and tell contributors where new issues and reviews now live.
  • Cutover: Freeze pushes to GitHub for a short window so the last commits and open pull requests are not left behind.

Before you start, confirm with your team which repositories have external contributors, since their accounts and open pull requests need a clear owner after the move.

What drives the cost and duration of the move

This table lists the factors that change how much a GitHub to Gitea move costs in time, infrastructure and staff effort, with a way to reduce each one. Read it as a checklist to size the work before asking for a quote, since most of the effort sits in repository count, workflow rebuilds and identity setup rather than in the import itself.

DriverWhy it changes cost or effortHow to keep it down
Number of repositoriesEach repository needs its own import, verification and access review, so staff time grows with the count even when the importer runs unattended.Group repositories into waves, retire inactive ones before the move, and archive rather than import history nobody uses.
Total repository sizeGitHub recommends keeping a repository's .git folder under 10 GB and enforces a 100 MB file limit, so large histories slow clones and mirrors and may need cleanup first.Find oversized files and binaries before migrating, move them to object storage or a package registry, and rewrite history only with reviewed sign-off.
Actions workflows and secretsGitea Actions reads .gitea/workflows and is designed to be compatible with GitHub Actions, but unsupported actions and runners need testing. Secrets never export, so each one must be re-entered.Inventory workflows and the actions they call, prioritize the few that run deployments, and keep a secrets register that owners verify.
Package registries in useRepositories that publish npm, Maven, container or other packages to GitHub Packages need a target registry, token rules and client configuration changes.List every registry consumer, decide which packages move, and plan client configuration changes in the same release window.
Identity integrationAccounts, SSO, team mapping and permissions must be rebuilt. Migrating items such as issues and pull requests needs a GitHub username and token, and personal access tokens face rate limits during bulk runs.Decide the identity source before import, map GitHub teams to Gitea organizations in advance, and schedule large imports to stay within GitHub's 5,000 REST requests per hour for personal access tokens.
Integrations to rebuildWebhooks, chat notifications, deployment tools, code scanners and build badges point at GitHub and must be repointed and tested one by one.Export a list of webhooks and GitHub App installations, retire unused ones, and test each replacement in a staging instance.
Hosting and operationsServers, storage, backups, monitoring and upgrades recur every year, and the size of the instance depends on repository size and CI load.Size storage from the measured repository footprint, separate CI runners from the forge, and set a regular upgrade window.
Support and staff timeA commercial support contract from CommitGo for Gitea Enterprise is optional and priced separately. Internal engineers, security reviewers and the team that trains users carry most one-time effort.Ask vendors for written scope, define who owns each wave, and confirm which support tier includes the features your organization needs.

What usually goes wrong and how to prevent it

Most failed GitHub to Gitea moves are not caused by Git itself. They come from what sits around the repositories: secrets, runners, imported discussions, remote addresses, size limits and access rights. Each card below names one risk, why it matters for this migration, and the check that prevents it.

Secrets missing after cutover

GitHub Actions secrets never leave GitHub, so every token, deploy key and registry password used by a workflow must be created again in Gitea. Teams often find the gap only when a deploy job fails at 2 a.m. Build an inventory from each workflow's secrets. references before cutover, recreate them at the repository or organization level, and run one non-production deploy per pipeline to confirm each secret resolves.

Workflows assuming GitHub-hosted runners

Gitea Actions is designed to be compatible with GitHub Actions wherever possible, but a workflow that assumes a GitHub-hosted image, preinstalled tools or GitHub-only marketplace actions may fail on a self-hosted runner. Check runner labels, container images and every uses: reference in .gitea/workflows or the migrated workflow files. Run each pipeline on a test branch and treat any unsupported action as a rewrite item, not a surprise.

Lost pull request context in imports

The Gitea GitHub downloader can carry issues and pull requests, but review threads, reviewer assignments, approvals and attachments may not map one-to-one, and the imported author of each item may not match a local account. Reviewers then lose the reasoning behind merged changes. Run a sample import of a busy repository, compare comments and labels against the original, and decide in advance which history is archived read-only on GitHub.

Webhook and remote URL drift

Local clones, build scripts, package manifests and webhooks still point at github.com after cutover, so commits land in the old place or CI never fires. Search repositories and automation for hardcoded GitHub hostnames, update each origin remote on developer machines, and recreate every webhook in Gitea. Keep the GitHub repository archived with a pointer README so stale remotes fail visibly instead of silently diverging.

Repositories over size limits

GitHub recommends keeping a repository's .git folder under 10 GB and enforces a 100 MB file limit, so large binaries committed years ago may have been moved to external storage. A self-hosted Gitea server has no such platform cap, but the disk, backup window and clone time still grow with history. Measure each repository's size before the move, check for large files, and confirm your storage and backup capacity with your own infrastructure team.

Permissions drifting from GitHub teams

GitHub organization teams, CODEOWNERS rules and branch protections do not transfer as-is into Gitea, so access can end up broader or narrower than before. Developers may push to protected branches, or auditors may find former contractors still have access. Map each GitHub team to a Gitea organization team, reapply branch protection rules to every default branch, and review membership against the source list before engineers receive access.

Running GitHub and Gitea in parallel and cutting over

Plan the cutover around one rule: GitHub stays readable and intact until the team signs off on Gitea. Start by running a final mirror or migration pass, then set the GitHub repositories to read-only so no new pushes, issues or pull requests land after the snapshot you verified. Announce the freeze date to every contributor and to any integration that writes to GitHub, such as bots, release tooling and webhooks. Keep the window defined in advance, with a named owner who decides when it opens and closes. Confirm in GitHub's repository settings how archiving or read-only status is applied in your plan, because a repository that is archived stops accepting issues and pull requests, which may not suit every team.

Verify the copy before anyone trusts it. Compare the commit hash of each default and release branch in GitHub with the matching hash in Gitea, and check that tags point to the same objects. Then reconcile the metadata that the migration form carries: issue and pull request counts, open items, labels, milestones, reviews and attachments. Attachments and some comment content can behave differently after import, so sample a few threads per repository and record what does not match. Next, point local remotes at Gitea with git remote set-url origin and update CI triggers, deploy keys and webhook targets. Test one pipeline run per critical repository on Gitea Actions before retiring the GitHub trigger, and confirm that secrets were re-created rather than assumed.

Keep a rollback path that does not depend on rebuilding anything. Until sign-off, leave GitHub repositories in their frozen state, keep the original remote configuration in a documented runbook, and retain the final verified mirror. If a critical defect appears in Gitea, the decision to reopen GitHub should be made by the same named owner, and the team should reverse the remote change and lift the freeze in a single pass. Set a sign-off checklist covering commit hash parity, open item review, CI and deploy success, and access for every team. Do not delete GitHub repositories or revoke tokens used by the migration until that checklist is complete and the backup of Gitea has been restored in a test environment at least once.

Questions teams ask before moving from GitHub to Gitea

How long does a migration from GitHub to Gitea take?

The duration depends on the number of repositories, the size of their issue and pull request history, how many Actions workflows and secrets need rework, and how many people must review the result. No supplied source gives a general timeline, so ask any implementation partner for a duration tied to a written scope. Repository history moves quickly with a clone or mirror, but the metadata step is bounded by GitHub's API rate limits: GitHub allows 5,000 REST requests per hour for personal access tokens, so large organizations should plan batches across several sessions. Confirm the batch plan and cutover window with your engineering leads before scheduling.

Can our own team migrate from GitHub to Gitea without outside help?

Yes, a small team with administrator rights can run Gitea's built-in migration form for individual repositories, because Gitea documents this path directly. The work becomes harder at scale: you must map users and organizations, decide which items to import, rebuild Actions workflows, re-create secrets, configure runners, set up backups and integrate single sign-on. Teams that lack staff time for those tasks often choose a fixed-scope engagement with DeployOpen, which plans, implements, backs up and documents the platform inside your own infrastructure. Whichever path you choose, agree on who owns each step in writing before the first repository moves.

What access and resources does the migration require from our side?

Plan for four inputs. First, an administrator on the Gitea instance who can run migrations and manage users. Second, a GitHub token with read access to each source repository, plus a GitHub username for importing issues and pull requests, as Gitea's migration documentation describes. Third, runner capacity for Gitea Actions, which you must provision and register. Fourth, an identity decision: local accounts or single sign-on, and how users map from GitHub logins to Gitea accounts. Ask your team to confirm token scopes and network paths to GitHub from the Gitea host before migration day.

Do GitHub Actions workflows run unchanged on Gitea?

Often they run with small changes, but do not assume they run unchanged. Gitea Actions is designed to be compatible with GitHub Actions wherever possible, and Gitea reads workflows from the .gitea/workflows directory. Expect differences in runner labels, available contexts, hosted runner images, and any actions that call GitHub-only APIs or services. Inventory every workflow, classify it as direct copy, adapted, or retired, and test each one on a registered runner. Gitea's comparison page lists the documented differences, so start there.

Are GitHub Actions secrets exported during the migration?

No. Secret values never leave GitHub, so every repository, organization and environment secret must be re-created in Gitea by someone with the original values. Make a list of secrets from GitHub, identify the owner of each credential, and rotate any that are shared broadly or cannot be confirmed. Store the new values in the Gitea secret store or in a dedicated secrets manager, and test each pipeline that depends on them. This step is often the one that delays cutover, so start it early.

How does Gitea Enterprise differ from community Gitea?

Gitea is MIT licensed, and CommitGo, Inc. provides leadership and commercial support and sells Gitea Enterprise. According to the Gitea Enterprise page, the enterprise edition adds SAML 2.0 service provider support, audit logging, organization-level branch protection inheritance, IP allowlisting, mandatory two-factor authentication and dependency scanning. Community Gitea covers Git hosting, code review, CI/CD and packages without those controls. Ask CommitGo for the current subscription terms, support levels and pricing, and confirm which features your compliance requirements need before you choose an edition.

What should a partner's migration scope include?

A written scope should name the repositories in and out of the move, the metadata to import (issues, pull requests, reviews, labels, milestones, wikis and releases), the user and identity mapping, the Actions workflow and secret inventory, runner design, backup and restore tests, a cutover and rollback plan, and documentation for administrators. It should also state who handles access controls and evidence collection for your assessment. DeployOpen works on fixed scope, with deliverables and timelines agreed in writing before work starts, and provides ongoing support and upgrades as retainers. Ask for a quote built from that scope, and do not accept a plan that leaves secrets or identity out.

How DeployOpen scopes and runs a GitHub to Gitea migration

DeployOpen plans, implements, integrates, hardens, backs up, documents and supports self-hosted open-source platforms inside your own infrastructure, including Gitea. For a GitHub to Gitea move, the work starts with a written scope that covers repositories, metadata, Actions workflows and secrets, and it ends with a documented handover that your team can operate.

How we scope

  • Inventory repositories, owners, branch protections, issues, pull requests and wikis to decide what the migration carries.
  • Confirm the Gitea hosting model, database choice and where the instance runs inside your cloud account or data center.
  • Agree in writing which Actions workflows move to .gitea/workflows and which secrets must be re-created by owners.

How we build

  • Install and harden the Gitea instance, configure authentication, backups and the built-in migration path for each repository.
  • Run test migrations on sample repositories, then compare issues, pull requests and labels against the GitHub source.
  • Plan bulk exports around GitHub API rate limits and document the sequence in which repositories move.

How we hand over

  • Deliver runbooks for administrators covering backups, upgrades, user onboarding and repository mirroring during cutover.
  • Provide a migration record listing each repository, its moved metadata and any items that needed manual re-creation.
  • Train platform and development leads on the new workflows, secret handling and where Gitea differs from GitHub.

How we support

  • Ongoing support, upgrades and continuous testing are available as a retainer after handover.
  • Confirm with your team which upgrade windows, release tracking and escalation paths the retainer should cover.
  • Quotes follow from the written scope, so ask for the scope items and timelines to be listed before work starts.

Talk to our team.

Tell us what you're working on, whether it's a deployment, an audit, a security test or a cyber range. You'll speak with an engineer who can help you scope it.

  • 30-minute call: free, with no obligation.
  • NDA on request: we can sign before you share details.
  • Clear next steps: a scope and plan after the call.