Enable the canvas core plugin and disable bookmarks in core-plugins.json. Rewrite the README to describe the collapsed single-tier global config (the per-vault fork tier and bookmarks.json are retired) and add a comprehensive git submodule how-to. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CsXyUHsjzgFfz2EWPrSQ2U
Obsidian config — shared global config via git submodule
A single, shared Obsidian configuration used by every vault.
Each vault's .obsidian/ directory is a git submodule pointing at one repo —
the global config:
ssh://git@gitea.bchen.dev:2222/brendan/obsidian-global-config.git (remote: origin)
vault-A/.obsidian ─┐
vault-B/.obsidian ─┼──submodule──► obsidian-global-config (one source of truth)
vault-C/.obsidian ─┘
Change a setting once, push it, and pull it down in every other vault. There is no per-vault tier and no vault-specific fork — everything tracked here is shared everywhere. Anything that should not be shared is machine-local and gitignored.
History: this config used to be two-tier (a per-vault fork with the global repo as
upstream). That has been collapsed — the per-vault repo and its remote are gone, and the global repo is now the singleorigin. If you ever need the old vault-specific data (e.g. the formerbookmarks.json), it still lives in the retiredobsidian-configrepo's history.
Tiers
| Tier | Examples | Tracked? |
|---|---|---|
| Shared (everywhere) | app.json, appearance.json, hotkeys.json, templates.json, daily-notes.json, core-plugins.json, community-plugins.json, types.json, themes/**, plugin code, plugin data.json |
✅ tracked in this repo → flows to every vault |
| Machine-local (not synced) | workspace.json, workspace-mobile.json, workspaces.json, .DS_Store |
❌ gitignored (see .gitignore) — stays on the one machine |
If a setting starts diverging per-machine, add it to .gitignore. There is no longer a
per-vault tier — keep everything tracked truly shareable.
Daily workflow
Run these from a vault root (the directory that contains .obsidian as a submodule).
All git -C .obsidian … commands operate inside the submodule.
Change a setting and publish it to all vaults
# 1. Make the change (edit in Obsidian, or edit the JSON directly)
git -C .obsidian add -A
git -C .obsidian commit -m "Describe the config change"
git -C .obsidian push # publish to the global repo (origin)
# 2. Record the new submodule pointer in this vault's repo
git add .obsidian && git commit -m "Bump obsidian config" && git push
Pull the latest global config into a vault
git -C .obsidian pull # fast-forward to the latest global config
# or, equivalently, from the vault root:
git submodule update --remote .obsidian
git add .obsidian && git commit -m "Bump obsidian config" && git push # record the pointer
Restart Obsidian (or reload the vault) after pulling config so it re-reads the JSON.
Working with git submodules — comprehensive how-to
.obsidian being a submodule means the vault repo stores only a pointer (a commit
SHA) to the config repo, not its files. The two repos have independent histories. This
section covers everything you'll need.
Mental model
- The vault repo tracks your notes plus a pointer entry for
.obsidian. - The config repo (
obsidian-global-config) holds the actual.obsidianfiles. git statusin the vault shows.obsidianas a single line:modified: .obsidian (new commits)→ the submodule is checked out at a different commit than the pointer recorded in the vault repo. Fix by committing the pointer (git add .obsidian && git commit) or by resetting the submodule.modified: .obsidian (modified content)→ there are uncommitted edits inside the submodule.
.gitmodules(in the vault root) maps the submodule path → its URL.git submodule synccopies that URL into the vault's.git/configfor local use.
Cloning a vault that uses this submodule
# Clone the vault and its submodule in one step:
git clone --recurse-submodules <vault-repo-url>
# Already cloned without --recurse-submodules? Initialize after the fact:
git submodule update --init --recursive
Adding the config to a brand-new vault
Do this before opening the vault in Obsidian — Obsidian auto-creates a default
.obsidian/ on first open, which blocks submodule add. Delete any auto-created one first.
cd /path/to/new-vault
rm -rf .obsidian # only if Obsidian already created a default one
git submodule add ssh://git@gitea.bchen.dev:2222/brendan/obsidian-global-config.git .obsidian
git commit -m "Add shared obsidian config submodule"
On first open the vault starts in Restricted Mode — click Trust author and enable plugins to load the configured community plugins.
Pulling submodule updates
# Update this one submodule to the latest commit on its tracked branch:
git submodule update --remote .obsidian
# Update every submodule in the repo:
git submodule update --remote --merge
# Plain `git pull` in the vault updates the *pointer* but NOT the submodule contents.
# Follow it with this to actually check out the recorded commit:
git submodule update --init --recursive
Tip:
git config --global submodule.recurse truemakesgit pull/git checkoutupdate submodules automatically.
Making and pushing changes from inside the submodule
cd .obsidian
git checkout main # submodules often land in DETACHED HEAD — see gotchas
# … make changes …
git add -A && git commit -m "…"
git push # to origin (the global config repo)
cd ..
git add .obsidian && git commit -m "Bump obsidian config" # record the new pointer
git push
Changing the submodule's remote URL
# Edit the URL in .gitmodules (vault root), then sync it into .git/config:
git submodule sync .obsidian
# Verify the submodule's own remotes:
git -C .obsidian remote -v
Inspecting submodule state
git submodule status # shows SHA + path for each submodule
git -C .obsidian remote -v # the submodule's remotes
git -C .obsidian branch -vv # branch + upstream tracking
git -C .obsidian log --oneline -5
Removing a submodule (de-init)
git submodule deinit -f .obsidian # unregister + clear working tree
git rm -f .obsidian # remove from index + .gitmodules
rm -rf .git/modules/.obsidian # delete the cached git dir
git commit -m "Remove obsidian config submodule"
Gotchas
- Detached HEAD:
git submodule updatechecks out a specific commit, leaving the submodule in detached-HEAD state. Rungit checkout maininside.obsidianbefore committing, or your commit won't be on a branch. - Pointer vs contents: committing in the submodule is only half the job — you must
also
git add .obsidianin the vault to record the new pointer, or other clones won't get the change. - Two pushes: changes need a push from inside
.obsidian(to the config repo) and a push of the vault repo (to record the pointer). - Restart Obsidian after pulling config changes so it reloads the JSON.
- Don't track machine-local files — keep
workspace*.jsonand.DS_Storein.gitignoreso per-machine state never syncs.