Migration From Github to Codeberg

Table of Contents


On January 8, 2021, I have joined GitHub, back then I knew very little about FOSS and how it works, haven’t done design ever and had awful knowledge of English, to point that I used Google Translate to understand the text.

Things have changed since then, but this post is not about this (or is it).

GitHub is the biggest Git service that every developer knows about, a lot of open source projects use it because it provides free Git hosting and very convenient tools such as Actions and Pages, but not everything is perfect, and where there’s Microsoft there’s bad stuff.

It is owned by Microsoft for a long time, which is the first red sign. When Russo-Ukrainian War began, GitHub started suspending accounts and deleting repositories of Russian developers who has nothing to do with war but the fact that they were in Russia (info varies). Last year they launched Copilot - an AI code completion and suggestion software trained on FOSS projects, violating the GPL license. Microsoft itself has not the cleanest history with FOSS and Linux, but listing every incident here would take a lot of time.

Recently I were contributing to some projects hosted on Codeberg, and I had to create an account and use it for some time, and… I liked it! The UI of Codeberg; the workflow and the overall vibe were really nice, the fact that Codeberg is very open with its Community helped a lot too.

Edit: apparently I have contributed to one project earlier, so I already had a Codeberg account xD

Codeberg is non-profit powered by Forgejo - a soft-fork of Gitea.

(…) We started Forgejo in reaction to control of Gitea being taken away from the community by the newly-formed for-profit company Gitea Ltd without prior community consultation, and after an Open Letter to the Gitea project owners remained unanswered.

And I started thinking of and preparing for migration.

Why not GitLab?

Good question, I honestly don’t know. As a matter of fact, GitLab is a bit confusing for me (especially after recent sidebar redesign) and I just liked Codeberg so much, it’s small and cute :)


I have found about that Dan Erat have published an article about his migration from GitHub to Codeberg before this one, check it out.

After final decision that I will migrate my personal repositories to Codeberg I have created a poll on Mastodon,in which asked what to do with repositories on GitHub, people decided that adding small note in README that tells about migration and gives a link to repository on Codeberg, and then archiving were the best approach, and so I did it!


The migration of repositories were very simple - I have created GitHub Fine-grained personal access token which I used to give Codeberg access to GitHub repositories

You can fine-tune the migration - enable migration of pull requests, issues, labels, releases, milestones and wiki, all by simply checking a box.


To make the migration as smooth as possible for everyone, I have added redirect from GitHub pages to Codeberg pages right before archiving, so all the links will continue work just like before.

To do so, I have added this two lines to <head> of HTML

<meta http-equiv="refresh" content="0; URL=https://daudix.codeberg.page">
<link rel="canonical" href="https://daudix.codeberg.page">

GitHub Pages → Codeberg Pages

Speaking of Codeberg pages, I have successfully recreated the workflow of GitHub pages with said Codeberg pages and Woodpecker - CI service that Codeberg provides (you need to request access), which allows running various jobs on changes. Тhe one I needed were Jekyll - Static site generator from Markdown (and not only) that are used by GitHub pages and this blog is powered by.


See blog post by Jan Wildeboer for better understanding how the CI works, since this guy created the workflow used here.

First, I have requested and waited for manual approval to access to Woodpecker CI by opening an issue here and selecting Woodpecker CI Access, it took a few hours, so when I woke up I already had access.

After approval, I have created blog-source and blog repositories (names can be whatever you want), the later will contain the generated static site, and should only have pages branch in it, and created .woodpecker.yml file in the blog-source repository.

Then copy and paste the contents of Jekyll workflow example in .woodpecker.yml

    # Use the official jekyll build container
    image: jekyll/jekyll
    secrets: [ cbtoken, cbmail ]
      # Avoid permission denied errors
      - chmod -R a+w .
      # Set up git in a working way
      - git config --global --add safe.directory /woodpecker/src/codeberg.org/CBUSER/CBIN/_site
      - git config --global user.email "$CBMAIL"
      - git config --global user.name "CI Builder"
      - git config --global init.defaultBranch pages
      # clone and move the target repo
      - git clone -b pages https://codeberg.org/CBUSER/CBOUT.git
      - mv CBOUT _site
      - chmod -R a+w _site
      - cd _site
      # Prepare for push
      - git remote set-url origin https://$CBTOKEN@codeberg.org/CBUSER/CBOUT.git
      - cd ..
      # Run Jekyll build stage
      - bundle install
      - bundle exec jekyll build
      # Only needed for custom domains
      - cp domains _site/.domains
      # Push to target
      - cd _site
      - git add --all
      - git commit -m "Woodpecker CI Jekyll Build at $( env TZ=Europe/Berlin date +"%Y-%m-%d %X %Z" )"
      - git push

After that, open it in your favorite text editor and replace:

Personally I use VSCodium, fork of VSCode with Microsoft telemetry removed.

Push all the changes and Generate an Access Token, you need to generate token named cbtoken with the repo scope selected

scopes repo

Then copy the resulted token and save it to a safe place, as it won’t be shown again.

Go to Woodpecker and navigate to Repositories tab and add a new repository (blog-source)

add repository button

Navigate to Settings and go to Secrets tab

settings button

secrets tab

Here create two secrets, cbmail and cbtoken

cbmail should contain your Codeberg account email

cbmail secret

And cbtoken should contain the secret we saved earlier

cbtoken secret

Make sure these two secrets have successfully created and make some changes in blog-source to trigger the CI, it should finish successfully.

If you don’t want to trigger the CI (the change doesn’t affect content for example) you can add [CI SKIP] to your commit message to skip the CI

ci successful

Now it’s up to you to choose Jekyll theme and write something ;)

In my case I already had blog based on jimmac/os-component-website (this blog) so it were all I needed to do.


The migration from GitHub to Codeberg were simple and smooth, but not without issues, I had difficulties understanding how to make Woodpecker secrets work and how to create them in first place, this is why I wrote this post in first place.

Edit: in Gitea and consequently in Forgejo v1.20 the secret creation UI have been completely changed, and it’s more clear than current one

Guys over Codeberg seem to be very nice so if you value your code then you may want to do the same :)

This is all for now, take cake care!

QR code to a Mastodon post


You can comment on this blog post by publicly replying to this post using a Mastodon or other ActivityPub/Fediverse account. Known non-private replies are displayed below.

Go to TopFile an Issue