2026-05-08 06:33:42 +00:00
2026-05-10 16:18:35 +00:00
2026-05-10 15:23:50 +00:00
2026-05-10 15:23:50 +00:00
2026-05-08 06:29:13 +00:00
2026-05-08 15:32:33 +00:00
2026-05-09 23:44:18 +00:00
2026-05-10 05:46:50 +00:00
2026-05-08 06:29:13 +00:00
2026-05-08 06:29:13 +00:00

refray logo

refray

A tool to keep your repos in sync across all git platforms, while being able to work from everywhere all at once.

Created becasue github is so unusable and unreliable and I want to leave, but I don't want to leave the community behind.

  • ∞-side sync: Sync between any number of hosted/self-hosted git accounts/orgs/groups
  • read-write mirrors: Make changes from any provider, and the changes will sync to the others
  • webhook support: Sync right after push, reduce potential divergence window
  • conflict handling: Rebase or open pull requests when two platforms diverge
  • tracks deletions: Branches/repo deletions sync across platforms (with backup)
  • selective sync: Sync subset of repos by regex white/black list, or by private/public visibility
  • multithreaded: Process multiple repos simultaneously!

Supported platforms: GitHub, GitLab, Gitea, Forgejo

Note

My cat made this codebase, meow

demo

Install

Option 1. Install with Cargo

  1. Install rust cargo if you don't have it: https://rustup.rs
  2. cargo install refray

Option 2. Download binary

Go to the releases page, find the latest release, and download the appropriate binary for your platform.

Option 3. Docker Compose

docker compose run --rm refray config

# Start the webhook receiver as a service
docker compose up -d --build

# If you want to edit config manually:
docker compose run --rm --entrypoint nano refray /data/config/refray/config.toml

Usage

1. Configure

Run the interactive configuration wizard:

refray config
Example Config
jobs = 8

[[sites]]
name = "github"
provider = "github"
base_url = "https://github.com"
token = { value = "github_pat_..." }

[[sites]]
name = "gitea"
provider = "gitea"
base_url = "https://gitea.example.com"
token = { value = "gitea_pat_..." }

[[mirrors]]
name = "personal"
sync_visibility = "all"
repo_whitelist = "^important-"
repo_blacklist = "-archive$"
create_missing = true
visibility = "private"
conflict_resolution = "auto_rebase_pull_request"

[[mirrors.endpoints]]
site = "github"
kind = "user"
namespace = "hykilpikonna"

[[mirrors.endpoints]]
site = "gitea"
kind = "user"
namespace = "azalea"

2. One-time Sync

Run all configured mirror groups:

refray sync
Sync options

Run one group:

refray sync --group personal

Preview commands without writing to Git remotes:

refray sync --dry-run

Skip repository creation even when create_missing = true in the mirror group:

refray sync --no-create

To restrict which repositories sync, set repo_whitelist and/or repo_blacklist on the mirror group in config.

Retry only repositories that failed during the previous non-dry-run sync:

refray sync --retry-failed

Control parallelism for sync, serve, and webhook commands in config. The default is 10 workers:

jobs = 8

3. Service & Webhooks

You can run refray as a service that listens for webhook events and runs full sync periodically. This is the recommended way to run refray.

Note

If you want to use webhooks, you need to expose port 8787 to a public URL that can be accessed by the git provider.
This can be done using e.g. port forwarding, reverse proxy, cloudflare tunnel, or tailscale funnel.

Start the service (to sync on push and also do full sync periodically):

refray serve

Install webhooks on all repos (with the URL in config):

refray webhook install

To uninstall webhooks previously installed by refray:

Warning

If you want to stop using refray, make sure you run this! Otherwise, all of your repos will keep trying to send webhooks to the URL.

refray webhook uninstall

By default, uninstall uses [webhook].url from your config. To remove hooks for a previous URL, pass it explicitly:

refray webhook uninstall https://old.example.com/webhook

To move installed hooks to a new public URL, use webhook update. It removes hooks matching the current configured [webhook].url, installs the new URL, updates [webhook].url in the config, and refreshes local webhook state:

refray webhook update https://new.example.com/webhook

Issues and Pull Requests

Issues and pull requests are not mirrored.

S
Description
No description provided
Readme MIT 5.2 MiB
Languages
Rust 99.9%
Dockerfile 0.1%