Skip to main content

GitHub Backup Sync logo

GitHub Backup Sync

Mirror every GitHub repository you can access into local git backups.
Authenticated through the GitHub CLI, so there are no tokens to juggle.

PyPI version Python versions Monthly downloads Tests Coverage License

github-backup-sync mirrors every GitHub repository your account can access (owned, collaborator, and organization member) into bare --mirror clones, grouping sources and forks separately.

The project was inspired after watching ThePrimeTime's reminder about GitHub bans, highlighting why local backups matter. Plenty of alternative backup tools exist, but I wanted something simple that relies on the GitHub CLI for authentication so I never have to juggle API tokens directly.

Table of Contents

Features

  • Complete mirrors: bare git clone --mirror copies keep every branch, tag, and ref; re-runs update them in place.
  • Sources and forks apart: forks land in their own directory, or skip them entirely with --skip-forks.
  • No token management: the token comes from gh auth token, so staying logged in to the GitHub CLI is all it takes.
  • Fast: repositories sync in parallel (--workers).
  • Safe pruning: mirrors of repositories that disappeared upstream are listed on every run and only deleted with --prune.
  • Flexible: optional working-tree checkouts, Git LFS objects, and archived-repository filtering.
  • Single file: one script with a uv run --script shebang, so you can also vendor it anywhere.

Quick Start

gh auth login                                  # once
uvx github-backup-sync --root ~/github-backups # mirror everything

Run the same command again whenever you want to pull in new commits, branches, and repositories.

Requirements

  • uv (recommended) or any Python 3.12+ environment
  • GitHub CLI (gh) authenticated with gh auth login
  • git, plus git-lfs if you use --lfs
  • SSH access to GitHub for the default SSH remotes, or pass --https

Installation

Method Command
Run without installing uvx github-backup-sync --help
Install as a tool uv tool install github-backup-sync
Install with pip pip install github-backup-sync
Vendor the script Copy github_backup_sync.py and run ./github_backup_sync.py

uvx fetches the latest release on each run, while uv tool install puts a github-backup-sync executable on your PATH. The vendored script installs its own dependencies through the uv run --script shebang.

Usage

# If installed from PyPI
github-backup-sync --root /path/to/mirrors [--https] [--prune] [--skip-forks] [--workers 4]

# From a local checkout
./github_backup_sync.py --root /path/to/mirrors [--https] [--prune] [--skip-forks] [--workers 4]

Options

Option Description
-r, --root PATH Backup directory (required, created if missing)
--https Use HTTPS remotes instead of SSH, authenticated through the GitHub CLI
--prune Delete local mirrors that no longer exist upstream; without it they are only listed
--working-tree / --bare Clone with files checked out instead of bare mirrors (default: --bare)
--include-archived / --exclude-archived Whether to back up archived repositories (default: include)
--skip-forks Mirror only non-fork repositories
--lfs Fetch Git LFS objects after mirroring
-w, --workers N Parallel sync operations (default: CPU count, capped at 8)
--sleep SECONDS Delay between repositories
--limit N Process at most N repositories, handy for smoke tests

CLI Help

github_backup_sync.py --help output
 Usage: github_backup_sync.py [OPTIONS]

 Mirror every GitHub repository you can access into local git mirrors.

╭─ Options ──────────────────────────────────────────────────────────────────────────────────────────────────╮
│ --root              -r                        <path>                  Directory that will hold the mirror  │
│ --https                                                               Use HTTPS remotes, authenticated     │
│                                                                       through the GitHub CLI               │
│ --include-archived      --exclude-archived                            Include archived repositories        │
│                                                                       [default: include-archived]          │
│ --prune                                                               Remove local mirrors that no longer  │
│                                                                       exist upstream                       │
│ --lfs                                                                 Fetch Git LFS objects after          │
│                                                                       mirroring                            │
│ --working-tree          --bare                                        Clone repositories as working trees  │
│                                                                       instead of bare mirrors              │
│                                                                       [default: bare]                      │
│ --sleep                                       <float range> [x>=0.0]  Delay between repositories in        │
│                                                                       seconds                              │
│                                                                       [default: 0.0]                       │
│ --limit                                       <int range> [x>=1]      Process at most this many            │
│                                                                       repositories                         │
│ --skip-forks                                                          Ignore forked repositories while     │
│                                                                       mirroring                            │
│ --workers           -w                        <int range> [x>=1]      Max concurrent mirror operations     │
│                                                                       (default: based on CPU count)        │
│ --help              -h                                                Show this message and exit.          │
╰────────────────────────────────────────────────────────────────────────────────────────────────────────────╯

Layout

<root>/source/<owner>/<repo>.git
<root>/forks/<owner>/<repo>.git

This is the default layout when backing up as bare mirrors. When --working-tree is used, the .git suffix is omitted and each directory contains a checked-out working tree instead.

Working with Mirrors

Repositories under source/ and forks/ are bare --mirror clones, so they do not contain a checked-out working tree unless you opted into --working-tree. Clone from a mirror path when you want editable files:

git clone /srv/github-backups/source/basnijholt/dotfiles.git ~/dotfiles

You can also inspect a mirror directly without cloning by pointing Git commands at it:

git --git-dir=/srv/github-backups/source/basnijholt/dotfiles.git log --oneline

Automated Backups (cron)

Schedule a daily sync with cron:

0 3 * * * /usr/bin/env uvx github-backup-sync --root /srv/github-backups --https --prune --workers 4 >> /var/log/github-backup-sync.log 2>&1

This example runs every day at 03:00, prunes mirrors of deleted repositories, and logs the output. The cron user needs uv on its PATH and a logged-in gh. Adjust the path, flags, and worker count to suit your environment.

License

MIT

Metadata

Release files for github-backup-sync 0.2.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for github-backup-sync 0.2.1
File Size Uploaded
github_backup_sync-0.2.1.tar.gz 12.0 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for github-backup-sync 0.2.1
File Interpreter ABI Platform
github_backup_sync-0.2.1-py3-none-any.whl Python 3 none any Details

Total release size: 24.1 kB

Release files / github_backup_sync-0.2.1.tar.gz

Download URL github_backup_sync-0.2.1.tar.gz
Size 12.0 kB
Tags Source
SHA-256 checksum
How to use checksums
b6cbaaac78649edc805cce7984851ea6d6d2489fa2baefed455f35193261e3c3
BLAKE2b-256 checksum
How to use checksums
26411d30ddc4fe49d1130bfb5613987185fdbe55ae17bf87b182283c6c68a304
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 10, 2026.

Transparency log

Release files / github_backup_sync-0.2.1-py3-none-any.whl

Download URL github_backup_sync-0.2.1-py3-none-any.whl
Size 12.1 kB
Tags Python 3
SHA-256 checksum
How to use checksums
0fd20b35f829d18f58fbc323a595d233c735b2fb830d158d9f4eb7f7f73d1639
BLAKE2b-256 checksum
How to use checksums
8f6584c0c40833a15d11ce832db26acf3d01f50e0663d198bc57f04ac2591104
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 10, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.2.1 This release

2 release files

0.2.0

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page