by MercurioSolutions
Commit, pull, push and sync your vault with Git, without ever being asked for credentials. Side panel with the changed files, guided setup, automatic backups and warnings for large files.
Mercurio Git Sync
An Obsidian desktop plugin (Windows, macOS, Linux) that keeps your vault under Git, built on simple-git.
- Commands: Commit, Commit with custom message…, Pull, Push, Sync (commit + pull + push), Abort merge and Initialize repository.
- A Git panel in the right sidebar (ribbon icon on the left): all the commands as buttons and the list of modified files, grouped and sorted.
- A status bar item with the number of modified files, refreshed every 30 seconds and after every operation (plus
↑n/↓nfor commits to push / pull). Click it for a menu with the commands. - Remote URL and commit author can be set from the plugin settings: no terminal needed.
- Optional pull on startup and automatic backup every N minutes.
- Never asks for credentials interactively: it relies on SSH (a key loaded in
ssh-agent) or on your configured credential helper. - Conflicts after a pull stop the operation with a clear notice: no automatic resolution, nothing pushed.
The plugin is desktop-only (isDesktopOnly: true).
Requirements
- Obsidian 1.4.4 or later, desktop.
- Git 2.13 or later (2.28+ recommended).
Installation
- From Obsidian (once the plugin is listed): Settings → Community plugins → Browse, search for Mercurio Git Sync, then Install and Enable.
- Before it is listed, with the BRAT plugin: Add beta plugin →
00TIA/pluginobsidianGit. - Manually: download
main.js,manifest.jsonandstyles.cssfrom the latest release into<vault>/.obsidian/plugins/mercurio-git-sync/, restart Obsidian and enable the plugin in Settings → Community plugins.
To build it from the source code instead:
npm install
npm run build
then copy main.js, manifest.json and styles.css as above.
Getting started
The settings tab starts with the same steps as a checklist that ticks itself as you complete them.
- If the vault is not a Git repository, the plugin shows a notice with an Initialize repository button (also available as a command). It runs
git init(branchmainunless you configuredinit.defaultBranch) and creates:- a
.gitignorefor Obsidian (workspace layout files,.trash/, OS files); - a
.gitattributeswith* text=auto eol=lf: Obsidian writes LF line endings on every OS, so notes keep LF in the repository and in the vault, also on Windows withcore.autocrlf=true.
- a
- In Settings → Mercurio Git Sync → Repository, set the Remote URL (copy the SSH or HTTPS address from GitHub/GitLab/…) and, if Git does not know you yet, the Commit author.
- Run Sync. The first push sets the upstream branch.
Git panel
Select the Git icon in the left ribbon (or run Open Git panel) to open the panel in the right sidebar:
- branch and upstream, number of modified files, commits to push / pull;
- buttons for Sync, Commit, Commit with message…, Pull, Push, Abort merge (only during a merge) and Refresh, or Initialize repository when the vault is not a repository yet;
- the modified files grouped as Conflicts, Modified, New, Renamed, Deleted, sorted by path; select a file to open it (Cmd/Ctrl-click opens it in a new tab).
The panel and the status bar refresh every 30 seconds, after every operation, and 2 seconds after files change in the vault.
Commands
| Command | What it does |
|---|---|
| Commit | Stages every change in the vault and commits it with the message built from the configured format (with a timestamp). |
| Commit with custom message… | Same, but opens a dialog with the generated message, which you can edit. Enter confirms. |
| Pull | git pull --no-rebase from the upstream branch. |
| Push | Pushes the current branch; the first time it sets the upstream (origin, or the only remote). |
| Sync | Commit, then pull, then push. Stops before pushing if the pull produces conflicts. |
| Abort merge | After a conflicting pull, goes back to the state before the pull (git merge --abort), after confirmation. Your commits are kept. |
| Initialize repository | See Getting started. |
Settings
- Git executable – path of the Git executable; empty means automatic detection (see below). Git in use shows which executable was found; Check searches again.
- Repository
- Remote URL – URL of the remote used by pull/push (
origin, or the remote of the current upstream branch). Addsoriginif there is no remote yet. - Commit author – name and email saved in this repository's config only (
git config --local); your global Git configuration is never modified. Leave empty to use the global values, which are shown as hints.
- Remote URL – URL of the remote used by pull/push (
- Commit message – format with the placeholders
{{date}},{{hostname}},{{numFiles}}(defaultvault backup: {{date}}), date format in Moment.js syntax (defaultYYYY-MM-DD HH:mm:ss) and a preview. - Large files – Size limit in megabytes (default 50, 0 turns the check off). See Large files and Git LFS.
- Automation
- Pull on startup – pulls when Obsidian starts. Quiet when there is nothing new; notices for pulled files, conflicts and errors.
- Automatic backup, Interval in minutes (at least 1) and Include pull and push – the backup is a full sync, or a local commit only. It is quiet: it reports only errors and conflicts, once, without repeating the same notice at every run.
Git not in PATH
When Obsidian is started from the macOS Dock (or from a desktop launcher on Linux) it does not get your shell's PATH, so Git installed with Homebrew & co. is "not in PATH". The plugin looks for Git in this order:
- the path set in the settings (if set, it must work: no silent fallback);
- the folders in PATH;
- the common install locations:
- macOS:
/opt/homebrew/bin,/usr/local/bin,/opt/local/bin(MacPorts), Nix, Xcode / Command Line Tools./usr/bin/gitis used only when the developer tools are installed, so the "install Xcode tools" dialog never pops up; - Windows:
Program Files\Git\cmd,Program Files (x86)\Git\cmd,%LOCALAPPDATA%\Programs\Git\cmd, Scoop; - Linux:
/usr/bin,/usr/local/bin,/snap/bin, Nix, Linuxbrew,~/.local/bin;
- macOS:
- on macOS and Linux, the PATH of a login shell (
$SHELL -lc 'command -v git').
Git's folder and the existing common locations are appended to the PATH of the processes started by Git, so git-lfs, gh auth git-credential and similar tools work too.
Credentials: never interactive
The plugin never shows username, password or passphrase prompts, and prevents Git, ssh and credential helpers from doing so:
GIT_TERMINAL_PROMPT=0and-c core.askPass=(empty): Git asks nothing, not even through graphicalSSH_ASKPASSprograms;GCM_INTERACTIVE=neverand-c credential.interactive=false: Git Credential Manager (and Git 2.46+) only use saved credentials;- unless you configured your own SSH command (
core.sshCommand,GIT_SSH,GIT_SSH_COMMAND), ssh runs with-o BatchMode=yes(no passphrase, no host key confirmation); your own command is used as is; - network operations that produce no output for 2 minutes are stopped.
So credentials must already be available:
- SSH: a key loaded in
ssh-agent(on macOSssh-add --apple-use-keychain, on Windows the OpenSSH Authentication Agent service) and the host already inknown_hosts(connect once from a terminal, e.g.ssh -T git@github.com); - HTTPS: a credential helper with saved credentials (Git Credential Manager on Windows/macOS/Linux,
osxkeychain,libsecret, …). Pull once from a terminal to save them.
When authentication fails, a notice explains what to configure, with Git's error message.
Conflicts
Pull always merges (--no-rebase), whatever pull.rebase says. If the merge produces conflicts:
- the operation stops, nothing is pushed and no automatic resolution is attempted;
- a notice lists the conflicted files, with buttons to open them and to Abort merge; the status bar shows
Git: N conflicted; - the
<<<<<<</=======/>>>>>>>markers stay in the files: keep the right content, remove the markers, then run Commit (or Sync) to conclude the merge. The commit is refused while markers remain; - or run Abort merge to go back to the state before the pull (changes made while resolving are lost; your commits are kept and the remote changes will be merged again at the next pull);
- pull, push and the automatic backup stay paused until the merge is concluded or aborted; the automatic backup never concludes a merge by itself.
Note: Git cannot put markers in binary files (images, PDFs); the local version stays unless you replace it before committing.
Large files and Git LFS
Before a commit, the plugin looks for new or modified files of at least the size limit (50 MB by default) that Git LFS does not handle:
- Commit, Commit with custom message… and Sync show the list with their sizes and ask: Commit without them (the files stay in the vault, uncommitted), Commit anyway or Cancel;
- the automatic backup cannot ask, so it commits everything else and leaves those files out, with a notice shown once (not at every run) until the list changes.
Once committed, a file stays in the history for good (removing it means rewriting history), and GitHub rejects files over 100 MB. Files tracked by Git LFS are never reported.
Git LFS itself is not applied automatically by file size: it stores in LFS only the files matching the patterns in .gitattributes. To use it:
git lfs install # once per computer (e.g. after brew install git-lfs)
cd /path/to/vault
git lfs track "*.pdf" "*.mp4" "*.zip" # once per vault: writes .gitattributes
Then commit .gitattributes (Commit / Sync). From then on the plugin handles LFS transparently: matching files are stored as LFS pointers on commit and uploaded on push, also when Obsidian is started from the Dock (the folder of git-lfs is added to the PATH). LFS authentication follows the same non-interactive rules as Git.
Keep in mind:
- files committed before
git lfs trackstay in the normal Git history (moving them needsgit lfs migrate, which rewrites history); - GitHub rejects files larger than 100 MB that are not in LFS, and LFS storage and bandwidth have quotas on most hosts.
Network use and privacy
- The plugin makes no network requests of its own. It runs Git on your computer, and Git contacts only the remotes configured for the vault (for example your GitHub repository), when you pull, push or sync, and when Pull on startup or Automatic backup with pull and push are on.
- No telemetry, no analytics, no third-party services.
- The plugin never reads, asks for or stores credentials: Git uses your SSH keys or your credential helper.
- It reads and writes the files of the vault and the repository's own Git configuration (
git config --local, for the remote URL and the commit author). To find the Git executable it checks the common install locations and, on macOS and Linux, asks your login shell wheregitis. - The plugin page in the community directory lists Direct filesystem access and Shell execution. Both come from working with the Git installed on your computer, which the Obsidian API cannot do:
- the only programs it starts are
git,xcode-select -pon macOS (to check that Apple's developer tools, which provide/usr/bin/git, are installed) and, when Git is not found otherwise, your login shell withcommand -v git; - it uses the file system to look for the Git executable in the common install locations, to check file sizes, conflict markers and an unfinished merge in the repository, and to create
.gitignoreand.gitattributeswhen it initializes a repository.
- the only programs it starts are
Other details
- Git runs with English messages (
LC_ALL=C) so errors are recognised reliably. - The periodic status check uses
GIT_OPTIONAL_LOCKS=0: it never takesindex.lockand does not disturb other Git programs working on the same repository. - Operations are serialised: while one runs, the others are refused with a notice (the automatic backup skips its turn).
- If the vault is a sub-folder of a larger repository, counting, staging and committing are limited to the vault (the repository found is shown in the settings).
- Specific notices for: unknown author (
user.name/user.email), existingindex.lock, repository owned by another user (safe.directory), unreachable remote, push rejected because the remote has new commits, detached HEAD.
Known limitations
- Obsidian installed as a Flatpak cannot see the system Git: use the official AppImage/deb/rpm or a Git available inside the sandbox.
- GPG commit signing: a passphrase prompt, if any, comes from
gpg-agent/pinentry, not from the plugin.
Development
npm install
npm run dev # watch mode
npm run build # typecheck + production build (main.js)
npm run lint # ESLint with eslint-plugin-obsidianmd
npm test # unit and integration tests with real Git
@types/node is listed under dependencies rather than devDependencies: the community directory review type-checks the code without installing devDependencies, and without the Node.js types every use of fs, path or os is reported as unsafe. It contains only type declarations, so nothing from it ends up in main.js. npm run lint also runs the type-aware rules that review reports.
Layout:
src/
main.ts plugin lifecycle, timers
commands.ts command registration
git-controller.ts connects the Git service to Obsidian: locking, notices, status bar, automation
settings.ts settings tab
settings-data.ts settings model and validation
commit-message.ts commit message format
messages.ts user-facing texts
git/
git-service.ts commit / pull / push / sync / init / remote / author / abort merge (no Obsidian dependency)
git-env.ts non-interactive environment for Git and ssh
locate-git.ts Git executable lookup
errors.ts classification of Git errors
ui/ notices, commit and confirmation dialogs, status bar
test/ node:test + tsx
The integration tests create temporary repositories with a local remote and check, among other things: conflicts after a pull (nothing pushed, markers left in the files, merge concluded only by hand or aborted), no credential prompt against an HTTP server answering 401 (even with an SSH_ASKPASS program configured), ssh in BatchMode and core.sshCommand respected, timeouts of network operations, Git lookup with an empty PATH, remote and author settings, Git LFS commit and push, and the production bundle loaded with a fake obsidian module. CI runs them on Linux, macOS and Windows.
Releasing a new version
npm version patch # or minor / major: updates manifest.json, versions.json and creates the tag
git push --follow-tags # the Release workflow builds the plugin and creates a draft release
Without pushing a tag, the same draft can be created from GitHub: Actions → Release Obsidian plugin → Run workflow, with the version written in manifest.json.
Then open the draft on the GitHub Releases page and publish it: Obsidian offers the update to everyone who installed the plugin.
License
0BSD, see LICENSE. Based on obsidian-sample-plugin.
For plugin developers
Search results and similarity scores are powered by semantic analysis of your plugin's README. If your plugin isn't appearing for searches you'd expect, try updating your README to clearly describe your plugin's purpose, features, and use cases.