by Dan
Replace git submodules with plain nested git repos, ignored via .gitignore and tracked via folder-note frontmatter.
Not Submodules
An Obsidian plugin that replaces git submodules with
plain nested git repos - discovered by scanning your vault's filesystem and
kept out of your vault's own git history by a self-maintaining pre-commit
hook, instead of .gitmodules.
Submodules are brittle, especially on mobile and when using Obsidian with iOS through terminal emulators such as iSH. This plugin avoids them entirely: nested repos are just ordinary git repositories living inside your vault, automatically found and ignored by the vault's own repo - no folder-naming convention, no frontmatter, no manual registration step.
How it works
- Click Refresh in Settings and the plugin walks your vault for nested
.gitentries, classifying each as an original clone, a git worktree, or a real git submodule (read-only, sourced from.gitmodules). - Locations that share the same origin remote (however they're named, wherever they live) are grouped into one entry, so a repo cloned in more than one place - or a clone plus its worktrees - shows up as one thing, not several.
- Install git hook installs a plain POSIX pre-commit hook that
re-scans your vault on every commit and keeps a managed block in
.gitignorein sync automatically - no naming convention, no manual.gitignoreediting, ever. - A repo folder can be renamed, or its remote URL respelled (SSH vs HTTPS), without looking like a deletion - the next Refresh recognises it as the same location.
Features
- Initialise git repo - one-click
git initfor the vault itself, if it isn't a git repository yet. - Install git hook - installs the self-maintaining pre-commit hook; refuses to overwrite a hook it didn't install itself, and offers to reinstall if it ever goes missing (hooks aren't tracked by git, so a fresh clone or checkout won't have one).
- Refresh - rescans the vault's filesystem and rebuilds the list. Manual only - nothing scans automatically on startup.
- Originals & Worktrees, per repo - Clone / Push / Pull / Delete / Remove and a branch dropdown (switching to a remote-only branch fetches it first) for every location; New clones the origin again at a vault path you choose. Delete leaves a location listed as "missing" until you Remove it; a repo with no locations left disappears on the next Refresh.
- Stash / Pop Stash - a dirty working tree greys out the branch dropdown and offers Stash; Pop Stash is only enabled while you're back on the branch the stash came from.
- Worktree repair - detects a worktree whose folder was moved outside
git worktree moveand offers a one-click repair. - Submodules - a read-only section listing every real git submodule
declared in
.gitmodules, including ones not yet initialized on disk. - Migration - existing installs of the plugin's old naming-convention
system are carried forward automatically: an on-update popup (or a
persistent settings banner if you dismiss it) rescans your vault,
installs the hook, and removes the old static
.gitignoreline, all in one step. Nothing you'd already registered is lost.
Installation
This plugin is desktop-only (isDesktopOnly: true), since it shells out
to your local git.
Manual installation: copy main.js, manifest.json, and styles.css
from a release into
<your-vault>/.obsidian/plugins/not-submodules/, then enable it in
Obsidian's Community plugins settings.
Development
npm install
npm run dev # watch build
npm run build # type-check + production build
npm test # unit + integration tests (tsx --test)
License
MIT
For plugin developers
Search results and similarity scores are powered by semantic analysis of your plugin's README. If your plugin isn't appearing for searches you'd expect, try updating your README to clearly describe your plugin's purpose, features, and use cases.