github-backup

github-backup is a GitHub backup tool written in Rust. It backs up the repositories, issues, pull requests, releases, gists, wikis and relationship data of a GitHub user or organisation to a local directory, optionally copies the JSON metadata to S3-compatible storage and the git data to another git host. TLS is rustls (no OpenSSL), the S3 client is a pure-Rust SigV4 implementation (no AWS SDK), and an optional full-screen TUI is available with --tui.

Documentation version. These pages describe the current development branch (main). The latest release, v0.3.2, predates many of the behaviours described here (exit status 3, per-repository incremental state, lossless JSON, --doctor, restore changes, and more); the Unreleased section of the changelog lists them. See Installation for how to get a matching build.

Feature Highlights

FeatureDetails
RepositoriesMirror, bare, full or shallow clones, kept up to date with git fetch; optional Git LFS objects
Issues and pull requestsThe lists, comments, events, commits and reviews, saved as GitHub's complete JSON responses
ReleasesMetadata and, optionally, the assets (streamed, size and checksum verified)
Gists and wikisOwned gists and repository wikis cloned; starred gists as metadata
MetadataTopics, branches and protection rules, labels, milestones, hooks, deploy keys, collaborators, security advisories, Actions workflows, runs and environments, package metadata
User and organisation dataStarred, watched, followers, following, organisation members and teams; optional clone of every starred repository
Private dataA user's own private repositories and secret gists are included when the token belongs to that user
Filters--include-repos / --exclude-repos glob patterns on repository names
Incremental runsA watermark per repository; lists are always fetched in full and merged, so a run never loses data; --full forces a complete refresh
Honest outcomeFailures never stop the rest of the run; exit status 3 means "finished but incomplete"; report, metrics, webhook and history agree
S3 syncThe JSON metadata (not the clones) to AWS S3, Backblaze B2, MinIO, Cloudflare R2, Spaces or Wasabi, with content-digest skipping
At-rest encryptionAES-256-GCM of the S3 uploads (--encrypt-key)
Push mirrorsBranches and tags to Gitea, Forgejo, Codeberg or GitLab; repositories created private by default; never overwrites a repository it did not create
RestoreLabels, milestones and issues back into an organisation, from the local backup (--restore)
AuthenticationPersonal access token, OAuth device flow, or anonymous (public data only)
GitHub Enterprise Server--api-url and --clone-host
Config fileTOML; see precedence for how it combines with the command line
MonitoringJSON report, Prometheus textfile metrics, webhook, run history
Safety--dry-run writes nothing; OS file locks (no stale locks); atomic writes; atomic clones
Interactive TUIFull-screen terminal interface with live progress (--tui)
ContainersAlpine-based multi-arch image, Compose profiles, Unraid template

What It Does Not Back Up

  • Discussions and Projects: GitHub's REST API has no endpoints for them (--discussions and --projects are accepted but do nothing).
  • Actions secrets and variables, code-scanning and Dependabot alerts, rulesets, issue attachments, commit comments and statuses.
  • Git LFS objects unless you pass --lfs (requires git-lfs).
  • Repository clones are not uploaded to S3, only the JSON metadata.
  • It cannot see what the token cannot see: other users' private data, or categories the token lacks permission for (a 403/404 is skipped with an INFO line and is not counted as a failure).
  • Pull requests, comments and reactions cannot be restored; --restore handles labels, milestones and issues only.

See What Is Not Restored, or Not Backed Up.

Design Principles

  • No OpenSSL, no reqwest, no AWS SDK: TLS via rustls, HTTP via hyper.
  • No unsafe in the workspace's own source.
  • Trait-based: BackupClient, Storage and GitRunner make the engine testable without network or filesystem.
  • Credentials stay out of argument lists, URLs and files: git receives the token through an environment variable and a host-scoped credential helper.
  • Rate-limit aware: rate-limit responses are waited out and retried.
  • A backup that is incomplete says so: see Monitoring.