Skip to content

Instantly share code, notes, and snippets.

@AndrewAltimit
Last active July 4, 2025 17:28
Show Gist options
  • Save AndrewAltimit/23acbef0545f79840947e4954ef89085 to your computer and use it in GitHub Desktop.
Save AndrewAltimit/23acbef0545f79840947e4954ef89085 to your computer and use it in GitHub Desktop.
Backup GitHub Repos

GitHub Repository Complete Backup

A Docker-based solution to create complete backups of private GitHub repositories, including all branches, history, and LFS files.

What's Included in the Backup

  • ✅ All branches and tags
  • ✅ Complete commit history
  • ✅ All Git LFS files
  • ✅ All refs and remote tracking info
  • ✅ Compressed into a single .tar.gz archive

Quick Start

  1. Clone this gist and set up credentials:
# Create .env file with your GitHub credentials
cat > .env << EOF
GITHUB_TOKEN=your_personal_access_token_here
GITHUB_USER=yourusername
REPO_NAME=your-repo-name
EOF
  1. Run the backup:
# Create the backup
docker compose run --rm github-backup
  1. Find your backup:
ls -lh backups/
# Output: your-repo-name-backup-2024-01-15-143022.tar.gz

Restore from Backup

# Extract the archive
tar -xzf backups/your-repo-name-backup-*.tar.gz

# Option 1: Create a normal repo from backup
git clone your-repo-name.git restored-repo
cd restored-repo
git branch -a  # Shows all branches

# Option 2: Push to a new GitHub repo
cd your-repo-name.git
git push --mirror https://github.com/username/new-repo.git
git lfs push --all https://github.com/username/new-repo.git

Requirements

  • Docker and Docker Compose
  • GitHub Personal Access Token with repo scope
  • Enough disk space for your repository + compressed archive

How It Works

  1. Uses git clone --mirror to create a complete bare repository
  2. Fetches all LFS objects with git lfs fetch --all
  3. Compresses everything into a timestamped .tar.gz archive
  4. Cleans up temporary files, leaving only the archive

Notes

  • The backup is a "bare" repository (no working files, just Git data)
  • Archives are timestamped for versioning
  • Compression uses gzip level 6 (balanced speed/size)
  • For large repositories with many LFS files, ensure adequate disk space

Troubleshooting

If folders like refs/heads/ appear empty after extraction, this is normal. Branches are often stored in the packed-refs file. Verify your backup with:

git clone your-repo-name.git test-restore
cd test-restore
git branch -a  # Should list all branches
# GitHub Personal Access Token (needs 'repo' scope for private repos)
GITHUB_TOKEN=your_personal_access_token_here
# Your GitHub username or organization
GITHUB_USER=AndrewAltimit
# Repository name (without .git extension)
REPO_NAME=VSExample
version: '3.8'
services:
github-backup:
image: alpine/git:latest
environment:
- GITHUB_TOKEN=${GITHUB_TOKEN}
- GITHUB_USER=${GITHUB_USER}
- REPO_NAME=${REPO_NAME}
volumes:
- ./backups:/backups
- ./scripts:/scripts
entrypoint: ["/bin/sh", "-c"]
command: |
"set -e
echo 'Installing git-lfs...'
apk add --no-cache git-lfs
git lfs install
echo 'Creating backup directory...'
TIMESTAMP=$(date +%Y-%m-%d-%H%M%S)
BACKUP_DIR=/backups/temp-$$TIMESTAMP
mkdir -p $$BACKUP_DIR
cd $$BACKUP_DIR
echo 'Cloning repository with --mirror...'
git clone --mirror https://$${GITHUB_TOKEN}@github.com/$${GITHUB_USER}/$${REPO_NAME}.git
echo 'Fetching all LFS objects...'
cd $${REPO_NAME}.git
git lfs fetch --all
echo 'Creating compressed archive...'
cd /backups
tar -czf $${REPO_NAME}-backup-$$TIMESTAMP.tar.gz -C temp-$$TIMESTAMP .
echo 'Cleaning up temporary directory...'
rm -rf temp-$$TIMESTAMP
echo 'Backup complete!'
echo 'Archive created: /backups/$${REPO_NAME}-backup-$$TIMESTAMP.tar.gz'
ls -lh /backups/$${REPO_NAME}-backup-$$TIMESTAMP.tar.gz"
@echo off
REM Run the backup
echo Starting GitHub repository backup...
docker compose run --rm github-backup
REM Show the created backup
echo.
echo Backup files:
dir /b /o-d backups\*.tar.gz 2>nul
if errorlevel 1 (
echo No backup files found in backups directory
)
REM Optional: Keep only the last N backups (remove REM to enable)
REM set KEEP_BACKUPS=5
REM cd backups
REM for /f "skip=%KEEP_BACKUPS% delims=" %%f in ('dir /b /o-d *.tar.gz 2^>nul') do del "%%f"
REM cd ..
REM echo.
REM echo Kept last %KEEP_BACKUPS% backups
#!/bin/bash
# Run the backup
echo "Starting GitHub repository backup..."
docker-compose run --rm github-backup
# Show the created backup
echo -e "\nBackup files:"
ls -lh ./backups/*.tar.gz
# Optional: Keep only the last N backups (uncomment to enable)
# KEEP_BACKUPS=5
# cd ./backups
# ls -t *.tar.gz | tail -n +$((KEEP_BACKUPS+1)) | xargs -r rm
# echo -e "\nKept last $KEEP_BACKUPS backups"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment