Created
August 1, 2025 11:49
-
-
Save johannschopplich/964362450360b3fb1d1e5c657446aa12 to your computer and use it in GitHub Desktop.
GitHub backup script
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/usr/bin/env bash | |
| # GitHub Backup Script | |
| # Backs up all accessible repositories (public & private) to organized ZIP files | |
| set -euo pipefail | |
| # Terminal colors | |
| RED='\033[0;31m' | |
| GREEN='\033[0;32m' | |
| YELLOW='\033[1;33m' | |
| BLUE='\033[1;34m' | |
| NC='\033[0m' | |
| # Check dependencies | |
| for cmd in curl jq git zip; do | |
| command -v "$cmd" >/dev/null 2>&1 || { | |
| echo -e "${RED}β Missing dependency: $cmd${NC}" >&2 | |
| exit 1 | |
| } | |
| done | |
| if [[ -z "${GITHUB_TOKEN:-}" ]]; then | |
| echo -e "${RED}β Please export GITHUB_TOKEN first${NC}" >&2 | |
| exit 1 | |
| fi | |
| # Configuration | |
| PER_PAGE=100 | |
| TODAY=$(date +%F) | |
| BACKUP_DIR="github-backups/$TODAY" | |
| mkdir -p "$BACKUP_DIR" | |
| echo -e "${BLUE}π¦ Output directory:${NC} $BACKUP_DIR" | |
| gh_api() { | |
| local url=$1 | |
| if ! curl -sSfL \ | |
| -H "Authorization: Bearer $GITHUB_TOKEN" \ | |
| -H "Accept: application/vnd.github+json" \ | |
| -H "User-Agent: github-backup-script" \ | |
| "$url"; then | |
| echo -e "${RED}β API request failed: $url${NC}" >&2 | |
| return 1 | |
| fi | |
| } | |
| list_repos() { | |
| local page=1 | |
| local repos=() | |
| while true; do | |
| local resp | |
| resp=$(gh_api "https://api.github.com/user/repos?per_page=$PER_PAGE&page=$page&type=all") | |
| local names | |
| names=$(echo "$resp" | jq -r '.[] | select(.archived == false) | .full_name') | |
| if [[ -z "$names" ]]; then | |
| break | |
| fi | |
| while IFS= read -r name; do | |
| [[ -n "$name" ]] && repos+=("$name") | |
| done <<< "$names" | |
| ((page++)) | |
| done | |
| printf '%s\n' "${repos[@]}" | |
| } | |
| backup_repo() { | |
| local full_name=$1 | |
| local owner repo | |
| owner=${full_name%%/*} | |
| repo=${full_name##*/} | |
| local owner_dir="$BACKUP_DIR/$owner" | |
| mkdir -p "$owner_dir" | |
| local repo_dir="$owner_dir/$repo" | |
| echo -e "${YELLOW}π Cloning ${full_name}β¦${NC}" | |
| git clone "https://github.com/${full_name}.git" "$repo_dir" --quiet --depth=1 | |
| echo -e "${GREEN}πΎ Archiving ${full_name} β ${owner}/${repo}.zip${NC}" | |
| (cd "$repo_dir" && zip -qr "../${repo}.zip" .) | |
| rm -rf "$repo_dir" | |
| } | |
| echo -e "${BLUE}π Authenticating & fetching repo listβ¦${NC}" | |
| ALL_REPOS=() | |
| while IFS= read -r repo; do | |
| [[ -n "$repo" ]] && ALL_REPOS+=("$repo") | |
| done < <(list_repos) | |
| TOTAL=${#ALL_REPOS[@]} | |
| echo -e "${BLUE}π Found $TOTAL repositories${NC}" | |
| COUNT=0 | |
| for r in "${ALL_REPOS[@]}"; do | |
| backup_repo "$r" && ((COUNT++)) | |
| done | |
| echo -e "${GREEN}β Backup complete: ${COUNT}/${TOTAL} repos archived${NC}" | |
| echo -e "${BLUE}π Everything stored in $BACKUP_DIR${NC}" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment