Skip to content

fauzaanu/github-backup

Repository files navigation

GitHub HDD Mirror

Mirrors all your GitHub repositories to a local drive. Discovers every repo you have access to (personal, private, org), creates bare mirror clones, and keeps them current with incremental fetches.

Highlights

  • Bare mirror clones with all refs and branches
  • Incremental updates — never re-downloads everything
  • Atomic staging so failed clones don't corrupt existing backups
  • Resume interrupted syncs
  • Concurrent workers
  • Git LFS support
  • Linux, macOS, Windows

Install

Download a binary from the Releases page, or build from source:

make build        # outputs to bin/

Quick Start

  1. Set your GitHub PAT: export GITHUB_MIRROR_PAT=ghp_...
  2. Copy and edit the config: cp mirror-config.example.json mirror-config.json
  3. Run: github-hdd-mirror --config ./mirror-config.json

You can also run github-hdd-mirror with no flags — it will use ./mirror-config.json if it exists, or mirror to the current directory.

See mirror-config.example.json for all options.

Configuration

Field Required Default Description
mirror_dir Yes Where bare mirror repos are stored
stage_dir No <mirror_dir>/.stage Temp staging dir (must be on same filesystem)
workers No 4 Concurrent mirror goroutines
lfs_enabled No false Run git lfs fetch --all after each sync
log_file_path No "" (stdout) Path to JSON Lines log file

The GitHub PAT is read from the GITHUB_MIRROR_PAT environment variable (or a .env file in the working directory). See .env.example for details.

Scheduling Automatic Backups

The tool runs a single sync and exits — scheduling is handled by your OS. Pick the section for your platform below.

Linux (cron)

crontab -e

Add a line:

0 */6 * * * cd /opt/github-mirror && ./github-hdd-mirror --config ./mirror-config.json >> /var/log/github-mirror-cron.log 2>&1

The cd ensures the .env file is found. Alternatively, pass the PAT inline:

0 */6 * * * GITHUB_MIRROR_PAT=ghp_xxx /opt/github-mirror/github-hdd-mirror --config /opt/github-mirror/mirror-config.json >> /var/log/github-mirror-cron.log 2>&1

Verify your crontab is active:

crontab -l

macOS (launchd)

macOS uses launchd instead of cron. Create a plist file:

nano ~/Library/LaunchAgents/com.github-hdd-mirror.plist
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>Label</key>
    <string>com.github-hdd-mirror</string>

    <key>ProgramArguments</key>
    <array>
        <string>/usr/local/bin/github-hdd-mirror</string>
        <string>--config</string>
        <string>/opt/github-mirror/mirror-config.json</string>
    </array>

    <key>WorkingDirectory</key>
    <string>/opt/github-mirror</string>

    <key>EnvironmentVariables</key>
    <dict>
        <key>GITHUB_MIRROR_PAT</key>
        <string>ghp_YOUR_TOKEN_HERE</string>
    </dict>

    <key>StartInterval</key>
    <integer>21600</integer>

    <key>StandardOutPath</key>
    <string>/var/log/github-mirror.log</string>
    <key>StandardErrorPath</key>
    <string>/var/log/github-mirror.log</string>
</dict>
</plist>

Load it:

launchctl load ~/Library/LaunchAgents/com.github-hdd-mirror.plist

To unload:

launchctl unload ~/Library/LaunchAgents/com.github-hdd-mirror.plist

StartInterval is in seconds — 21600 = 6 hours.

Windows (Task Scheduler)

Option A: GUI

  1. Open Task Scheduler (taskschd.msc)
  2. Click "Create Basic Task"
  3. Name it GitHub HDD Mirror
  4. Trigger: Daily, repeat every 6 hours
  5. Action: Start a Program
    • Program: C:\tools\github-hdd-mirror.exe
    • Arguments: --config C:\tools\mirror-config.json
    • Start in: C:\tools
  6. Finish and check "Open the Properties dialog" to set the environment variable

To set GITHUB_MIRROR_PAT, edit the task and wrap it in a batch script instead:

@echo off
set GITHUB_MIRROR_PAT=ghp_YOUR_TOKEN_HERE
C:\tools\github-hdd-mirror.exe --config C:\tools\mirror-config.json >> C:\tools\logs\mirror.log 2>&1

Then point the task at the batch script.

Option B: PowerShell (one-liner setup)

$action = New-ScheduledTaskAction `
    -Execute "C:\tools\github-hdd-mirror.exe" `
    -Argument "--config C:\tools\mirror-config.json" `
    -WorkingDirectory "C:\tools"

$trigger = New-ScheduledTaskTrigger -Daily -At "03:00AM"

# Repeat every 6 hours for the duration of 1 day
$trigger.Repetition = (New-ScheduledTaskTrigger -Once -At "00:00" -RepetitionInterval (New-TimeSpan -Hours 6) -RepetitionDuration (New-TimeSpan -Days 1)).Repetition

Register-ScheduledTask -TaskName "GitHub HDD Mirror" -Action $action -Trigger $trigger -Description "Mirror GitHub repos to local drive"

Set the PAT as a system environment variable:

[System.Environment]::SetEnvironmentVariable("GITHUB_MIRROR_PAT", "ghp_YOUR_TOKEN_HERE", "User")

Common Intervals

Schedule Linux/macOS cron launchd (seconds) Windows
Every hour 0 * * * * 3600 Repeat every 1 hour
Every 6 hours 0 */6 * * * 21600 Repeat every 6 hours
Daily at 3 AM 0 3 * * * Use StartCalendarInterval Daily at 03:00
Twice daily 0 0,12 * * * 43200 Repeat every 12 hours

About

CLI tool to mirror all your GitHub repositories to a local drive

Resources

Stars

Watchers

Forks

Contributors