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; the gh token authenticates private repositories
--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 (token optional    │
│                                                                       for public repos)                    │
│ --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.0

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.0
File Size Uploaded
github_backup_sync-0.2.0.tar.gz 11.8 kB Details

Built distribution (wheel)

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

Total release size: 23.6 kB

Release files / github_backup_sync-0.2.0.tar.gz

Download URL github_backup_sync-0.2.0.tar.gz
Size 11.8 kB
Tags Source
SHA-256 checksum
How to use checksums
085c0a333cee1208ac47b58ddceb88fa0130c26cb2f3aed87ea5667269dc98ff
BLAKE2b-256 checksum
How to use checksums
ba68209c730930f054c0d03910dca1f0329f39c3738646a4494b5c71afb2a391
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.0-py3-none-any.whl

Download URL github_backup_sync-0.2.0-py3-none-any.whl
Size 11.8 kB
Tags Python 3
SHA-256 checksum
How to use checksums
be31832aa42a122ee57a50ea4e9e0a543f9da6e01024b76ef97fa4f5bc160354
BLAKE2b-256 checksum
How to use checksums
d334e13c9caa744fa4d986b1ae2b2402e282fb3579b0faf14d5e0fc20f58bbf5
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

0.2.1

2 release files

This release

0.2.0 This release

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