Created
February 20, 2026 09:27
-
-
Save dewomser/9e7d278dd31718f47594cfbf7e1a4c85 to your computer and use it in GitHub Desktop.
Backup all your Gists . Clone to local
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
| #!/bin/bash | |
| # Script to pull GitHub gists | |
| # Based on the functional model in models/gist-backup.sh | |
| # Configuration | |
| GITHUB_USERNAME="foo" | |
| # Path to backup directory (change this to your preferred location) | |
| BACKUP_PATH="/home/foo/github-gists-backup-$(date '+%Y-%m-%d-%H')" | |
| GITHUB_TOKEN="$GIST_TOKEN" | |
| #echo $GITHUB_TOKEN | |
| # Max length for folder name prefix (from file name) | |
| MAX_NAME_LENGTH=30 | |
| # Current date in DDMMYY format for folder naming | |
| CURRENT_DATE=$(date '+%d%m%y') | |
| # Log function | |
| log() { | |
| echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | |
| } | |
| # Error log function | |
| error_log() { | |
| echo "[$(date '+%Y-%m-%d %H:%M:%S')] ERROR: $1" >&2 | |
| } | |
| # Create backup directory | |
| log "Starting GitHub gists backup to $BACKUP_PATH" | |
| mkdir -p "$BACKUP_PATH/public" "$BACKUP_PATH/private" || { | |
| error_log "Failed to create backup directories" | |
| exit 1 | |
| } | |
| # Log configuration | |
| log "Configuration:" | |
| log "- Username: $GITHUB_USERNAME" | |
| log "- Backup Path: $BACKUP_PATH" | |
| log "- GitHub Token: ${GITHUB_TOKEN:0:8}... (truncated)" | |
| # Check for required dependencies | |
| log "Checking for required dependencies..." | |
| for cmd in curl jq git; do | |
| if ! command -v $cmd &> /dev/null; then | |
| error_log "$cmd is not installed." | |
| exit 1 | |
| fi | |
| done | |
| log "All required dependencies are installed." | |
| # Change to backup directory | |
| cd "$BACKUP_PATH" || { | |
| error_log "Failed to change to backup directory" | |
| exit 1 | |
| } | |
| log "Fetching Gists for user: $GITHUB_USERNAME..." | |
| # Initialize counters | |
| SUCCESSFUL=0 | |
| FAILED=0 | |
| # Fetch and process gists with pagination | |
| page=20 | |
| MAX_PAGES=20 # Safety limit to prevent infinite loops | |
| while [ $page -le $MAX_PAGES ]; do | |
| log "Fetching page $page..." | |
| response="$(curl --header "Authorization: 'token' '$GITHUB_TOKEN'" -L "https://api.github.com/users/dewomser/gists?page=2&per_page=100")" | |
| log "bei mehr als 100 Gists muss nach dem 1. Durchlauf … page=2 … gesetzt werden und Skript neu starten" | |
| # Check for errors or empty response | |
| if [[ "$response" == "[]" ]] || [[ "$response" == *"message"* && "$response" == *"error"* ]]; then | |
| log "No more gists found on page $page" | |
| break | |
| fi | |
| # Count items in the response | |
| item_count=$(echo "$response" | jq '. | length') | |
| if [ "$item_count" -eq 0 ]; then | |
| log "No more gists found on page $page (empty array)" | |
| break | |
| fi | |
| # Process each gist | |
| echo "$response" | jq -c '.[]' | while read -r gist; do | |
| gist_id=$(echo "$gist" | jq -r '.id') | |
| is_public=$(echo "$gist" | jq -r '.public') | |
| git_url=$(echo "$gist" | jq -r '.git_pull_url') | |
| # Determine if public or private | |
| if [ "$is_public" = "true" ]; then | |
| visibility="public" | |
| else | |
| visibility="private" | |
| fi | |
| # Get the first filename from the gist | |
| filename=$(echo "$gist" | jq -r '.files | keys | .[0]') | |
| # Create a sanitized folder name from the filename (first MAX_NAME_LENGTH chars) | |
| # Remove special characters and spaces, replace with underscores | |
| sanitized_name=$(echo "${filename:0:$MAX_NAME_LENGTH}" | tr -c '[:alnum:]' '_' | tr -s '_') | |
| folder_name="${sanitized_name}_${CURRENT_DATE}" | |
| # Full path for this gist | |
| gist_path="$BACKUP_PATH/$visibility/$folder_name" | |
| # New gist, clone it | |
| log "Cloning gist $gist_id to $gist_path..." | |
| if git clone --quiet "$git_url" "$gist_path"; then | |
| # Create a marker file with the gist ID for future incremental updates | |
| echo "$gist_id" > "$gist_path/.gist_id" | |
| log "Successfully cloned gist $gist_id to $gist_path" | |
| ((SUCCESSFUL++)) | |
| fi | |
| done | |
| page=$((page + 1)) | |
| done | |
| # Print summary | |
| log "=== Backup Summary ===" | |
| log "Successful: $SUCCESSFUL" | |
| log "Failed: $FAILED" | |
| log "Backup location: $BACKUP_PATH" | |
| # Log total disk usage | |
| TOTAL_SIZE=$(du -sh "$BACKUP_PATH" | cut -f1) | |
| log "Total backup size: $TOTAL_SIZE" | |
| # Log completion time | |
| log "Backup completed at: $(date '+%Y-%m-%d %H:%M:%S')" | |
| # Exit with error if any backups failed | |
| if [ "$FAILED" -gt 0 ]; then | |
| error_log "Backup completed with $FAILED failures" | |
| exit 1 | |
| else | |
| log "✅ Gist backup complete: $BACKUP_PATH" | |
| exit 0 | |
| fi |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment