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
- Create a Github Token with “all” permissions (see here)
- Create a Codeberg with “all” permissions (see here)
- 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
historyshell 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:
- Check if a user exists
- 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.