sync-bot 4df4044f20 Adopt josh-sync for josh-sync
Sync-Origin: adopt/main/2026-05-28T03:19:12Z
2026-05-28 04:19:12 +01:00
2026-05-28 04:15:02 +01:00
2026-05-28 04:15:02 +01:00
2026-05-28 04:15:02 +01:00
2026-05-28 04:15:02 +01:00
2026-05-28 04:15:02 +01:00
2026-05-28 04:15:02 +01:00
2026-05-28 04:15:02 +01:00
2026-05-28 04:15:02 +01:00
2026-05-28 04:15:02 +01:00
2026-05-28 04:15:02 +01:00
2026-05-28 04:15:02 +01:00
2026-05-28 04:15:02 +01:00
2026-05-28 04:15:02 +01:00

josh-sync

Bidirectional monorepo ↔ subrepo sync via josh-proxy. Supports multiple sync targets from a single config.

Quick Start

1. Add config

Create .josh-sync.yml in your monorepo root:

schema_version: 2

josh:
  proxy_url: "https://josh.example.com"
  monorepo_path: "org/monorepo"
  monorepo_url: "git@gitea.example.com:org/monorepo.git"
  monorepo_auth: "ssh"               # optional, default "https"

targets:
  - name: "billing"
    subfolder: "services/billing"
    subrepo_url: "git@gitea.example.com:ext/billing.git"
    subrepo_auth: "ssh"
    branches:
      main: main
    exclude:                          # files excluded from subrepo (optional)
      - ".monorepo/"

bot:
  name: "josh-sync-bot"
  email: "josh-sync-bot@example.com"
  trailer: "Josh-Sync-Origin"

2. Add CI workflows

Copy from examples/ and customize paths/branches:

# .gitea/workflows/josh-sync-forward.yml
- uses: https://your-gitea.example.com/org/josh-sync@v1
  with:
    direction: forward
  env:
    SYNC_BOT_USER: ${{ secrets.SYNC_BOT_USER }}
    SYNC_BOT_TOKEN: ${{ secrets.SYNC_BOT_TOKEN }}
    SUBREPO_SSH_KEY: ${{ secrets.SUBREPO_SSH_KEY }}

3. Local dev (Nix)

Add josh-sync as a flake input, then:

{ inputs, ... }: {
  imports = [ inputs.josh-sync.devenvModules.default ];
}

Run josh-sync preflight to validate your setup.

Documentation

Versioning

josh-sync follows semver:

Bump Meaning Action required
Patch (1.x.y) Bug fixes only Safe to upgrade
Minor (1.y.0) New optional config fields, new commands, new action inputs Safe to upgrade; new features are opt-in
Major (y.0.0) Removed or renamed config fields, CLI flags, action inputs, env vars, or state format Read the Breaking Changes section in the changelog before upgrading

CI workflows pin to a floating major tag (e.g. @v1). A breaking change bumps the major version and moves the tag — @v1 workflows keep working until you explicitly update to @v2.

CLI

josh-sync sync [--forward|--reverse] [--force] [--target NAME[,NAME]] [--branch BRANCH]
josh-sync preflight
josh-sync import <target>
josh-sync adopt <target> [--restart]
josh-sync reset <target>
josh-sync onboard <target> [--restart]
josh-sync migrate-pr <target> [PR#...] [--all]
josh-sync status
josh-sync state show <target> [branch]
josh-sync state reset <target> [branch]

How It Works

  • Forward sync (mono → subrepo): pushes directly if clean, creates conflict PR if not. Uses --force-with-lease for safety.
  • Reverse sync (subrepo → mono): creates a PR by default. Add --force to bypass the PR and push directly to the mono branch (destructive).
  • Adoption: existing active subrepos can be connected to josh-sync with a normal fast-forward merge commit, preserving old subrepo history and avoiding force-push.
  • File exclusion: exclude patterns are embedded inline in the josh-proxy URL. Excluded files exist only in the monorepo.
  • Filter reconciliation: Changing the exclude list auto-creates a merge commit that connects old and new histories — no force-push needed.
  • Loop prevention: Josh-Sync-Origin: git trailer filters out bot commits.
  • State tracking: orphan branch josh-sync-state stores JSON per target/branch.

Dependencies

bash >=4, git, curl, jq, yq (mikefarah/yq v4+), openssh, rsync

The Nix flake bundles all dependencies automatically.

License

MIT

Description
No description provided
Readme MIT 617 KiB
Languages
Shell 97.6%
Nix 1.5%
Makefile 0.9%