No description
Find a file
2026-05-03 19:49:32 +07:00
src Revert "feat: run on schedule" 2026-04-30 14:27:12 +07:00
.envrc feat: initial scaffolding 2026-04-30 07:58:13 +07:00
.gitignore feat: initial scaffolding 2026-04-30 07:58:13 +07:00
Cargo.lock Revert "feat: run on schedule" 2026-04-30 14:27:12 +07:00
Cargo.toml Revert "feat: run on schedule" 2026-04-30 14:27:12 +07:00
config.toml chore: add more repos 2026-05-03 19:49:32 +07:00
flake.lock feat: initial scaffolding 2026-04-30 07:58:13 +07:00
flake.nix feat: initial scaffolding 2026-04-30 07:58:13 +07:00
Makefile build: add simple makefile 2026-04-30 13:36:08 +07:00
README.md Revert "feat: run on schedule" 2026-04-30 14:27:12 +07:00

git-mirror

Vendor-agnostic tool to mirror Git repositories across forges.

git-mirror reads a declarative TOML file and mirrors each source repository to one or more targets. Mirroring is one-way from source to target. The tool only manages Git refs. It does not create repositories or manage forge metadata.

Usage

git-mirror --config config.toml [repo-key...]
  • --config is required
  • --cache-dir overrides the managed bare-mirror cache location
  • --concurrency bounds concurrent repo runs and defaults to available CPU parallelism

Configuration

Pass the configuration file with --config config.toml.

[repo.dotfiles]
source = "git@github.com:khuedoan/dotfiles"
targets = [
    "git@tangled.org:khuedoan.com/dotfiles",
    "https://code.khuedoan.com/khuedoan/dotfiles",
]

[repo.nix-setup]
source = "git@github.com:khuedoan/nix-setup"
targets = [
    "git@tangled.org:khuedoan.com/nix-setup",
    "https://code.khuedoan.com/khuedoan/nix-setup",
]
  • The top-level schema is [repo.<key>], repo keys are the canonical identity used for selection and filtering
  • source and targets URLs must be globally unique across the file, a target URL cannot equal any other target or source
  • URL comparison uses exact string matching with no normalization

Mirror semantics

git-mirror mirrors all refs in the sense of git push --mirror, including ref deletions, with one safety exception for the source repository's default branch.

  • The source repository's default branch is inferred from source HEAD
  • Before pushing, the tool fetches the target's default branch when the target already has refs
  • The target default branch must be identical to the source or behind it
  • If the target default branch is ahead or has diverged, that target fails
  • Non-default branches and tags may be overwritten

Runtime behavior

  • Mirroring is one-way only
  • Target repositories must already exist
  • Non-empty targets must expose a default branch through HEAD
  • Authentication is delegated to the user's Git environment
  • Source repositories are cached as persistent managed bare mirrors
  • The cache path is configurable by CLI flag, with an XDG-style default
  • The CLI supports all repos by default or one or more exact repo keys
  • Runs execute concurrently, bounded by a CLI concurrency flag
  • Failures do not stop other scheduled work
  • The process exits non-zero if any repo-target sync fails

Operational assumptions

  • Targets are expected to be read-only for humans and other tools
  • git-mirror does not configure or verify forge permissions
  • Default-branch protection is a preflight safety check, not an atomic push-time guarantee
  • Manual pushes to targets can still violate the read-only assumption
  • Assumes only one git-mirror process runs at a time