Skip to content

1.6.0 — two-way sync, automatic pull/push, optional PAT

Choose a tag to compare

@yanqingwang yanqingwang released this 17 Oct 08:04
· 5 commits to main since this release

Two-way sync

Until now the plugin only pushed. It staged, committed, fetched, and then stopped whenever the remote was ahead, with "Pull to update" — and there was no pull code path at all. Divergence had to be resolved by hand in a terminal, or by reaching for Force, which discards remote work.

One sync is now:

stage -> commit -> fetch -> integrate remote -> push

Commit comes before integrating because git rebase refuses to run with unstaged changes, and a merge would otherwise have to resolve the commit we just made. Integrating comes before pushing so your commits land on top of remote history instead of against it.

Divergence is integrated, not refused. Choose merge (default — keeps existing commit hashes, so nothing already on the remote is ever rewritten) or rebase (linear history, only replaying your not-yet-pushed commits). --force-with-lease is now reached only in Force mode, or in Auto mode when the remote is strictly behind.

Automatic push and pull

  • Auto sync every N minutes — default 5, 0 disables. Pull and push on one timer.
  • Auto sync on load — one full sync shortly after Obsidian starts.
  • A re-entrancy guard: a trigger arriving while a sync is running is dropped rather than queued. With two intervals armed this would otherwise race on the same index.

New commands: Pull remote changes only (fetch and integrate, never commits or pushes) and Show sync status (branch, short SHA, ahead/behind, uncommitted count).

Conflicts cannot corrupt notes

Obsidian has no merge UI, and a note nobody opens would keep its <<<<<<< markers indefinitely. So a conflicted sync is rolled back to the state it started from and the conflicting files are listed. Local commits stay, the remote is untouched, your note is byte-for-byte what you wrote.

Turn Auto-abort sync conflicts off to leave the merge in place and resolve it yourself. Either way, an unresolved merge blocks the next sync rather than being committed.

Optional credentials (new)

By default the plugin still uses your machine's own git credentials — gh auth login, Keychain, Git Credential Manager, libsecret, SSH. Nothing to configure, and that path is unchanged.

The gap this closes: git runs without a terminal here, so it cannot show a login prompt. On a machine with no credential helper, sync simply failed with an auth error in the log. Settings → Credentials now lets you select a personal access token:

  • Stored in Obsidian's SecretStorage, not data.json — only the secret's name is kept in settings.
  • Passed to git through a generated askpass helper in the child process's environment. Never written into .git/config, the remote URL, or this repository.
  • Git's credential-helper list is cleared for that command, so your chosen token is the one actually used instead of a cached credential silently winning.
  • Leave it empty for zero change.

Requires Obsidian 1.11.4+ for SecretStorage; older versions say so in the settings row rather than failing to authenticate.

Fixes

  • Log path: it joined Vault#configDir, which is a folder name, not a path. fs resolves relative paths against process.cwd() — the Obsidian install directory, not the vault — so the log was being written somewhere the vault never looks. Now joined onto the vault, with absolute configDir still handled.
  • Settings now implement getSettingDefinitions() from a single spec table shared with display(), so they are searchable on Obsidian 1.13.0+ and the two renderers cannot disagree about what settings exist.
  • Async settings callbacks are wrapped so a rejected save surfaces as a Notice instead of an unhandled rejection that silently reverts.

Installing

Download main.js, manifest.json, and styles.css into <vault>/.obsidian/plugins/vault-force-sync/, then enable the plugin. minAppVersion is unchanged at 0.15.0.

Verified against real repositories rather than mocks — 8 two-device scenarios (push-only, pull-only fast-forward, clean divergence, conflict rollback, rebase, force, blocked merge, re-entrancy), 17 settings/timer checks, and 17 credential checks that drive git credential fill itself. 42/42.