Skip to main content
A submodule mounts one Diversion repo at a folder path inside another repo, pinned to a specific commit. Use it to share an engine, a library, or an art pack across projects: each project decides which version it uses, and upgrades are an explicit, reviewable change.

Key terms

  • Mount path — the folder in the parent repo where the other repo appears, for example libs/engine.
  • Pin — the commit of the mounted repo that the parent points to. The pin is part of the parent’s history, so everyone who syncs the parent gets the same version.
  • Child workspace — the working copy of the mounted repo that Diversion creates inside the mount path. It is a real workspace: you can check out a branch, edit, and commit in it.

Add a submodule

From anywhere inside the parent workspace:
<repo> is the mounted repo’s name or ID. The files appear at libs/engine, and the pin is committed in the parent, so teammates get the submodule when they sync. Diversion refuses to mount over a folder that already has files, on a symlink, or at a path that differs from an existing mount only by letter case (such paths open the same folder on Windows and macOS).

See what state your submodules are in

  • synced — the local mount is at the pinned commit.
  • missing — the pointer exists but the files were not created locally yet (for example, right after cloning the parent). Run dv submodule update.
  • pin_mismatch — the local mount is at a different commit than the pin, usually after committing inside the mount.
LOCAL CHANGES counts uncommitted changes inside the child workspace. It shows paused when the child workspace’s sync is paused, because a paused workspace cannot report its changes. The parent’s regular dv status also warns when any submodule needs attention:

Get or repair the files

update makes the local mounts match the pins: it clones missing mounts, moves drifted mounts back to the pinned commit, and re-creates a mount folder that was deleted. It never touches a mount that has uncommitted work or is on a branch — your work is safe.

Work inside a submodule and move the pin

The mount is a working clone. To change the mounted repo and point the parent at the result:
repin moves the pin of an existing submodule. Without --ref it pins the child workspace’s current commit — what you just built and tested. To pin a different commit:
Moving a pin never overwrites work: if the mount has uncommitted changes, the repin is refused until you commit or undo them.

Remove a submodule

Removes the pointer and the local files. Like update, it refuses while the mount holds uncommitted work.

Good to know

  • Commands run inside the mount apply to the mounted repo, not the parent. dv status in libs/engine shows the child’s changes.
  • Edits inside the mount never show up as parent changes; the parent repo stays clean.
  • The child workspace is named <folder> submodule @ <your machine> in the workspace list, so it is easy to tell apart from a regular clone.
  • In the web app, the parent’s file tree shows a mount with a tree icon and a tooltip naming the mounted repo and its pinned commit.
  • The pin is part of the parent’s history. Branching, merging, and going back in time in the parent carry the pin with them like any other change.