CLI Reference

Reference for every github-backup command-line flag. github-backup --help is the authoritative list for the binary you have installed; this page is checked against it, and the Env var and Default columns are taken from it.

Synopsis

github-backup [OPTIONS] [OWNER]
github-backup [OWNER] --tui
github-backup --config <FILE> [OPTIONS]
github-backup --completions <SHELL>
github-backup --print-config-template

--completions <SHELL> is not listed by --help (it is handled before the normal argument parsing); --help and --version (-h, -V) behave as usual.

Arguments

ArgumentDescription
[OWNER]GitHub username or organisation name. May be omitted when --config supplies owner. It is used as a directory name under --output, so .., /, \ and control characters are rejected.

Authentication

FlagEnv varDefaultDescription
-t, --token <TOKEN>GITHUB_TOKENnonePersonal access token (classic or fine-grained). Prefer the variable: a command-line value is visible in ps.
--device-authnonefalseUse the GitHub OAuth device flow (interactive). Needs --oauth-client-id.
--oauth-client-id <CLIENT_ID>GITHUB_OAUTH_CLIENT_IDnoneOAuth App client ID. The variable is ignored unless --device-auth is given; the flag without --device-auth is an error.
--oauth-scopes <SCOPES>nonerepo gist read:orgScopes requested by the device flow (space-separated). These do not cover every category (for example --packages needs read:packages); see Authentication.

With no credential at all the tool runs unauthenticated (public data, 60 requests per hour). It refuses to start, with exit status 1, when one of --private, --hooks, --deploy-keys, --collaborators, --org-members, --org-teams, --actions, --action-runs, --packages, --discussions or --projects is given explicitly. That check does not look inside --all: an anonymous --all starts, and everything that needs a token fails or comes back empty.

GitHub Enterprise Server

FlagEnv varDefaultDescription
--api-url <URL>GITHUB_API_URLhttps://api.github.comAPI base URL. Must be https://.
--clone-host <HOST>GITHUB_CLONE_HOSTfrom the APIReplace the hostname in every clone URL.

See GitHub Enterprise Server.

Configuration

FlagDefaultDescription
-c, --config <FILE>noneTOML config file. Values in the file are defaults; see Config File for exactly how the command line and the file combine.
--print-config-templatefalsePrint an annotated config template and exit. Needs no owner or token.

Output

FlagDefaultDescription
-o, --output <DIR>.Root directory for everything the tool writes.
--report <FILE>noneWrite a JSON summary after the run (also after a failed run). See Monitoring.

Target Type

FlagDefaultDescription
--orgfalseTreat OWNER as an organisation.

Broad Selector

FlagDescription
--allEnable every category listed in --help for --all (see The --all flag). Conflicts with the individual category flags on the command line, but not with --forks, --private, --action-runs, --clone-starred, --lfs and the other behaviour flags, which are honoured next to --all.

Repository Options

FlagShortDefaultDescription
--repositoriesfalseClone or update repositories.
--forks-FfalseInclude forks.
--private-PfalseInclude private repositories. For a user target this needs a token that belongs to that user; see Private repositories.
--prefer-sshfalseClone over SSH instead of HTTPS (no token is used; git needs working SSH keys).
--clone-type <TYPE>mirrormirror, bare, full or shallow:<depth>; see Clone types.
--lfsfalseAlso fetch Git LFS objects (git lfs fetch --all) after the mirror update. Needs git-lfs installed; overrides --clone-type.
--prunefalseDelete branches and tags from the clone when they were deleted on GitHub. Without it they are kept; force-pushed branches are overwritten either way.
--no-pruneDeprecated and ignored: not pruning is the default. Cannot be combined with --prune.

Issue and Pull Request Options

FlagDescription
--issuesIssue list. Pull requests appear in it too.
--issue-commentsComments of every issue and pull request.
--issue-eventsEvents of every issue and pull request.
--pullsPull request list.
--pull-commentsInline review comments, per pull request.
--pull-commitsCommit list, per pull request (GitHub returns at most 250).
--pull-reviewsReviews, per pull request.

Repository Metadata

FlagDescription
--labelsLabels.
--milestonesMilestones.
--releasesRelease metadata.
--release-assetsDownload release assets. Requires --releases.
--hooksWebhook configurations (admin access).
--security-advisoriesPublished security advisories.
--wikisClone wikis.
--topicsTopics.
--branchesBranch list and, for protected branches, the protection rules (admin access).
--deploy-keysDeploy keys (admin access).
--collaboratorsCollaborators with permissions (admin access).

GitHub Actions and Environments

FlagDescription
--actionsWorkflow metadata (workflows.json).
--action-runsRun history per workflow. Requires --actions; can be very large; not part of --all.
--environmentsDeployment environments with protection rules.

Discussions, Classic Projects, Packages

FlagDescription
--discussionsNot functional. GitHub has no REST endpoint for Discussions; nothing is saved and a warning is logged. Still part of --all.
--projectsNot functional. Classic Projects are gone from GitHub's REST API; nothing is saved and a warning is logged. Still part of --all.
--packagesPackage metadata of the target user (needs read:packages).

Organisation Data

FlagDescription
--org-membersMember list (organisation targets only; ignored for users).
--org-teamsTeam list (organisation targets only; ignored for users).

User and Organisation Data

FlagDescription
--starredStarred repositories as a JSON list.
--clone-starredClone every starred repository as a bare mirror through a durable queue. Not part of --all, but honoured next to it.
--watchedWatched repositories.
--followersFollowers.
--followingAccounts followed.
--gistsClone gists owned by the target.
--starred-gistsMetadata of the gists starred by the authenticated user (not cloned).

Repository Filters

FlagDefaultDescription
--include-repos <PATTERN>allOnly repositories whose name matches (repeat the flag or separate with commas).
--exclude-repos <PATTERN>noneSkip repositories whose name matches; wins over --include-repos.

Patterns match the repository name only (not owner/name): * matches any sequence, ? one character, case-insensitively. There is no pattern for "archived" repositories; *archived* matches names that contain the word.

github-backup octocat --output /backup --repositories --include-repos "rust-*"
github-backup octocat --output /backup --repositories --exclude-repos "*-old,*-fork"

Incremental Behaviour

Issue and pull request lists are always fetched in full and merged into issues.json / pulls.json; a run never shrinks them. What is incremental is the per-item data (comments, events, commits, reviews): a repository's own watermark from the previous clean run decides which items can be skipped. See Incremental runs.

FlagDefaultDescription
--since <DATE>noneExpert override: treat everything updated before DATE as already backed up. Accepts 2024-01-01 (midnight UTC) or an RFC 3339 timestamp with any offset. Never written to the state file.
--fullfalseIgnore all watermarks and fetch every per-item file again. Conflicts with --since.

Push Mirror Options

FlagEnv varDefaultDescription
--mirror-to <URL>nonenoneBase URL of the destination (https://codeberg.org, https://gitlab.com, ...).
--mirror-type <TYPE>nonegiteagitea (Gitea, Codeberg, Forgejo) or gitlab.
--mirror-token <TOKEN>MIRROR_TOKENnoneAPI token for the destination. The variable is ignored unless --mirror-to is given.
--mirror-owner <OWNER>noneOWNERUser or organisation/namespace at the destination.
--mirror-privatenonefalseCreate every destination repository as private. This is the default; the flag states it explicitly. Cannot be combined with --mirror-public.
--mirror-publicnonefalseCreate mirrors of repositories that are public on GitHub as public. A private source, or one whose visibility is unknown, is still mirrored privately. Cannot be combined with --mirror-private.

See Mirroring.

S3 Options

FlagEnv varDefaultDescription
--s3-bucket <BUCKET>nonenoneBucket (must exist). Enables S3 sync of the JSON metadata; clones are not uploaded.
--s3-region <REGION>noneus-east-1Region.
--s3-prefix <PREFIX>noneemptyKey prefix; objects are stored as <prefix>/<owner>/json/<path>.
--s3-endpoint <URL>noneAWSCustom endpoint with scheme (B2, MinIO, R2, ...).
--s3-access-key <KEY>AWS_ACCESS_KEY_IDnoneAccess key ID. The variable is ignored unless --s3-bucket is given.
--s3-secret-key <SECRET>AWS_SECRET_ACCESS_KEYnoneSecret access key. Same rule.
--s3-session-token <TOKEN>AWS_SESSION_TOKENnoneSession token for temporary credentials. Same rule.
--s3-include-assetsnonefalseAlso upload release assets.
--s3-delete-stalenonefalseDelete remote objects whose local file is gone (guarded; see S3).

At-Rest Encryption

FlagEnv varDefaultDescription
--encrypt-key <HEX_KEY>BACKUP_ENCRYPT_KEYnone64 hexadecimal characters (32 bytes): encrypt files with AES-256-GCM before the S3 upload. Applies to S3 only.
--decryptnonefalseDecrypt one file and exit. Needs the key (--encrypt-key or BACKUP_ENCRYPT_KEY), no OWNER and no network.
--decrypt-input <FILE>nonenoneEncrypted input (with --decrypt).
--decrypt-output <FILE>nonenonePlaintext output (with --decrypt).

Restore

FlagEnv varDefaultDescription
--restorenonefalseRe-create labels, milestones and issues from the local backup in another organisation. Makes no backup first and does not contact the source.
--restore-target-org <ORG>noneOWNEROrganisation to restore into. The repositories must already exist there.
--restore-yesGITHUB_BACKUP_RESTORE_YES=1falseConfirm without the interactive prompt (required when stdin is not a terminal).

See the Restore guide.

Manifest and Verify

FlagDefaultDescription
--manifestfalseAfter the run, write json/backup_manifest.json with the SHA-256 of every data file under json/ (not the history, state, checkpoint and lock files, which change on every run).
--verifyfalseCheck the manifest of an existing backup and exit. Needs OWNER (and --output unless the backup is in the current directory); no network. Covers the files under json/ only, not the git clones. Conflicts with --all.

Monitoring

FlagEnv varDefaultDescription
--prometheus-metrics <FILE>nonenoneWrite node_exporter textfile metrics (also after a failed run).
--notify-webhook <URL>BACKUP_NOTIFY_WEBHOOKnonePOST a JSON status (success, partial or failure) after the run.
--diff-with <PREV_JSON_DIR>nonenoneAfter the run, log how the repository list differs from a previous backup's <owner>/json directory (repository names only).
--history-size <N>none20Entries kept in json/backup_history.json.

Execution Options

FlagDefaultDescription
--concurrency <N>4Repositories processed in parallel.
--dry-runfalseList what would be backed up; write nothing. See below.

What --dry-run does

A dry run fetches the repository list (read-only API calls) and logs which repositories it would back up. It writes nothing: no files or directories (not even the lock), no state, report, manifest, metrics, history, no webhook, no S3 upload and no mirror push, and it runs no git. Owner-level data and gists are skipped. With --restore it makes no API call at all.

Deprecated

FlagDescription
--keep-last <N>Ignored. A warning is logged after a real run.
--max-age-days <DAYS>Ignored. A warning is logged after a real run.

The tool keeps one continuously updated backup per owner under <output>/<owner>/; it never deletes snapshot directories. Rotate or expire copies with a tool built for it (restic, borg, ZFS or LVM snapshots, a lifecycle rule on the bucket). github-backup --help still describes the two flags as if they pruned directories; they do not.

Logging

FlagShortDefaultDescription
--quiet-qfalseErrors only; also hides the plan and summary banners.
--verbose-v0-v debug, -vv trace. Neither prints the token.

RUST_LOG overrides the level; see Environment Variables.

Diagnostics

FlagDescription
--doctorRun the pre-flight checks and exit (details below).
--check--doctor plus the resolved configuration (owner, output, API URL, concurrency and the scopes --list-scopes would print).
--list-scopesPrint the classic OAuth scopes recommended for the flags given and exit.

--doctor runs, in order: the git binary and its version, whether the output directory exists or can be created (it is created if missing) and is writable, the kind of credential (classic, fine-grained, OAuth or app token, judged by its prefix), whether the API answers, and whether GitHub accepts the token (GET /rate_limit, which costs no quota). A rejected token (HTTP 401 or 403) or an unreachable API is a failure; a server without /rate_limit is only a warning. It does not check free disk space, the token's scopes, S3 access, the mirror destination or git-lfs. It exits 0 when no check failed and 1 otherwise.

--list-scopes maps each enabled flag to the scopes it would need. With --all it prints only public_repo repo (it does not expand --all), and it recommends user:follow for --followers and admin:public_key for --deploy-keys, which only read data. For a token covering --all use the table in Authentication.

Interactive TUI

--tui starts the full-screen interface instead of a run. The owner, token, output directory and API URL given on the command line pre-fill the form; other flags are not read. See the Interactive TUI guide.

Shell Completions

--completions <SHELL> prints a completion script and exits without a token or network access. Supported shells: bash, zsh, fish, powershell, elvish. Per-shell setup is in Installation.

Exit Codes

CodeMeaning
0Everything that was asked for succeeded.
1The run could not be carried out: bad configuration or arguments that the tool detects itself, rejected credentials, the repository list could not be fetched, another run holds the lock, the disk is full, a failed --verify, --doctor or --decrypt, or a restore that could not start.
2Usage error reported by the argument parser (unknown flag, missing value, conflicting flags).
3The run finished but something could not be backed up: a repository, an issue list, an S3 upload, a mirror push, the manifest. The backup is incomplete. Re-running retries only what failed. --restore also exits 3 when some items could not be restored.
130 / 143Interrupted by SIGINT / SIGTERM.
64Container entrypoint only: refused a malformed UMASK, BACKUP_MODE or BACKUP_FLAGS.

Failures never stop the rest of the run: a repository that cannot be cloned does not prevent its issues or the other repositories from being backed up. Each failure is recorded once and shows up in the log, the summary banner, the --report file (failure_count, failures[]), the metrics (github_backup_failures, github_backup_success), backup_history.json and the webhook ("status": "partial"); they cannot disagree with the exit code. A failure of the notification itself (webhook, report or metrics file that cannot be written) is logged but does not change the exit code.