Files
josh-sync/README.md
Slim B 8ab07b83ab Update docs, changelog, examples, and add ADRs for v1.2
- Add v1.1.0 and v1.2.0 changelog entries
- Add exclude field to config reference and example config
- Add ADRs documenting all major design decisions
- Fix step numbering in reverse_sync()
- Fix action.yml to copy VERSION file
- Add dist/ and .env to .gitignore
- Use refs/tags/ format for Nix flake tag refs

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-14 21:28:40 +03:00

2.9 KiB

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:

josh:
  proxy_url: "https://josh.example.com"
  monorepo_path: "org/monorepo"

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

CLI

josh-sync sync [--forward|--reverse] [--target NAME[,NAME]] [--branch BRANCH]
josh-sync preflight
josh-sync import <target>
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): always creates a PR, never pushes directly.
  • 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