Skip to main content

Mirrors

Two folders with the same splice id are one splice in two places, so they're meant to be mirrors: the same files, synced with the same upstream. Folders with different ids are independent, even of one upstream, e.g. a library at two versions (splice identity). A mirror whose files differ from the others' has drifted.

git-splice doesn't act on that yet: each splice is pulled and pushed on its own, and compared only with its own upstream. This page says what mirrors would need, what of it is possible, and what can be done meanwhile.

Where mirrors come fromโ€‹

  • A copy in the monorepo, e.g. cp -r vendor/a vendor/a-copy.
  • One nested splice, reached twice. If B's upstream splices in A, which has L nested, then a monorepo that splices in both A and B has a/l/ and b/a/l/, with the same id: A's clone of L. The monorepo copied nothing.

Not from separate clones: if A, B and M each clone C, the three copies have three ids, and are independent (diamond). To declare them mirrors, a clone would need to take over the id of an existing splice. There's no command for that yet.

Because of nesting, mirrors can't be forbidden or forced to stay alike: b/a/l/ belongs to B's upstream, and may lag behind a/l/ because B has an older version of A. The monorepo can't change that alone. Refusing duplicate ids would refuse diamonds of that shape.

Nor can the rebuild tell mirrors apart. A splice's history starts where a .splice with another id appears at its path, so when two mirrors swap paths, each path keeps its own history: a push sends the commits made at that path before the swap, though the folder has the other mirror's files now, and may not have what those commits added (example).

What would be desired, and what's possibleโ€‹

DesiredStatus
Mirrors are stored onceAlready so. Git stores identical files as one object, and identical folders as one tree (diamond).
A report of mirrors that drifted, with how to resolve itPossible, not implemented: compare the folders of splices with the same id, without .splice.
A fork or a new version made from a copy is pointed outPossible in part, not implemented: a copy that names another upstream than its mirrors. A new URL also keeps the id when the upstream moved, so it's a warning, not an error.
A pull of one mirror pulls the othersPossible for copies in the monorepo, not implemented. Not for a nested copy that another upstream owns.
Mirrors never differImpossible. Nested copies can differ for reasons the monorepo can't change.
Mirrors share one folder: an edit in one is an edit in allImpossible with Git. A symlink commits a link, not files: A's own repository would get a link that points outside of it, and a checkout without symlink support gets a text file with the link's target. And a link is a reference: the copies could never differ, not even while you work. Mirrors are values, which are alike at sync points.
Mirrors take disk space onceImpossible in Git's checkout, which writes every file. A file system with copy-on-write, e.g. btrfs, XFS or APFS, can share the blocks of identical files that stay separate files.

Meanwhile: disciplineโ€‹

What git-splice can't do yet, a team can do by hand. A report wouldn't take that over, only point at it: it names the mirrors that differ and how to resolve the difference. For a mirror that's only behind, that's a plain pull, which anyone can check. Where both changed, the pull merges, and the difference left is for someone to resolve. That fits the design's principles: refuse rather than guess, and make the state explicit (design).

  1. Edit one copy, e.g. the top-level s/ in the diamond.

  2. Push it, and pull every mirror right away, as the diamond's round trip does.

  3. Compare mirrors before merging, e.g. in CI. Their folders, without .splice, have the same tree:

    git diff --quiet HEAD:vendor/a HEAD:vendor/a-copy -- ':!.splice'

    (splice identity shows it with real output.)

  4. Clone, don't copy, a fork or a version of its own, so it gets an id of its own (splice identity).