chore: enable canvas, disable bookmarks, document single-tier config
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
This commit is contained in:
204
README.md
204
README.md
@@ -1,88 +1,182 @@
|
|||||||
# Obsidian config — global + per-vault fork model
|
# Obsidian config — shared global config via git submodule
|
||||||
|
|
||||||
Two-tier Obsidian configuration:
|
A single, shared Obsidian configuration used by **every** vault.
|
||||||
|
|
||||||
- **Global config** — `ssh://git@gitea.bchen.dev:2222/brendan/obsidian-global-config.git` —
|
Each vault's `.obsidian/` directory is a **git submodule** pointing at one repo —
|
||||||
shared settings (plugins, hotkeys, appearance, theme) used by **every** vault.
|
the global config:
|
||||||
- **Per-vault config** (this repo, e.g. `obsidian-config`) — a *fork* of the global repo:
|
|
||||||
the global config **plus** files specific to one vault that must sync with that vault
|
|
||||||
but never be published globally.
|
|
||||||
|
|
||||||
Each vault's `.obsidian` is a git submodule pointing at that vault's per-vault repo, which
|
|
||||||
has the global repo configured as its `upstream` remote.
|
|
||||||
|
|
||||||
```
|
```
|
||||||
vault/.obsidian ──submodule──► obsidian-config (per-vault, downstream)
|
ssh://git@gitea.bchen.dev:2222/brendan/obsidian-global-config.git (remote: origin)
|
||||||
│ remote: upstream
|
|
||||||
▼
|
|
||||||
obsidian-global-config (shared, upstream)
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```
|
||||||
|
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
|
## Tiers
|
||||||
|
|
||||||
| Tier | Examples | Lives in |
|
| Tier | Examples | Tracked? |
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
| **Global** (shared everywhere) | `app.json`, `appearance.json`, `hotkeys.json`, `templates.json`, `daily-notes.json`, `core-plugins.json`, `community-plugins.json`, `types.json`, `themes/**`, plugin code, most plugin `data.json` | global upstream → flows to every vault |
|
| **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 |
|
||||||
| **Vault-specific** (synced, never published) | `bookmarks.json` | per-vault repo only — never pushed upstream |
|
| **Machine-local** (not synced) | `workspace.json`, `workspace-mobile.json`, `workspaces.json`, `.DS_Store` | ❌ gitignored (see `.gitignore`) — stays on the one machine |
|
||||||
| **Machine-local** (not synced) | `workspace.json`, `workspaces.json`, `workspace-mobile.json`, `.DS_Store` | gitignored everywhere |
|
|
||||||
|
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
|
## Daily workflow
|
||||||
|
|
||||||
Run from a vault root (where `.obsidian` is the submodule).
|
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 vault-specific setting** (a bookmark) — stays in this vault:
|
### Change a setting and publish it to all vaults
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
# 1. Make the change (edit in Obsidian, or edit the JSON directly)
|
||||||
git -C .obsidian add -A
|
git -C .obsidian add -A
|
||||||
git -C .obsidian commit -m "..."
|
git -C .obsidian commit -m "Describe the config change"
|
||||||
git -C .obsidian push
|
git -C .obsidian push # publish to the global repo (origin)
|
||||||
git add .obsidian && git commit -m "bump config" && git push # record the pointer
|
|
||||||
|
# 2. Record the new submodule pointer in this vault's repo
|
||||||
|
git add .obsidian && git commit -m "Bump obsidian config" && git push
|
||||||
```
|
```
|
||||||
|
|
||||||
**Pull global changes down** — conflict-free; never touches your vault-specific files:
|
### Pull the latest global config into a vault
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
git -C .obsidian fetch upstream
|
git -C .obsidian pull # fast-forward to the latest global config
|
||||||
git -C .obsidian merge upstream/main
|
# or, equivalently, from the vault root:
|
||||||
git -C .obsidian push # save merged result to this vault's repo
|
git submodule update --remote .obsidian
|
||||||
git add .obsidian && git commit -m "pull global config" && git push
|
|
||||||
|
git add .obsidian && git commit -m "Bump obsidian config" && git push # record the pointer
|
||||||
```
|
```
|
||||||
|
|
||||||
**Change a global setting** — make it in a clone of the **global** repo, push there, then run
|
> Restart Obsidian (or reload the vault) after pulling config so it re-reads the JSON.
|
||||||
the pull-down above in each vault:
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# 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
|
```bash
|
||||||
git -C /path/to/obsidian-global-config add -A
|
# Clone the vault and its submodule in one step:
|
||||||
git -C /path/to/obsidian-global-config commit -m "..."
|
git clone --recurse-submodules <vault-repo-url>
|
||||||
git -C /path/to/obsidian-global-config push
|
|
||||||
|
# Already cloned without --recurse-submodules? Initialize after the fact:
|
||||||
|
git submodule update --init --recursive
|
||||||
```
|
```
|
||||||
|
|
||||||
> Promoting a *global* change you happened to make **inside a vault** isn't a plain push
|
## Adding the config to a brand-new vault
|
||||||
> (your per-vault history has vault-specific commits in the way) — cherry-pick it onto an
|
|
||||||
> `upstream`-tracking branch and push that. Editing global settings in the global clone
|
|
||||||
> avoids this entirely.
|
|
||||||
|
|
||||||
## Which files are vault-specific
|
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.
|
||||||
|
|
||||||
The current list is just `bookmarks.json`. To make a plugin's settings
|
```bash
|
||||||
vault-specific, add `plugins/<plugin>/data.json` to the denylist and remove it from the
|
cd /path/to/new-vault
|
||||||
global repo. The denylist is enforced by a `pre-receive` hook on the global repo, which
|
rm -rf .obsidian # only if Obsidian already created a default one
|
||||||
rejects any push that touches a vault-specific path (so a stray cherry-pick can't publish
|
git submodule add ssh://git@gitea.bchen.dev:2222/brendan/obsidian-global-config.git .obsidian
|
||||||
private data). See the project notes for the hook script.
|
git commit -m "Add shared obsidian config submodule"
|
||||||
|
```
|
||||||
|
|
||||||
## Bootstrapping a new vault
|
On first open the vault starts in **Restricted Mode** — click **Trust author and enable
|
||||||
|
plugins** to load the configured community plugins.
|
||||||
|
|
||||||
- **Only needs the global config** → point the submodule straight at the global repo:
|
## Pulling submodule updates
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
git submodule add ssh://git@gitea.bchen.dev:2222/brendan/obsidian-global-config.git .obsidian
|
# Update this one submodule to the latest commit on its tracked branch:
|
||||||
```
|
git submodule update --remote .obsidian
|
||||||
|
|
||||||
- **Needs its own private tracked config** → create an empty gitea repo for it, seed it from
|
# Update every submodule in the repo:
|
||||||
the global repo, add it as the submodule, and set `upstream` to the global repo. (Ask to
|
git submodule update --remote --merge
|
||||||
have this scripted.)
|
|
||||||
|
|
||||||
> Do this **before opening the vault in Obsidian** — Obsidian auto-creates a default
|
# Plain `git pull` in the vault updates the *pointer* but NOT the submodule contents.
|
||||||
> `.obsidian/` on first open, which blocks the submodule add. Delete it first if present.
|
# Follow it with this to actually check out the recorded commit:
|
||||||
> On first open the vault starts in **Restricted Mode** — click **Trust author and enable
|
git submodule update --init --recursive
|
||||||
> plugins** to load the configured community plugins.
|
```
|
||||||
|
|
||||||
|
> 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.
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
"switcher": true,
|
"switcher": true,
|
||||||
"graph": true,
|
"graph": true,
|
||||||
"backlink": true,
|
"backlink": true,
|
||||||
"canvas": false,
|
"canvas": true,
|
||||||
"outgoing-link": true,
|
"outgoing-link": true,
|
||||||
"tag-pane": true,
|
"tag-pane": true,
|
||||||
"footnotes": false,
|
"footnotes": false,
|
||||||
@@ -16,7 +16,7 @@
|
|||||||
"command-palette": true,
|
"command-palette": true,
|
||||||
"slash-command": false,
|
"slash-command": false,
|
||||||
"editor-status": true,
|
"editor-status": true,
|
||||||
"bookmarks": true,
|
"bookmarks": false,
|
||||||
"markdown-importer": false,
|
"markdown-importer": false,
|
||||||
"zk-prefixer": false,
|
"zk-prefixer": false,
|
||||||
"random-note": false,
|
"random-note": false,
|
||||||
|
|||||||
Reference in New Issue
Block a user