How to move from GitHub to Codeberg


Migrate from Github to Codeberg

Are you tired of GitHub social tab? What about issues tab being “removed” in favor of AI?

There’s AI everywhere nowadays, but Github was one of the places that were left untouched.

Not anymore.

[!INFO] FYI Some code has been written and tested with the help of an AI

Why

  • Codeberg is not controlled by a commercial entity, but by its non-profit association based in Berlin, Germany
    • this means that every change is led by the community
    • no forced AI
    • no stupid UI/UX changes “because they say so”
  • Codeberg servers are based in Berlin, in EU, unlike Github servers
  • Codeberg run Forgejo that is open source
  • You don’t want to use a popular platform, whatever the reason

How

The general idea is: use Codeberg as main and GIthub as a mirror. Or viceversa.

Migrating from GitHub to Codeberg is not a straightforward process.

The estimated time for the entire procedure is about 45min.

Preliminary steps

  1. Create a Github Token with “all” permissions (see here)
  2. Create a Codeberg with “all” permissions (see here)
  3. Save them somewhere in your computer. You’ll need both of them.

Let’s export these variables for the current shell:

export CODEBERG_USERNAME="codeberg-username"
export CODEBERG_TOKEN="codeberg-token"
export GITHUB_TOKEN="gh-token"
export GITHUB_USERNAME="github-username"

We’ll need them later. Make sure by giving echo $CODEBERG_TOKEN it prints <codeberg-token>.

[!NOTE] Security Issues It’s not a safe idea issuing these commands, due to the history shell command. If you are an advanced user, and feel that ’this is bad’, find a proper safer way. One idea is to save it in .bashrc and reload the bash, and remove everything when it’s over.

Github: spring cleaning regardless of the season

In your public repos: is there any fork that you don’t use? If yes, delete it.

In your private ones: is there any project that you started years ago and never touched anymore because you were too scary or full of work? It is a good time to delete them.

Is your public repo a private one? Make sure to “publish” it and viceversa.

Unless you’re ready to deal with Forgejo and so on, the repos that has workflows or something more complicated, should remains on Github.

(optional) Download all your Github repos in local

You never know.

Save this script in your home and launch it with ./github_to_local.sh:

#!/usr/bin/env bash

set -euo pipefail

DEST="$HOME/github-backup"
mkdir -p "$DEST"

cd "$DEST"

page=1

while :; do
    repos=$(curl -s \
        -H "Authorization: Bearer $GITHUB_TOKEN" \
        -H "Accept: application/vnd.github+json" \
        "https://api.github.com/user/repos?per_page=100&page=$page&type=owner" \
        | grep -o '"clone_url": *"[^"]*"' \
        | cut -d '"' -f4)

    if [ -z "$repos" ]; then
        break
    fi

    for repo in $repos; do
        repo_name=$(basename "$repo" .git)

        if [ -d "$repo_name" ]; then
            echo "Skipping existing repo: $repo_name"
            continue
        fi

        echo "Cloning $repo"

        git clone "https://$GITHUB_TOKEN@${repo#https://}"
    done

    page=$((page + 1))
done

Move from Github to Codeberg

This excellent script from LionyxML is pretty customizable and allow us to move from one place to another the repos.

Make sure to either export the variables as explained at the beginning of the guide, or fill the variables at the beginning with your data.

wget https://raw.githubusercontent.com/LionyxML/migrate-github-to-codeberg/refs/heads/main/migrate_github_to_codeberg.sh

Everything is written in the file, but here’s a small portion, that’s how I set up:

# !!!!! 
# Since you have exported your usernames and tokens before, there is no need to redeclare them here. If needed, uncomment them.
# !!!!!

# GitHub username and personal access token
# GITHUB_USERNAME="YourGitHubUsername"
# GITHUB_TOKEN="YourGitHubToken"

# Codeberg username and personal access token
# CODEBERG_USERNAME="YourCodebergUsername"
# CODEBERG_TOKEN="YourCodebergToken"

# REPOSITORIES array with repository names you want to migrate, one per row with commas
# blank = ALL repositories
REPOSITORIES=()

# OWNERS array with specific usernames whose repositories you want to migrate, one per row
# blank = ALL repositories
OWNERS=(
	"$GITHUB_USERNAME"
)

Since we want to migrate everything… let’s leave everything as it is, but I’m not interested in the code I’ve created in the organizations.

Therefore, I’ll write my name in “owners” array.

Save the script in your home directory, fill with your information, make it executable and launch it.

Wait a while and… boom, your Codeberg account is now populated.

[!Danger] Warning Make sure to change visibility to “private” those repos that you will manage through Github, or even better, delete them. This will help Codeberg in being a free, cleaner space for everybody. Furthermore, you’ll avoid code duplication.

Make also sure to adhere to their principles.

Following and followers

We need to perform two actions:

  1. Check if a user exists
  2. Fetch the list of following and followers Github users in our profile, and try to see if there’s a match on Codeberg

Check if a user exists

In a file named check_codeberg.sh let’s write:

#!/usr/bin/env bash  
  
for user in "$@"; do  
   status=$(curl -s -o /dev/null -w "%{http_code}" \  
       "https://codeberg.org/api/v1/users/$user")  
  
   if [ "$status" = "200" ]; then  
       echo "$user exists"  
   else  
       echo "$user does not exist"  
   fi  
done

Make it executable:

chmod +x check_codeberg.sh

And run it with an username:

./check_codeberg.sh torvalds
torvalds exists

Fetch the list of following and followers Github users

Let’s move to the second action.

Let’s retrieve following people of our own profile with these piece of code:

page=1; while body=$(curl -s -H "Authorization: Bearer $GITHUB_TOKEN" "https://api.github.com/users/$GITHUB_USERNAME/following?per_page=100&page=$page"); do  
[[ $(jq 'length' <<< "$body") -eq 0 ]] && break  
jq -r '.[].login' <<< "$body" >> following.txt  
((page++))
done  

And followers:

page=1; while body=$(curl -s -H "Authorization: Bearer $GITHUB_TOKEN" "https://api.github.com/users/$GITHUB_USERNAME/followers?per_page=100&page=$page"); do  
[[ $(jq 'length' <<< "$body") -eq 0 ]] && break  
jq -r '.[].login' <<< "$body" >> followers.txt  
((page++))  
done  

We cannot merge both instructions because we may have more followers than following and viceversa.

All together now

It’s now time to see who’s on codeberg.

Let’s merge following and followers list into one file:

cat following.txt followers.txt | sort | uniq >> people.txt

And now, let’s find out who’s online:

while read -r user; do  
   curl -s -o /dev/null -w "%{http_code}" \  
   "https://codeberg.org/api/v1/users/$user" | grep -q 200 && echo "$user found! -> https://codeberg.org/$user"  
done < people.txt

[!NOTE] Enhancements This could be further enhanced by calling Codeberg API Keys and blindly following every account. Since sometimes people’s username may be different than the github ones (like me), always check profiles before blindly following everyone

That’s all folks!

Have I been useful? Support my work [on ko-fi](ko-fi.com/dag7, even a small euro could make the difference.

Thanks for reading this.


See also