# 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 ```bash # 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 ```bash 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 ```bash # Clone the vault and its submodule in one step: git clone --recurse-submodules # 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. ```bash 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 ```bash # 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 ```bash 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 ```bash # 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 ```bash 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) ```bash 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.