Files
josh-sync/docs/adr/001-josh-proxy-for-sync.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.6 KiB

ADR-001: Josh-proxy for Bidirectional Sync

Status: Accepted Date: 2026-01

Context

We need bidirectional sync between a monorepo and N external subrepos. Each subrepo corresponds to a subfolder in the monorepo. Developers on both sides should see a clean, complete git history — not synthetic commits or squashed blobs.

Alternatives considered

  1. git subtree: Built into git. git subtree split extracts a subfolder into a standalone repo. However, subtree split rewrites history on every run (O(n) on total commits), creating new SHAs each time. Bidirectional sync requires manual subtree merge with conflict-prone history grafting. No transport-layer filtering — all content must be fetched.

  2. git submodule: Tracks external repos via .gitmodules pointer commits. Does not provide content-level integration — monorepo commits don't contain subrepo files directly. Developers must run git submodule update. Bidirectional sync is not a supported workflow.

  3. Custom diff-and-patch scripts: Compute diffs between monorepo subfolder and subrepo, apply patches in both directions. Fragile with renames, binary files, and merge conflicts. Loses authorship and commit granularity.

  4. josh-proxy: A git proxy that computes filtered views of repositories in real-time. Clients git clone through josh and receive a repo containing only the specified subfolder, with history rewritten to match. Josh maintains a persistent SHA mapping, so the same monorepo commit always produces the same filtered SHA. Bidirectional: pushing back through josh maps filtered commits to monorepo commits.

Decision

Use josh-proxy as the transport layer for all sync operations.

Consequences

Positive:

  • Clean git history in both directions — no synthetic commits
  • Deterministic SHA mapping — same monorepo state always produces same filtered SHA
  • Bidirectional by design — push through josh maps back to monorepo
  • Transport-layer filtering — content exclusion happens at clone/push time, not via generated files
  • Supports any git hosting platform (Gitea, GitHub, GitLab) since it's a proxy

Negative:

  • Requires running a josh-proxy instance (operational overhead)
  • Josh-proxy is a Rust project with a smaller community than git-native tools
  • Proxy must have network access to the monorepo's git server
  • Josh's SHA mapping is opaque — debugging requires understanding josh internals
  • First-parent traversal behavior must be respected in merge commits (see ADR-008)

Risks:

  • Josh-proxy downtime blocks all sync operations
  • Josh-proxy bugs could corrupt history mapping (mitigated by force-with-lease on forward, always-PR on reverse)