Mirroring GitHub to Codeberg Without a Third-Party Action
You do not need an external action for this mirror setup.
A standard workflow using git push over SSH is enough.
Goal
- Mirror from GitHub to Codeberg
- No third-party dependency
- Only branches and tags (clean repo, no
origin/*refs)
1. Generate an SSH key
Create a dedicated key pair locally:
ssh-keygen -t ed25519 -C "github-actions-codeberg-mirror" -f ~/.ssh/codeberg_mirror -N ""
2. Store keys in the correct places
Important: do not mix up public and private keys.
- Codeberg Deploy Key (
Repository -> Settings -> Deploy keys): paste the content of~/.ssh/codeberg_mirror.pub - Enable Allow write access
- GitHub Secret (
Settings -> Secrets and variables -> Actions): createCODEBERG_SSHwith the content of~/.ssh/codeberg_mirror(private key)
If a key form shows
Key is invalid. You must supply a key in OpenSSH public key format,
you pasted a private key where a public key is expected.
3. Add the workflow
File: .github/workflows/sync-mirror.yml
name: 🪞 Mirror to Codeberg
on:
push:
branches: [main]
workflow_dispatch:
schedule:
- cron: "30 0 * * 0"
jobs:
codeberg:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Configure SSH
run: |
mkdir -p ~/.ssh
printf '%s\n' "${{ secrets.CODEBERG_SSH }}" > ~/.ssh/id_ed25519
chmod 600 ~/.ssh/id_ed25519
ssh-keyscan -H codeberg.org >> ~/.ssh/known_hosts
cat <<'EOF' > ~/.ssh/config
Host codeberg.org
HostName codeberg.org
User git
IdentityFile ~/.ssh/id_ed25519
IdentitiesOnly yes
EOF
- name: Verify SSH access
run: |
ssh -T git@codeberg.org || true
git ls-remote git@codeberg.org:adrian-altner/website.git > /dev/null
- name: Mirror to Codeberg
run: |
git remote add mirror git@codeberg.org:adrian-altner/website.git
# Remove previously mirrored remote-tracking refs (for example refs/remotes/origin/*).
while IFS= read -r ref; do
git push mirror ":${ref}"
done < <(git ls-remote --refs mirror 'refs/remotes/*' | awk '{print $2}')
# Mirror only real branches and tags.
git push --prune mirror \
+refs/heads/*:refs/heads/* \
+refs/tags/*:refs/tags/*
4. Expected behavior during testing
With successful SSH auth, this Forgejo message is expected:
... successfully authenticated ... but Forgejo does not provide shell access.
This is not an error. Git operations (fetch, push) still work.
Result
The setup mirrors reliably to Codeberg, runs automatically on pushes to main, can be started manually via workflow_dispatch, and also runs weekly via cron.