Skip to content

ADR-031: A Git front-end works by riding ADR-001 and ADR-011, not by being supported

Status: accepted

Context

#74 asked what git-tpl's stance is toward Jujutsu. A colocated jj git init workspace works today, with no code written for it: .git is real, and everything git-tpl does — writing refs/tpl/<id>, asking for a git merge — is plain Git (ADR-001) through the one backend module that speaks it (ADR-011). A non-colocated workspace fails, because there is no .git to find.

The question generalises past jj: Sapling, and anything else that can present itself as "a Git repository plus its own front-end," has the same two properties for the same structural reason — free compatibility in the colocated shape, none in the non-colocated one. It is worth deciding once rather than re-litigating per tool.

Decision

git-tpl targets Git. A front-end is never named in src/, never detected beyond the narrow diagnostic purpose of telling a user what to do next (see GitError::JujutsuNotColocated), and never gets a second GitBackend implementation to accommodate it — ADR-011 already declined that door for reasons that have nothing to do with any particular front-end. When a front-end leaves behind a real, discoverable .git, git-tpl works on it, because ADR-001's whole premise is that git-tpl produces ordinary Git state and stops there. When it does not, git-tpl reports plainly that it found no Git repository, with whatever pointer toward the front-end's own colocation mode it can give cheaply — not a workaround, and not a probe for what the front-end actually is.

A front-end's own footguns — jj's MERGE_HEAD blindness turning jj commit mid-merge into data loss, most notably — are documented (docs/concepts/git-model.md) as a thing to know, not a thing git-tpl works around. There is no commit hook, no merge wrapper, and no state git-tpl could hold that would make a foreign tool's own model compatible with Git's without duplicating the work that tool chose not to do.

Consequences

A compatible front-end works, and keeps working, without git-tpl's engagement, because it rides an existing invariant rather than a bespoke integration point built for it by name. The next front-end request — Sapling or whatever comes after — has this ADR as its answer instead of a fresh judgement call.

The cost: a front-end's rough edges around the merge (jj's MERGE_HEAD gap, for one) are the user's to navigate with that front-end's own commands, and a request to smooth them over from git-tpl's side is declined per this ADR, not evaluated case by case.