Import josh-sync from subrepo/main
Sync-Origin: import/josh-sync/20260528-041502
This commit is contained in:
56
docs/adr/013-non-destructive-adoption.md
Normal file
56
docs/adr/013-non-destructive-adoption.md
Normal file
@@ -0,0 +1,56 @@
|
||||
# ADR-013: Non-destructive adoption merge for existing subrepos
|
||||
|
||||
**Status:** Accepted
|
||||
**Date:** 2026-04
|
||||
**Update (2026-05):** The standalone `josh-sync adopt <target>` command described below has been folded into `josh-sync onboard <target>` as the `adopt` strategy (selectable via `--mode=adopt`, `targets[].history_lock: preserve`, or auto-detection when the subrepo has any branches). `josh-sync adopt` is retained as a thin CLI alias. The state file moved from `<target>/adopt.json` to `<target>/onboard.json` with a `.strategy` field; the legacy file is still read for backward compatibility. See the guide's Onboarding section.
|
||||
|
||||
## 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.
|
||||
Reference in New Issue
Block a user