Repository split
Pattern C in detail
The basic flow is in separating content from the site. This section adds the details that walkthrough omits.
Keep the vault in a private repository
- After
git init, create the private GitHub repository before the first push. .obsidian/is generated when Obsidian opens the vault. Even if it is pushed, putting.obsidian/**incontent.excludekeeps it out of the site build. If you do not want to track it, a middle ground is to gitignore only.obsidian/workspace*.json.- The baseline for private notes is: no
publish: true. Add a second layer by excluding a private folder (for exampleprivate/**) incontent.excludeso those notes are not even loaded. - Leave
publishStrategyat the defaultexplicit.selectiveis the "publish almost everything, hide exceptions" model, which is riskier for a private vault.
Fetching content is separate from triggering a deployment
The default deploy workflow (generated by --github-actions) checks out only the site repository.
Option 1: extra checkout plus repository dispatch (recommended for automatic deployment)
- name: Check out the site
uses: actions/checkout@v4
- name: Check out the notes
uses: actions/checkout@v4
with:
repository: <you>/notes
token: ${{ secrets.RIEBECKITE_CONTENT_READ_TOKEN || github.token }}
path: content
- With
path: content, setcontent.directoryto"content". - This checkout makes files available only after the site workflow starts. Add
repository_dispatch: types: [content-updated]to the site workflow and put a notification workflow in the content repository to start it on itsmainpushes. - Do not set
refwhen article updates should deploy the newest default-branch content. The checkout then reads its current tip; the defaultfetch-depth: 1is enough.
Checking out content and triggering a deployment are separate concerns:
Check out the content repository
≠
Start a build when the content updates
A checkout makes the content readable after the workflow has started. If you also want a push to the content repository to deploy the site automatically, you need a mechanism that starts the site workflow:
Diagram source
flowchart LR
Push["Content repository<br/>push"]
Notify["notify-site"]
Dispatch["repository_dispatch<br/>content-updated"]
Workflow["Site workflow"]
Checkout["Content checkout"]
Build["Build"]
Deploy["Deploy"]
Push --> Notify
Notify --> Dispatch
Dispatch --> Workflow
Workflow --> Checkout
Checkout --> Build
Build --> Deploy
If you do not pin a ref in the additional checkout, you get the latest state of the content repository's default branch, which is convenient when article updates should flow straight into the site:
Content main
↓
push
↓
Site workflow
↓
Latest content at that moment
The default fetch-depth: 1 is enough. If you want to pin the exact content commit a site uses, use a Git submodule instead.
Option 2: Git submodule
cd my-site
git submodule add git@github.com:<you>/notes.git content
contentbecomes a link to the articles repository; aligndirectoryinriebeckite.config.tswithcontent.- Add
submodules: recursivetoactions/checkout@v4in the workflow so CI fetches the dependency. - The referenced commit of a submodule is recorded in the site repository. Updating articles is a two-step operation: update the reference on the site side, commit, and push.
cd content && git pull
cd ..
git add content
git commit -m "update articles"
git submodule update --remote follows the latest remote, but you still need the site-side commit.
Comparing the options
| Aspect | Option 1 (extra checkout) | Option 2 (submodule) |
|---|---|---|
| Article push deploys automatically | Yes, with repository dispatch | No (update the reference) |
| Locality | path: content, directory: "content" |
Fixed at directory: "content" |
| History pinning | Follows the branch tip | Can pin a specific commit |
| Local operations | Often a normal clone | Requires submodule update |
| Best for | Article-first workflows | Pinning article revisions on the site side |
If article updates dominate, Option 1 is the easier fit; if you want the history pinned on the site side, use Option 2.
Authentication for private repositories in CI
github.tokenis scoped to the current repository. It can read another public GitHub repository, but cannot read a different private or internal repository.- For a private/internal vault, register
RIEBECKITE_CONTENT_READ_TOKENin the site repository. Use a fine-grained PAT restricted to the vault with Contents: read, or an equivalent read-only GitHub App installation token. - The content notification needs a separate
SITE_DISPATCH_TOKENstored only in the content repository. Restrict a fine-grained PAT to the site repository with Contents: read and write; classic PATs requirereposcope and GitHub App tokens require Contents: write. - If the submodule was added with an SSH URL (
git@github.com:...), CI needs an SSH key. Switching to an HTTPS URL and passingtoken:is simpler to configure.
The read token and the dispatch token serve different directions:
Diagram source
flowchart LR
Site["Site repository"]
ReadToken["RIEBECKITE_CONTENT_READ_TOKEN<br/>Contents: read"]
Content["Private content repository"]
Site --> ReadToken
ReadToken --> Content
Diagram source
flowchart LR
Content["Content repository"]
Token["SITE_DISPATCH_TOKEN"]
Site["Site repository"]
Content --> Token
Token -->|"repository_dispatch"| Site
RIEBECKITE_CONTENT_READ_TOKEN
→ read private content from the site
SITE_DISPATCH_TOKEN
→ start the site workflow from the content repository
Create a PAT from GitHub Settings → Developer settings → Personal access tokens, then register the value under each repository's Settings → Secrets and variables → Actions.
- name: Check out the notes
uses: actions/checkout@v4
with:
repository: <you>/notes
token: ${{ secrets.RIEBECKITE_CONTENT_READ_TOKEN || github.token }}
path: notes
Keep the local and CI layouts aligned
A relative directory is appRoot-relative, so different layouts locally and in CI resolve differently.
| Environment | Layout | directory |
|---|---|---|
| Local (siblings) | workspace/notes and workspace/my-site |
"../notes" |
| CI (extra checkout) | my-site/notes |
"notes" |
| Submodule | my-site/content |
"content" |
Changing the value (../notes locally, notes in CI) points both at the same vault. If you would rather use one value, either keep the vault under my-site locally or make CI lay it out as ../notes.