Saiki7769 downloadsA secure, plug-and-play way to sync individual vault folders or sections with GitHub. Private repos supported, multiple folder mappings, bidirectional sync, and conflict resolution.
End-to-end: open Settings, add a mapping, pick the repo, save, sync. (MP4)
![]() |
![]() |
![]() |
![]() |
Obsidian's built-in Sync covers your whole vault. Easy Git is for the case where you want to share only one or two folders with a repo: a notes folder you keep public, course material you collaborate on, a snippets section you want backed up under version control. You pick the folder, you pick the repo, you pick the direction. That's it.
From inside Obsidian (recommended)
Via BRAT (for early-access builds between releases)
Saiki77/Easy-Git.Manual: download main.js, manifest.json, styles.css from the latest release into <your vault>/.obsidian/plugins/easy-git/.
Either works for private repos.
repo scope (or a fine-grained token with Contents: Read and write + Metadata: Read), paste it in settings, hit Test connection.Settings → Easy Git → + Add mapping. Pick the vault folder (or the vault root for whole-vault sync), add one or more destinations (each = repo + branch + path inside the repo), the direction (push only, pull only, or both), and how often to sync (manual, on interval, on startup, or on save). Save.
If you rename or move the mapping's folder inside Obsidian later, Easy Git updates the mapping path automatically and shows a Notice. If the folder is missing entirely (deleted, or moved while Obsidian was closed), the next sync aborts with a clear error instead of interpreting the missing folder as "delete everything on the remote."
After that, sync from the ribbon menu, the command palette (Easy Git: Sync mapping…), or the Sync button next to each mapping.
A single mapping can push the same vault folder to (or pull it from) several places at once. The mapping's direction (push / pull / both) applies to every destination of that mapping.
Mirror to several repos
Vault Remote
───── ──────
Notes/blog ──┬──> public-blog/main/posts/
└──> backup/main/blog-mirror/
Useful for keeping a public-facing copy and a private backup in sync from one source.
Fan out to several folders of one repo (e.g. a static site)
Vault Remote (one repo)
───── ──────
Notes/blog ──> site/main/src/content/blog/
Notes/projects ──> site/main/src/content/projects/
Notes/about ──> site/main/src/about/
The same mechanism works in the other direction. Set the mapping's direction to pull and add multiple destinations to aggregate several remote sources into a single vault folder:
Remote Vault
────── ─────
team-repo/main/notes/ ──┐
shared-team/main/docs/ ──┼──> Notes/aggregated/
upstream/main/handbook/ ──┘
Each destination pulls its own remote into the shared vault folder and tracks its own last-sync state. Each remote's files keep their existing relative paths. If team-repo brings intro.md and upstream also brings intro.md, whichever destination syncs last overwrites the file in your vault. Use distinct remote paths or rename files on the remote side if you need them to coexist.
In the mapping modal, scroll to Destinations and click + Add destination for another row, or Remove on an existing one. Each row needs a repo and a branch; the path inside the repo can be empty (= repo root). Save when done.
Obsidian uses wikilink embeds like ![[Pasted image …png]]. GitHub's Markdown renderer doesn't understand them, so they'd show as literal text. Easy Git rewrites them to standard CommonMark at push time:
| In your vault | What lands on GitHub |
|---|---|
![[image.png]] |
 |
![[image.png|Caption]] |
 |
![[image.png|400]] |
 (width hint dropped) |
![[note#header]] |
unchanged (GitHub can't transclude) |
If a wikilink points to an attachment outside the mapping's vault folder, the file is copied to attachments/<basename> inside the mapping's remote folder and the rewritten link points there. That keeps each remote folder self-contained, you can browse it on GitHub without broken references.
Your vault is never modified. The rewrite only affects the bytes pushed to GitHub. Pulling those notes back into Obsidian renders fine because both wikilink and standard-Markdown forms work in Obsidian.
Toggle off per mapping if you want the raw wikilinks pushed verbatim (the mapping summary will show (raw wikilinks)).
If the same file changed on both sides since the last sync, Easy Git pauses and lets you pick keep local, keep remote, or keep both (renames your local copy with a -conflict-local-<timestamp> suffix so neither side is lost). Cancelling the conflict modal aborts the entire run without touching anything.
Each run produces one atomic commit via GitHub's Git Data API: blob → tree (with base_tree so unrelated files in the repo are preserved) → commit → ref update. The branch's current HEAD is fetched right before the commit is built, and the ref update is non-fast-forward-protected, so if someone else pushes mid-run the sync retries from scratch (up to 3×, 1s/3s/9s backoff) instead of clobbering.
File identity is the git blob SHA-1 (matches git hash-object), so we compare local and remote without round-tripping content.
For a step-by-step walkthrough of one sync run, the three-way classifier, the conflict-resolution choices, the wikilink rewriter, and the OAuth Device Flow, see docs/how-it-works.md.
.obsidian/**, .trash/**, .git/**, node_modules/** (editable in settings)..easygitignoreDrop a .easygitignore file at the root of any mapping's vault folder and its patterns are added on top of the global excludes for that mapping only. Same syntax as the global list: one glob per line, # for comments, blank lines ignored. Useful when you want to exclude *.pdf in one mapping but not another. The .easygitignore file itself is never pushed.
A small indicator sits in Obsidian's bottom-right status bar showing the aggregate sync state across all mappings:
↻ Ready: at least one mapping configured, nothing has synced yet↻ Synced 5m ago: last successful sync (most recent across mappings)↻ Syncing…: a sync is in progress! Easy Git error: at least one mapping has an unresolved errorClick it to jump straight to Easy Git's settings. Hidden when you have no mappings configured.
api.github.com (and github.com/login/... for Device Flow). No third-party servers.npm install
npm run build
main.js is the bundled output. The release workflow at .github/workflows/release.yml builds and uploads main.js + manifest.json + styles.css on tag push.