id: 2763188 title: "Copia de seguridad y sincronización automática de todos los repositorios de una cuenta u organización Git" published: true tags: [git, github, bash, automatizacion] series: Lo Arreglé y No Sé Cómo description: "Copia de seguridad y sincronización automática de todos los repositorios de una cuenta u..." canonical_url: "https://dev.to/ivajofranc/copia-de-seguridad-y-sincronizacion-automatica-de-todos-los-repositorios-de-una-cuenta-u-cj" cover_image: "https://media2.dev.to/dynamic/image/width=1000,height=420,fit=cover,gravity=auto,format=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgrorsebd4936cvl1dz7f.png"
Copia de seguridad y sincronización automática de todos los repositorios de una cuenta u organización Git
🇬🇧 Also read this post in English
En este tutorial te cuento cómo cloné y mantuve sincronizados todos los repositorios de una cuenta/organización GitHub, pero que también funciona para GitLab, Bitbucket o cualquier servidor Git que exponga una API y soporte git clone
y git pull
.
🎯 Objetivo
- Descargar todos los repositorios (públicos y privados) de una cuenta/organización.
- Guardarlos en una carpeta local (opcionalmente sincronizada con OneDrive, Dropbox, etc.).
- Actualizarlos con un solo comando (
git pull
en cada uno). - Registrar todo en un archivo de log para auditoría.
🛠️ Entorno usado
- SO: Windows 10/11
- Terminal: Git Bash (incluido con Git para Windows)
- Herramientas necesarias:
- git (instalado previamente)
- curl (incluido en Git Bash)
- jq (https://stedolan.github.io/jq/)
🔑 Pasos realizados y aprendizajes
1️⃣ Creación del token de acceso
- Crear un Personal Access Token (PAT) en GitHub con permisos:
-
repo
(para repos privados) -
read:org
(para organizaciones)
-
Problema: usar el endpoint de organización en una cuenta de usuario devolvía 404 Not Found
.
Solución: diferenciar entre usuario (/users/usuario/repos
) y organización (/orgs/org/repos
).
2️⃣ Script inicial de clonado
ORG_NAME="Organizacion-Ejemplo" OUTPUT_DIR="." REPOS_FILE="$OUTPUT_DIR/repos.txt" GITHUB_TOKEN="TOKEN_AQUI" mkdir -p "$OUTPUT_DIR" cd "$OUTPUT_DIR" || exit 1 curl -s -H "Authorization: token $GITHUB_TOKEN" "https://api.github.com/orgs/$ORG_NAME/repos?per_page=100&type=all" | jq -r '.[].clone_url' > "$REPOS_FILE" while read -r repo_url; do git clone "$repo_url" done < "$REPOS_FILE"
✅ Funciona para clonar todos los repos.
❌ Falla al repetir ejecución: fatal: destination path already exists
.
3️⃣ Mejora para sincronizar (git pull
)
repo_name=$(basename "$repo_url" .git) if [ -d "$repo_name/.git" ]; then git -C "$repo_name" pull else git clone "$repo_url" fi
✅ Actualiza si ya existe.
❌ Falla si nombre de carpeta ≠ nombre repo (mayúsculas/minúsculas).
4️⃣ Solución robusta
if [ -d "$repo_name/.git" ]; then (cd "$repo_name" && git pull) elif [ -d "$repo_name" ]; then echo "⚠️ Carpeta $repo_name existe pero no es repo Git" else git clone "$repo_url" fi
✅ Actualiza correctamente todos los repos existentes.
5️⃣ Registro en log
LOG_FILE="$(pwd)/sync-repos.log" echo "$(date) - Iniciando sincronización" | tee -a "$LOG_FILE" while read -r repo_url; do repo_name=$(basename "$repo_url" .git) if [ -d "$repo_name/.git" ]; then echo "📥 Actualizando $repo_name" | tee -a "$LOG_FILE" (cd "$repo_name" && git pull >> "$LOG_FILE" 2>&1) else echo "📦 Clonando $repo_name" | tee -a "$LOG_FILE" git clone "$repo_url" >> "$LOG_FILE" 2>&1 fi done < "$REPOS_FILE" echo "$(date) - Finalizado" | tee -a "$LOG_FILE"
📂 Ubicación de las copias
-
OUTPUT_DIR="."
→ se guarda en la carpeta actual. - Ubicación fija en Windows + Git Bash:
OUTPUT_DIR=/c/Users/usuario/OneDrive/Backups/github
🔄 Adaptar para GitLab o Bitbucket
- GitLab:
https://gitlab.com/api/v4/groups/<grupo>/projects
- Bitbucket:
https://api.bitbucket.org/2.0/repositories/<usuario>
- Ajustar autenticación (Bearer token, Basic Auth, etc.).
💡 Recomendaciones finales
- Probar primero en carpeta de pruebas.
- Evitar espacios en rutas o escaparlos con
\
. - Controlar errores de red con
set -e
o validaciones. - Programar ejecución con Task Scheduler (Windows) o cron (Linux).
- Respaldar logs para histórico.
Top comments (0)