Files
josh-sync/docs/adr/013-non-destructive-adoption.md
2026-05-26 10:38:20 +03:00

2.3 KiB

ADR-013: Non-destructive adoption merge for existing subrepos

Status: Accepted Date: 2026-04

Context

Existing subrepos often already have real history, open PRs, and developer clones. The original import then reset onboarding path establishes Josh-compatible history by force-pushing the Josh-filtered monorepo history onto the subrepo. That is correct for empty replacement repos, but it rewrites the active subrepo branch and invalidates local clones.

We need a path for active subrepos where history must remain available on the same branch and where open PR branches should stay based on the existing history.

Decision

Add josh-sync adopt <target> as a separate workflow from onboard and reset. Adoption imports the subrepo content into the monorepo, waits for the import PR to merge, then creates one merge commit on each configured subrepo branch:

  1. First parent: Josh-filtered monorepo HEAD
  2. Second parent: existing subrepo HEAD
  3. Tree: Josh-filtered monorepo tree

Josh follows first-parent history back to the monorepo, while Git still keeps the old subrepo history reachable through parent 2. The push is a normal fast-forward push from the existing subrepo HEAD to the adoption merge commit. No force-push is used.

Before creating the adoption merge, josh-sync requires the existing subrepo tree to match the Josh-filtered monorepo tree. If the trees differ, adoption aborts and the user must merge the import PR or reconcile the branch contents first.

Adoption state is stored separately at <target>/adopt.json on the josh-sync-state branch.

Consequences

Positive:

  • Existing subrepo history remains on the active branch.
  • Existing clones can fast-forward instead of hard-resetting or re-cloning.
  • Open PR branches remain based on reachable history.
  • Josh-compatible ancestry is established without a destructive rewrite.

Negative:

  • Adoption adds one synthetic merge commit to each adopted subrepo branch.
  • Strict "no subrepo commit at all" adoption is impossible if the existing subrepo branch must become connected to the Josh-filtered history without a rewrite. A commit is needed to join the two histories.
  • Tree equality is strict. If the monorepo import differs from the subrepo content, adoption stops until the user resolves the mismatch.