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 single origin. If you ever need the old vault-specific data (e.g. the former bookmarks.json), it still lives in the retired obsidian-config repo'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 .obsidian files.
  • git status in the vault shows .obsidian as 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 sync copies that URL into the vault's .git/config for 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 true makes git pull / git checkout update 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 update checks out a specific commit, leaving the submodule in detached-HEAD state. Run git checkout main inside .obsidian before 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 .obsidian in 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*.json and .DS_Store in .gitignore so per-machine state never syncs.
Description
A global base Obsidian configuration (.obsidian)
Readme 314 KiB
Languages
CSS 95.7%
JavaScript 4.3%