Skip to content

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

FieldRequiredDefaultDescription
mirror_dirYesWhere bare mirror repos are stored
stage_dirNo<mirror_dir>/.stageTemp staging dir (must be on same filesystem)
workersNo4Concurrent mirror goroutines
lfs_enabledNofalseRun git lfs fetch --all after each sync
log_file_pathNo"" (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"?>
<!DOCTYPEplist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plistversion="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:

@echooffsetGITHUB_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

ScheduleLinux/macOS cronlaunchd (seconds)Windows
Every hour0 * * * *3600Repeat every 1 hour
Every 6 hours0 */6 * * *21600Repeat every 6 hours
Daily at 3 AM0 3 * * *Use StartCalendarIntervalDaily at 03:00
Twice daily0 0,12 * * *43200Repeat every 12 hours

About

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

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Contributors

Languages