Sincronizar repositorio de GitHub con GitLab
Objetivo: cada vez que se haga un
pusha la ramamainen GitHub, se debe replicar automáticamente el contenido (commits, ramas, tags) en un repositorio espejo de GitLab, usando GitHub Actions.
1. Generar el token de acceso en GitLab
El token es lo que le da permiso a GitHub Actions para hacer push hacia GitLab.
Opción A — Token de proyecto (recomendado)
- Entrar al repositorio destino en GitLab (ej.
gitlab.com/usuario/repo). - Ir a Settings → Access Tokens.
- Crear un token nuevo:
- Name:
github-sync(o cualquier nombre descriptivo) - Expiration date: definir una fecha (renovar cuando expire)
- Role:
Maintainer - Scopes: solo
write_repository
- Name:
- Copiar el token generado (solo se muestra una vez).
Opción B — Token personal
- Perfil → Edit profile → Access Tokens
- Mismo procedimiento, pero válido para todos los repos a los que se tenga acceso.
⚠️ No usar el scope
api. Da acceso total a la API de GitLab (crear/borrar proyectos, etc.), mucho más permiso del necesario. Conwrite_repositoryalcanza.
⚠️ Rol necesario: si la rama
mainen GitLab está protegida (lo normal por defecto), el token debe tener rol Maintainer. ConDeveloperno alcanza para pushear a ramas protegidas.
2. Guardar el token como secret en GitHub
- Ir al repositorio en GitHub.
- Settings → Secrets and variables → Actions.
- Pestaña Secrets → New repository secret.
- Completar:
- Name:
GITLAB_TOKEN - Secret: pegar el token copiado de GitLab
- Name:
- Add secret.
3. Crear el workflow de GitHub Actions
Crear el archivo .github/workflows/sync-gitlab.yml en el repositorio de GitHub, con el siguiente contenido:
name: Sincronizar con GitLab
on:
push:
branches:
- main
jobs:
sync:
runs-on: ubuntu-latest
steps:
- name: Clonar repositorio
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Enviar cambios a GitLab
run: |
# 1. Eliminamos el remoto si existía de un intento previo para evitar bloqueos
git remote remove gitlab || true
# 2. Añadimos el remoto usando el secreto GITLAB_TOKEN
git remote add gitlab https://oauth2:${{ secrets.GITLAB_TOKEN }}@gitlab.com/USUARIO/REPO.git
# 3. Enviamos los cambios de forma limpia
git push --prune gitlab +refs/remotes/origin/*:refs/heads/* +refs/tags/*:refs/tags/*Reemplazar
USUARIO/REPO.gitpor la ruta real del repositorio destino en GitLab (ej.daeshu/roms43.git).
Notas sobre el script:
git remote remove gitlab || true→ evita que falle si el remoto no existe aún (normal en la primera ejecución). El mensajeerror: No such remote: 'gitlab'que puede aparecer en los logs no es un error real, es solo la salida de este comando.fetch-depth: 0→ trae el historial completo, necesario para poder empujar todas las ramas y tags.- El
+antes de los refs indica force push, por eso GitLab debe permitirlo explícitamente (ver paso 4).
4. Requisitos del lado de GitLab
4.1 El repositorio debe existir
El push no crea el proyecto automáticamente en GitLab. Hay que crearlo manualmente antes (vacío o no) con el mismo nombre usado en la URL del workflow.
4.2 Permitir force push en la rama protegida
Por defecto, GitLab protege la rama main y rechaza force push, lo que genera este error:
remote: GitLab: You are not allowed to force push code to a protected branch on this project.
! [remote rejected] origin/main -> main (pre-receive hook declined)
Para solucionarlo:
- En GitLab: Settings → Repository → Protected branches.
- Buscar
main. - En Allowed to force push, habilitarlo (para el rol Maintainer como mínimo).
- Guardar.
4.3 Confirmar el rol del token
Verificar que el token usado en GITLAB_TOKEN tenga rol Maintainer (no Developer), ya que solo Maintainer puede modificar ramas protegidas incluso con el force push habilitado.
4.4 Si sigue fallando: desactivar la protección de la rama
En algunos casos, aunque se habilite “Allowed to force push”, GitLab igual rechaza el push mientras la rama siga marcada como protegida. Si el error persiste después de los pasos anteriores, la solución directa es desactivar por completo la protección de la rama:
- En GitLab: Settings → Repository → Protected branches.
- Buscar
mainen la lista de ramas protegidas. - Hacer clic en Unprotect (o eliminar la regla de protección para esa rama).
⚠️ Al desproteger la rama, cualquier persona con permiso de escritura podrá hacer push directo o force push a
mainsin restricciones, incluyendo sobreescribir el historial. Esto es aceptable en un repo espejo (que solo recibe copias automáticas), pero no se recomienda si en GitLab también se trabaja directamente sobre ese repositorio.
5. Probar la sincronización
- Hacer un cambio y
pushamainen GitHub. - Ir a la pestaña Actions del repositorio en GitHub.
- Verificar que el workflow “Sincronizar con GitLab” corra sin errores.
- Revisar el repositorio en GitLab para confirmar que los commits, ramas y tags se replicaron correctamente.
Checklist rápido
- Token generado en GitLab (rol
Maintainer, scopewrite_repository) - Secret
GITLAB_TOKENcreado en GitHub (Settings → Secrets and variables → Actions) - Archivo
.github/workflows/sync-gitlab.ymlcreado con la URL correcta del repo GitLab - Repositorio destino existe en GitLab
- “Allowed to force push” habilitado en la rama protegida
main - Si el push sigue fallando: rama
maindesprotegida (Unprotect) en GitLab - Primer
pushde prueba exitoso, verificado en la pestaña Actions