Skip to content

Instantly share code, notes, and snippets.

@0xMurage
Last active April 30, 2026 06:50
Show Gist options
  • Select an option

  • Save 0xMurage/63339abd6e850414d85116fe131eab3e to your computer and use it in GitHub Desktop.

Select an option

Save 0xMurage/63339abd6e850414d85116fe131eab3e to your computer and use it in GitHub Desktop.
Script to Mirror All User and Org GitHub Repositories Via SSH
#!/bin/sh
# ==============================================================================
# DESCRIPTION: Mirrors all repositories the user has access to (personal & orgs).
# GitHub SSH must be properly configured to clone repos successfuly.
# ==============================================================================
TOKEN="" # Replace with a valid GitHub PAT (use classic toke with 'repo' and 'read:org' scopes to read all orgs user has acces to)
SCRIPT_DIR=$(cd "$(dirname "$0")" && pwd)
BACKUP_DIR="$SCRIPT_DIR/backups"
LAST_SYNC_FILE="$BACKUP_DIR/.last_sync"
# ISO8601 date for the sync file
NOW=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
# Ensure backup directory exists
mkdir -p "$BACKUP_DIR"
# Get last sync time (POSIX way)
if [ -f "$LAST_SYNC_FILE" ]; then
LAST_SYNC=$(cat "$LAST_SYNC_FILE")
else
LAST_SYNC="1970-01-01T00:00:00Z"
fi
echo "Checking for changes since $LAST_SYNC..."
PAGE=1
while :; do
# Fetch a page of repos (includes Org repos if you have access)
REPOS=$(curl -s -H "Authorization: token $TOKEN" \
"https://api.github.com/user/repos?sort=pushed&direction=desc&per_page=100&page=$PAGE&type=all&since=$LAST_SYNC")
# Check if the response is empty or an error
COUNT=$(echo "$REPOS" | jq '. | length')
if [ "$COUNT" -eq 0 ] || [ -z "$COUNT" ]; then
break
fi
# Process each repo in the current page
echo "$REPOS" | jq -c '.[]' | while read -r repo; do
CLONE_URL=$(echo "$repo" | jq -r '.ssh_url')
FULL_NAME=$(echo "$repo" | jq -r '.full_name') # e.g., "MyOrg/ProjectA"
OWNER=$(echo "$FULL_NAME" | cut -d'/' -f1)
REPO_NAME=$(echo "$FULL_NAME" | cut -d'/' -f2)
# Create the organization/user folder that mirrors GitHub (Org/Repo)
ORG_PATH="$BACKUP_DIR/$OWNER"
mkdir -p "$ORG_PATH"
TARGET="$ORG_PATH/$REPO_NAME.git"
echo "Syncing: $OWNER / $REPO_NAME ..."
if [ -d "$TARGET" ]; then
(cd "$TARGET" && git fetch --all --prune)
else
git clone --mirror "$CLONE_URL" "$TARGET"
fi
done
PAGE=$((PAGE + 1))
done
# Update the sync timestamp
echo "$NOW" >"$LAST_SYNC_FILE"
echo "Sync complete."
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment