2026-02-12 09:20:55 +03:00
# josh-sync
Bidirectional monorepo ↔ subrepo sync via [josh-proxy ](https://josh-project.github.io/josh/ ). Supports multiple sync targets from a single config.
## Quick Start
### 1. Add config
Create `.josh-sync.yml` in your monorepo root:
```yaml
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
2026-02-14 21:28:40 +03:00
exclude: # files excluded from subrepo (optional)
- ".monorepo/"
2026-02-12 09:20:55 +03:00
bot:
name: "josh-sync-bot"
email: "josh-sync-bot@example .com"
trailer: "Josh-Sync-Origin"
```
### 2. Add CI workflows
Copy from [examples/ ](examples/ ) and customize paths/branches:
```yaml
# .gitea/workflows/josh-sync-forward.yml
2026-02-12 11:22:51 +03:00
- uses: https://your-gitea.example.com/org/josh-sync@v1
2026-02-12 09:20:55 +03:00
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:
```nix
{ inputs, ... }: {
imports = [ inputs.josh-sync.devenvModules.default ];
}
```
Run `josh-sync preflight` to validate your setup.
2026-02-12 18:00:08 +03:00
## Documentation
2026-02-14 21:28:40 +03:00
- **[Setup Guide ](docs/guide.md )** — Step-by-step: prerequisites, importing existing subrepos, CI workflows, file exclusion, and troubleshooting
2026-02-12 18:00:08 +03:00
- **[Configuration Reference ](docs/config-reference.md )** — Full `.josh-sync.yml` field documentation
2026-02-14 21:28:40 +03:00
- **[Architecture Decision Records ](docs/adr/ )** — Design rationale and trade-offs
- **[Changelog ](CHANGELOG.md )** — Version history
2026-02-12 18:00:08 +03:00
2026-04-01 00:56:33 +03:00
## Versioning
josh-sync follows [semver ](https://semver.org/ ):
| 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` .
2026-02-12 09:20:55 +03:00
## CLI
```
2026-04-04 01:43:47 +03:00
josh-sync sync [--forward|--reverse] [--force] [--target NAME[,NAME]] [--branch BRANCH]
2026-02-12 09:20:55 +03:00
josh-sync preflight
josh-sync import <target>
josh-sync reset <target>
2026-02-13 18:33:53 +03:00
josh-sync onboard <target> [--restart]
josh-sync migrate-pr <target> [PR#...] [--all]
2026-02-12 09:20:55 +03:00
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.
2026-04-04 01:43:47 +03:00
- **Reverse sync** (subrepo → mono): creates a PR by default. Add `--force` to bypass the PR and push directly to the mono branch (destructive).
2026-02-14 21:28:40 +03:00
- **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.
2026-02-12 09:20:55 +03:00
- **Loop prevention**: `Josh-Sync-Origin:` git trailer filters out bot commits.
- **State tracking**: orphan branch `josh-sync-state` stores JSON per target/branch.
## Dependencies
2026-02-14 21:28:40 +03:00
`bash >=4` , `git` , `curl` , `jq` , `yq` ([mikefarah/yq ](https://github.com/mikefarah/yq ) v4+), `openssh` , `rsync`
> The Nix flake bundles all dependencies automatically.
2026-02-12 09:20:55 +03:00
## License
MIT