id: 2763189
title: "Automatic Backup and Synchronization of All Repositories from a Git Account or Organization"
published: true
tags: ["git", "github", "bash", "automation"]
series: I Fixed It and I Don't Know How
description: "Automatic Backup and Synchronization of All Repositories from a Git Account or..."
canonical_url: "https://dev.to/ivajofranc/automatic-backup-and-synchronization-of-all-repositories-from-a-git-account-or-organization-2ehi"
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%2F522asln7hhm2jpp96qar.png"
Automatic Backup and Synchronization of All Repositories from a Git Account or Organization
In this tutorial, I’ll explain how I cloned and kept all repositories from a GitHub account/organization synchronized. It also works for GitLab, Bitbucket, or any Git server that exposes an API and supports git clone
and git pull
.
🎯 Goal
- Download all repositories (public and private) from an account/organization.
- Store them in a local folder (optionally synced with OneDrive, Dropbox, etc.).
- Update them with a single command (
git pull
in each one). - Log everything into a file for auditing purposes.
🛠️ Environment Used
- OS: Windows 10/11
- Terminal: Git Bash (included with Git for Windows)
-
Required tools:
- git (pre-installed)
- curl (included in Git Bash)
- jq (https://stedolan.github.io/jq/)
🔑 Steps Taken and Lessons Learned
1️⃣ Creating the Access Token
- Create a Personal Access Token (PAT) in GitHub with permissions:
-
repo
(for private repos) -
read:org
(for organizations)
-
Problem: Using the organization endpoint on a user account returned 404 Not Found
.
Solution: Differentiate between user (/users/username/repos
) and organization (/orgs/org/repos
).
2️⃣ Initial Cloning Script
ORG_NAME="Example-Organization"
OUTPUT_DIR="."
REPOS_FILE="$OUTPUT_DIR/repos.txt"
GITHUB_TOKEN="YOUR_TOKEN_HERE"
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"
✅ Works for cloning all repos.
❌ Fails on repeated execution: fatal: destination path already exists
.
3️⃣ Improved for Synchronization (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
✅ Updates if it already exists.
❌ Fails if folder name ≠ repo name (case sensitivity issues).
4️⃣ Robust Solution
if [ -d "$repo_name/.git" ]; then
(cd "$repo_name" && git pull)
elif [ -d "$repo_name" ]; then
echo "⚠️ Folder $repo_name exists but is not a Git repo"
else
git clone "$repo_url"
fi
✅ Correctly updates all existing repos.
5️⃣ Logging
LOG_FILE="$(pwd)/sync-repos.log"
echo "$(date) - Starting synchronization" | tee -a "$LOG_FILE"
while read -r repo_url; do
repo_name=$(basename "$repo_url" .git)
if [ -d "$repo_name/.git" ]; then
echo "📥 Updating $repo_name" | tee -a "$LOG_FILE"
(cd "$repo_name" && git pull >> "$LOG_FILE" 2>&1)
else
echo "📦 Cloning $repo_name" | tee -a "$LOG_FILE"
git clone "$repo_url" >> "$LOG_FILE" 2>&1
fi
done < "$REPOS_FILE"
echo "$(date) - Finished" | tee -a "$LOG_FILE"
📂 Backup Location
-
OUTPUT_DIR="."
→ saves in the current folder. - Fixed location in Windows + Git Bash:
OUTPUT_DIR=/c/Users/username/OneDrive/Backups/github
🔄 Adapting for GitLab or Bitbucket
- GitLab:
https://gitlab.com/api/v4/groups/<group>/projects
- Bitbucket:
https://api.bitbucket.org/2.0/repositories/<user>
- Adjust authentication (Bearer token, Basic Auth, etc.).
💡 Final Recommendations
- Test first in a sandbox folder.
- Avoid spaces in paths or escape them with
\
. - Handle network errors with
set -e
or validations. - Schedule execution with Task Scheduler (Windows) or cron (Linux).
- Keep logs for historical records.
Top comments (0)