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)