Moving from GitHub to Codeberg, for lazy people
Source: Hacker News
2025‑09‑06
I’ve just started to migrate some repositories from GitHub to Codeberg. I’ve wanted to do this for a long time but stalled because I perceived Codeberg as not being ready and the migration process as a lot of (boring) work. It turns out that is only partially true and wildly depends on your project. If you’re in a similar position as me, hopefully these notes serve as motivation and a starting point. These solutions are not what I might stick around with long‑term, but are aimed at what I think is easiest to get started with when migrating from GitHub.
Importing Issues, Pull Requests, and Releases
The easiest part is the migration of issues, pull requests and releases along with their artifacts. Codeberg offers a repository import from GitHub that just works, and all these features have a UI nearly identical to GitHub’s. The import preserves issue numbers, labels, and authorship. The user experience is a step above the extremely awkward hacks people use to import from other issue trackers into GitHub.
GitHub Pages Alternatives
If you’re using GitHub Pages you can use codeberg.page. There’s a warning that it does not offer any uptime SLO, but I haven’t noticed any downtime, and for now it’s fine. You push your HTML to a branch, very much like the old GitHub Pages.
Update 2025‑09‑22: Alternatively you may try grebedoc.dev or statichost.eu.
CI Considerations
The by‑far nastiest part is CI. GitHub has done an excellent job luring people in with free macOS runners and infinite capacity for public repos1. You will have to give up on both of those things. I recommend looking into cross‑compilation for your programming language, and to self‑host a runner for Forgejo Actions to solve those problems respectively.
Why Forgejo Actions (and not Woodpecker CI?)
Yes, Woodpecker on Codeberg is stable, but Forgejo Actions feels far more familiar coming from GitHub Actions. The UI and YAML syntax are almost identical, and the existing actions ecosystem mostly works as‑is on Codeberg. For example, where my GitHub Actions workflow would say
uses: dtolnay/rust-toolchainmy Forgejo Actions workflow would just change to
uses: https://github.com/dtolnay/rust-toolchainIf you absolutely need macOS runners, you can keep using GitHub Actions on the GitHub repository, mirror all commits from Codeberg to GitHub, and use Forgejo Actions to poll the GitHub API and sync the CI status back to Codeberg. I haven’t tried this yet, but I have tried other CI providers offering macOS builds and they aren’t easier or cleaner to integrate into Codeberg than GitHub Actions.
Handling the Old Repository on GitHub
Finally, what to do with the old repo on GitHub? I’ve just updated the README and archived the repo.
You could tell Codeberg to push new commits to GitHub, which allows users to still file PRs and comment on issues and commits2. Some folks have dealt with this by disabling issues on the GitHub repo, but that is a destructive action as it will 404 all issues, and pull requests cannot be disabled. Some repos (e.g., libvirt/libvirt) have written a GitHub Action that automatically closes all pull requests.
This approach has some terrible consequences for self‑hosting and the broader software ecosystem, as folks have no incentive to optimize their builds or how often they download a release tarball from your website.1
You might still want to maintain a read‑only mirror during a transitionary period, or to keep using GitHub Pages and GitHub Actions.2