7.9 KiB
Make Gitea the primary repository
The primary repository is https://overlord.kyun.li/vxaboveground/overlord. These instructions preserve all Git branches, tags, and commits reachable from them, make Gitea the default remote for development, and configure Gitea to push-mirror to GitLab.
This runbook targets Gitea 1.27.2. It intentionally does not use
git push --mirror from a working clone. A working clone contains local and
remote-tracking refs that are not part of the public branch/tag contract, and a
mirror push can also delete destination refs.
Canonical remotes
The prepared working clone has these exact remotes:
| Name | Role | Fetch and push URL |
|---|---|---|
origin |
Primary Gitea repository and default push target | ssh://git@overlord.kyun.li:222/vxaboveground/overlord.git |
gitlab |
Former primary; retained for comparison while the Gitea push mirror is verified | ssh://git@altssh.gitlab.com:443/vxaboveground/overlord.git |
forgejo |
Legacy internal Forgejo remote | ssh://git@10.0.22.220:22/KDOT/Overlord-Public.git |
main tracks origin/main, and remote.pushDefault is origin. Confirm the
local setup before the cutover:
git remote -v
git config --get branch.main.remote
git config --get branch.main.merge
git config --get remote.pushDefault
The expected last three values are origin, refs/heads/main, and origin.
Do not push directly to gitlab after the server-side push mirror is enabled;
Gitea must be the sole write authority.
Copy Git history safely
-
Announce a short write freeze on GitLab. Merge or close outstanding work and wait for running pushes to finish. Commit the migration-preparation files in this checkout and push that commit to
gitlab/mainbefore taking the final bare clone, so the new Gitea workflows and canonical links are included in the copied history. -
Back up the GitLab project. Create the Gitea repository at the primary URL as an empty repository: do not initialize a README, license, or
.gitignorein Gitea. -
From a temporary directory outside this working clone, make a bare clone of GitLab and inspect it:
migration_dir="$(mktemp -d)" git clone --bare \ ssh://git@altssh.gitlab.com:443/vxaboveground/overlord.git \ "$migration_dir/overlord.git" git -C "$migration_dir/overlord.git" fsck --full git -C "$migration_dir/overlord.git" for-each-ref \ --format='%(objectname) %(refname)' refs/heads refs/tags -
Add Gitea only to that bare migration clone, then push explicit branch and tag namespaces. These refspecs do not include remote-tracking, CI, merge request, or other implementation-specific refs, and they do not request deletion of destination refs:
git -C "$migration_dir/overlord.git" remote add gitea \ ssh://git@overlord.kyun.li:222/vxaboveground/overlord.git git -C "$migration_dir/overlord.git" push --atomic gitea \ 'refs/heads/*:refs/heads/*' \ 'refs/tags/*:refs/tags/*'A non-fast-forward rejection means Gitea already contains divergent work. Stop and reconcile that work; do not add
--forcejust to make the command pass. -
Compare the source and destination refs exactly:
git ls-remote --heads \ ssh://git@altssh.gitlab.com:443/vxaboveground/overlord.git \ | sort > "$migration_dir/gitlab-heads" git ls-remote --heads \ ssh://git@overlord.kyun.li:222/vxaboveground/overlord.git \ | sort > "$migration_dir/gitea-heads" git ls-remote --tags \ ssh://git@altssh.gitlab.com:443/vxaboveground/overlord.git \ | sort > "$migration_dir/gitlab-tags" git ls-remote --tags \ ssh://git@overlord.kyun.li:222/vxaboveground/overlord.git \ | sort > "$migration_dir/gitea-tags" diff -u "$migration_dir/gitlab-heads" "$migration_dir/gitea-heads" diff -u "$migration_dir/gitlab-tags" "$migration_dir/gitea-tags"Both
diffcommands should produce no output. In Gitea, setmainas the default branch and recreate branch/tag protection, collaborators, deploy keys, webhooks, Actions secrets, and other host-level settings.
The explicit Git copy does not migrate GitLab issues, merge requests, comments, release records, CI variables, job artifacts, package/container registries, or other GitLab database content. Export/import those separately if they must be retained. If Git LFS is enabled later, its objects also require an explicit LFS fetch/push; ordinary ref pushes do not transfer LFS object content.
Make Gitea the default in other clones
For an existing clone that still calls GitLab origin, preserve that remote
under the gitlab name and add Gitea as the new origin:
git remote rename origin gitlab
git remote add origin \
ssh://git@overlord.kyun.li:222/vxaboveground/overlord.git
git fetch origin --prune --tags
git branch --set-upstream-to=origin/main main
git config remote.pushDefault origin
If that clone already has a remote called gitlab, update URLs instead of
renaming over it:
git remote set-url origin \
ssh://git@overlord.kyun.li:222/vxaboveground/overlord.git
git remote set-url gitlab \
ssh://git@altssh.gitlab.com:443/vxaboveground/overlord.git
git fetch origin --prune --tags
git branch --set-upstream-to=origin/main main
git config remote.pushDefault origin
Test the cutover with a normal branch push to origin. Avoid configuring a
client-side push URL that writes to both hosts: the Gitea server-side mirror is
the single replication mechanism and exposes failures in its UI.
Configure the Gitea-to-GitLab push mirror
Gitea's push mirror force-updates the destination. Once enabled, changes made directly on GitLab may be overwritten or deleted on the next sync. Keep the GitLab project read-only for normal development and treat it as a replica.
-
In GitLab, create a project access token or personal access token with the
write_repositoryscope. Use an account permitted to update the repository's protected branches and tags. -
In Gitea, open Settings > Repository > Mirror Settings for
vxaboveground/overlordand choose Add Push Mirror. -
Enter these values:
- Remote repository URL:
https://gitlab.com/vxaboveground/overlord.git - Authorization username:
oauth2 - Authorization password: the GitLab token
- Remote repository URL:
-
Enable Sync when new commits are pushed, add the mirror, and select Synchronize Now for the initial replication.
-
Confirm that Gitea reports a successful sync, then compare heads and tags again with the verification commands above. Make a small test branch in Gitea, confirm it arrives in GitLab, and delete it from Gitea so the deletion behavior is also understood before ending the write freeze.
If a sync fails, inspect the error in Gitea's Mirror Settings. The usual causes
are an expired token, missing write_repository permission, or GitLab protected
branch/tag rules that reject the mirror account. Rotate the GitLab credential in
Gitea rather than embedding it in a Git remote URL or this repository.
GitLab CI may run when mirrored commits arrive because this repository retains
.gitlab-ci.yml. Keep that behavior if GitLab remains a CI replica; otherwise
disable GitLab pipelines in the GitLab project settings after confirming Gitea
Actions covers the required jobs.
Final checks
originfetches and pushes to Gitea over SSH port 222.maintracksorigin/main, andremote.pushDefaultisorigin.- All GitLab heads and tags match Gitea at the end of the write freeze.
- The Gitea push mirror reports a successful GitLab sync.
- Branch/tag protections, access controls, secrets, and webhooks exist in Gitea.
- The repository-scoped runner is online and a Gitea Actions workflow passes.
- Developers know Gitea is authoritative and GitLab is read-only.
After an agreed observation period, remove the legacy forgejo remote from
developer clones if it is no longer needed. Keep backups according to the
project's retention policy.