Moving away from GitHub is one of those things developers talk about more than they do. The ideology is easy: Microsoft owns it, Copilot was trained on your code, all of open source’s critical infrastructure runs through a single corporation’s servers. The inertia is harder. You have a dozen local clones pointing at github.com. Your CI references GitHub URLs. Your README has badge links. Your colleagues clone from GitHub. The cost of updating all of that is just enough friction to shelve the idea indefinitely.
Markus Unterwaditzer wrote a practical walkthrough of how he migrated to Codeberg “for lazy people”, meaning without touching every local clone or breaking every script that references a GitHub URL. The core technique is a git feature most developers have never used: url.insteadOf.
What url.insteadOf Actually Does
Git’s URL rewriting config lets you define prefix substitutions that apply transparently to every git operation. If you add this to your ~/.gitconfig:
[url "git@codeberg.org:yourname/"]
insteadOf = git@github.com:yourname/
Then every git push, git fetch, or git clone that would have gone to github.com/yourname/ silently goes to codeberg.org/yourname/ instead. Your existing local clones still have their remotes pointing at GitHub URLs. They keep working. The redirect happens at the git layer, not at the remote configuration level.
For HTTPS URLs, the same pattern applies:
[url "https://codeberg.org/yourname/"]
insteadOf = https://github.com/yourname/
You can be as broad or narrow as you want. A prefix match on your own username means only your repositories get redirected. Collaborator repos on GitHub still resolve normally. This is the “lazy” part: you do not need a migration day. You flip a config switch and your workflow changes incrementally.
The pushInsteadOf variant is also worth knowing. It rewrites only push URLs, leaving fetch URLs unchanged. This lets you fetch from GitHub (say, to pull in changes from collaborators who still push there) while pushing to Codeberg:
[url "git@codeberg.org:yourname/"]
pushInsteadOf = git@github.com:yourname/
That is a meaningful distinction during a transition period when you want Codeberg to be authoritative but GitHub to remain readable.
What Codeberg Is
Codeberg is a free, nonprofit git hosting platform operated by Codeberg e.V., a German registered association based in Berlin. It runs Forgejo, and it is subject to GDPR. It does not run ads. It does not sell data. The governance is membership-based, meaning users can join the association and participate in decisions about the platform.
The feature set is what you’d expect from a capable GitHub alternative: repositories, issues, pull requests, wikis, releases, a package registry, and integrated CI through Woodpecker CI. The interface is familiar if you have used any Gitea-based platform. Search, labels, milestones, code review with inline comments, protected branches, webhooks, all present.
For open source projects specifically, hosting is free. Codeberg has been growing steadily since 2022, driven largely by developers who became uncomfortable with Microsoft’s direction for GitHub, especially the Copilot training controversy.
The Forgejo Fork and Why It Matters
Codeberg runs Forgejo rather than Gitea directly, and that distinction is worth understanding.
Gitea started in 2016 as a community fork of Gogs. For years it was genuinely community-run, hosted on GitHub (ironically), developed by volunteers. In late 2022, a subset of the Gitea maintainers incorporated a company called Gitea Ltd and transferred the trademark and key project assets to that company, including the domain and the GitHub organization. This happened without a community vote or broad consultation. The announcement was met with significant backlash from contributors who felt the project’s direction had been changed unilaterally.
A group of those contributors forked Gitea and created Forgejo in December 2022, placing it under the governance of the Software Freedom Conservancy. Forgejo started as a near-identical soft fork, tracking Gitea’s releases closely. Over time it has diverged, most significantly in one area: federated git hosting.
Forgejo is actively developing support for ActivityPub-based federation through the ForgeFed protocol. The goal is a future where a Forgejo instance on codeberg.org can receive pull requests from a Forgejo instance on someone’s self-hosted server, and issue comments can cross instance boundaries, without anyone needing a centralized account. This is structurally different from GitHub or GitLab’s model, where federation means “import from another platform once” rather than ongoing cross-instance collaboration.
Federation is not fully deployed yet. But the architectural work is underway, and Codeberg as the largest Forgejo instance is a natural staging ground for it. Moving to Codeberg is not just leaving GitHub for a different silo; it positions you on infrastructure that has a plausible path toward decentralized git hosting.
Keeping GitHub Alive During Transition
For projects where people or systems depend on GitHub URLs, a push mirror handles the transition gracefully. Codeberg (via Forgejo) supports push mirrors natively in repository settings. After every push to Codeberg, Forgejo automatically pushes to the configured mirror URL. GitHub becomes a read-only replica.
This means:
- CI jobs that clone from GitHub keep working
- Other developers who have GitHub clones keep working
- GitHub stars and watch counts remain visible
- You maintain discoverability on GitHub’s search
Setting up the push mirror requires a GitHub personal access token with repo scope. In the Codeberg repository settings under “Mirror Settings”, you add GitHub as a push target. Forgejo handles the rest.
The Forgejo Migrations API also lets you import a GitHub repository including its issues, pull requests, labels, and milestones:
curl -X POST https://codeberg.org/api/v1/repos/migrate \
-H "Authorization: token YOUR_CODEBERG_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"clone_addr": "https://github.com/yourname/yourrepo",
"repo_name": "yourrepo",
"issues": true,
"pull_requests": true,
"labels": true,
"milestones": true,
"auth_token": "YOUR_GITHUB_TOKEN"
}'
For projects with substantial issue history, this is worth doing early. GitHub’s API returns issue data in a format Forgejo can ingest, preserving timestamps, authors (mapped where possible), and comment threads.
Woodpecker CI
Codeberg’s integrated CI is Woodpecker, which runs pipeline definitions from a .woodpecker.yml file in your repository. The syntax is YAML-based and reasonably close to what you get with GitHub Actions, though the model is simpler: steps run in containers you specify, there is no marketplace of pre-built actions, and you define most things explicitly.
steps:
- name: test
image: golang:1.22
commands:
- go test ./...
- name: build
image: golang:1.22
commands:
- go build -o bin/app ./cmd/app
For small projects, the translation from GitHub Actions is usually straightforward. The main adjustment is replacing actions/checkout and similar composite actions with direct shell commands. Woodpecker’s plugin ecosystem covers common cases: Docker builds, SSH deployments, notification integrations.
Codeberg provides shared runners for public repositories. For private repositories or resource-intensive builds, you can connect your own runner agent, which is a small Go binary that polls Woodpecker for jobs.
The Broader Context
Codeberg is not the only GitHub alternative seeing growth. Sourcehut has a dedicated following among developers who want minimal infrastructure and strong Unix philosophy adherence. GitLab dominates the self-hosted enterprise market. Gitea still exists as a managed service through the Gitea Ltd company.
What distinguishes Codeberg is the combination of nonprofit governance, zero-cost open source hosting, GDPR compliance, and the Forgejo federation work. The platform does not need to monetize your data or upsell you on enterprise features to survive. The model is straightforward: donations and memberships fund the infrastructure.
For developers who want to reduce dependency on GitHub without running their own infrastructure, Codeberg is the most complete answer available. The url.insteadOf trick makes starting that migration take about five minutes. The push mirror keeps the transition invisible to everyone else. The rest is just doing it.