org-mirror

module
v0.2.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 12, 2026 License: BSD-3-Clause

README

org-mirror

Mirror every repository accessible to your GitHub CLI account in an organization as normal local Git working copies. The tool calls the GitHub API with the same credentials stored by GitHub CLI and uses git to clone and update working copies safely. It never executes gh as a subprocess.

Installation

go install github.com/inovacc/org-mirror/cmd/org-mirror@latest

Before running it, install Git and GitHub CLI, then log in:

gh auth login

Usage

# List actions without cloning or updating anything.
org-mirror sync floci-io --dry-run

# Disable the automatic interactive progress interface.
org-mirror sync floci-io --no-tui

# Mirror into C:\Users\dyamm\Downloads\mirror\orgs\floci-io\<repository>.
org-mirror sync floci-io

# Choose another parent directory.
org-mirror sync floci-io --root D:\\mirrors

# Choose another sync-history database.
org-mirror sync floci-io --database D:\\mirrors\\database.db
Pacing, resume and limits

The sync paces itself between repositories. The delay protects two different things: GitHub's secondary rate limits react to bursts of requests, and local endpoint-protection software reacts to bursts of process creation, which is what a fast mirror run of several hundred repositories looks like.

# Slow down to one repository every two seconds.
org-mirror sync floci-io --delay 2s

# Turn pacing off entirely, accepting both risks.
org-mirror sync floci-io --delay 0

# Process 50 repositories, then stop. Run it again to continue.
org-mirror sync floci-io --limit 50

# Ignore an interrupted run and start over.
org-mirror sync floci-io --no-resume

# Check the remaining API budget before starting.
org-mirror limit floci-io

Every repository is written to the history database the moment it finishes, so a crash, a dropped connection or Ctrl+C loses nothing. Ctrl+C and SIGTERM are caught the same way whether or not --no-tui is set, and even with output redirected, so an interrupt always gets the chance to record the run instead of the OS's default disposition just killing the process. A second Ctrl+C still kills immediately, for a git child that is wedged. Cancelling a run does not exit silently: it still prints a result line for every repository the run already reported before the interruption, followed by a closing line stating how many repositories the history database actually has recorded for the run and that running the same sync again continues from there - that count always comes from the database itself, never from what the interrupted process happened to still be holding in memory, so it is accurate even when the interactive interface has nothing left to show. Silence, or a wrong count, would both look like nothing happened, when in fact everything up to that point was saved. The exit code stays non-zero, so scripts still see the interruption as unsuccessful. One cosmetic difference remains for the interactive interface: because of how it shuts down, the individual per-repository lines above that closing count can be missing right when the interface itself is what gets cancelled, even though the closing count is correct and every one of those repositories is genuinely in the database - --no-tui always shows both. The next sync of the same organization continues the interrupted run and skips what was already done. Repositories that failed are retried rather than skipped.

Each real run writes C:\Users\dyamm\Downloads\mirror\orgs\<organization>\metadata.json by default. It includes the UTC run time and, for each discovered repository, its local path, GitHub properties, default branch, sync outcome, and local/upstream commit hashes when available.

Every run also appends history to C:\Users\dyamm\Downloads\mirror\database.db. The SQLite database contains sync_runs (organization, start/end time, status, and repository count) and repositories (branch, local/upstream commit SHA, open issue count, outcome, path, timestamp, and message). Use --database to change its path.

The mirror never resets, stashes, deletes, or overwrites a working copy. A dirty, ahead, diverged, or detached checkout is left unchanged and recorded as a conflict. Failures in one repository are recorded while the remaining repositories continue. Interactive terminals show the current repository, completed work, and remaining queue in a full-screen interface. Redirected output and --no-tui use plain text instead.

Commands

Command Description
sync <organization> Mirror all repositories accessible to the authenticated gh account
limit [organization] Show the account's GitHub rate-limit budget
version Print version information

Development

# Build
task build

# Run
task run

# Test
task test

# Lint
task lint

License

BSD-3

Directories

Path Synopsis
cmd
org-mirror command
internal
ratelimit
Package ratelimit paces and retries outbound work so a long run trips neither GitHub's rate limits nor local endpoint-protection heuristics.
Package ratelimit paces and retries outbound work so a long run trips neither GitHub's rate limits nor local endpoint-protection heuristics.
tui

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL