Skip to content

Syncing and Conflicts

Jonathan D.A. Jewell edited this page Sep 15, 2026 · 1 revision

Syncing and Conflicts

When BerryWiki serves a folder that is a git working tree, it runs with commit-on-save: every save is one commit, sidebar included. --no-commit turns that off and serves the folder without touching git, and a folder that is not a working tree falls back to that with a warning.

The /changes page

/changes offers exactly three git operations, in this order:

  1. fetch — bring the remote's commits down. Changes nothing local.
  2. fast-forward — advance the local branch only if it is strictly behind.
  3. push — send your commits up.

There is deliberately no fourth. BerryWiki never merges and never force-pushes. If the branches have diverged, the fast-forward refuses and you are shown the conflict instead. A tool that silently merged your notes, or that resolved a divergence by discarding one side, would violate the core principle that the wiki stays fully usable — and fully yours — when BerryWiki is not running.

Conflicts are read from the index, not the working tree

When git records a conflict it leaves <<<<<<< markers in the file on disk. BerryWiki does not parse those. It reads the three conflicted stages out of the git index, which is where git keeps the ancestor, our version and their version as separate, intact blobs.

This matters: marker-laced text is ambiguous — a page whose body legitimately contains seven angle brackets would be misread. The index is unambiguous.

The seven kinds

Every conflicted path is classified as exactly one of these:

Kind What it means
Sidebar The generated _Sidebar.md.
Body Both sides changed the page's body text.
Metadata Both sides changed the page, but only inside the metadata block; the body text is identical.
AddedBoth Neither side started from a common ancestor — both created this path.
DeletedByThem You kept the page; the incoming side removed it.
DeletedByUs The incoming side kept the page; you removed it.
Opaque Not a Markdown page — an attachment, say. The content is not read, because it may not be text at all.

Which of them BerryWiki will settle

One: Sidebar. The sidebar is derived from the pages rather than authored, so once the pages are agreed the correct sidebar is whatever regeneration produces. Resolving it by regenerating is not a guess.

Not Metadata, even though it looks mechanical. Two metadata blocks merged field-by-field can express a tree neither author wrote — one person's parent combined with another's position is a structure nobody chose. So a metadata clash is surfaced with both sides shown, and you decide.

Not Body. Prose is not merged for you.

For everything except the sidebar, BerryWiki's job ends at showing you the ancestor, yours and theirs, clearly and per page. You conclude it in git.

Credentials

A push against a private wiki needs a token, read from the environment as BERRYWIKI_GITHUB_TOKEN. There is no flag for it: a flag would put the token in your shell history and in the process list.

Internally BerryWiki hands it to git through a generated askpass helper, which reads it from a variable named BERRYWIKI_TOKEN. If you see that name in a process environment, that is the helper — not something you are meant to set.

Clone this wiki locally