---
title: Tracking Obsidian Vault Changes with Local-Only Git
description: Version history for your vault without pushing to GitHub. Git stays local, iCloud handles backup. Daily auto-commits, tight .gitignore, and iCloud coexistence.
publishDate: 2026-03-12
canonical: https://www.mandalivia.com/obsidian/tracking-obsidian-vault-changes-with-local-only-git/
---

## The Problem

I use iCloud to sync my Obsidian vault. I trust Apple with my personal data — it's where everything already lives — and I didn't want to add Obsidian Sync or GitHub as another vendor with access to my notes. But iCloud gives you sync and backup, not *history*. If I rewrite a paragraph, the old version is gone. If I delete a file by accident, iCloud might propagate that deletion before I notice.

I wanted diffs. Not backup — I already have that — but the ability to see what changed, when, and roll back if needed.

## The Solution

Run Git locally inside the vault. No remote repository, no pushing to GitHub. Just `git init`, a tight `.gitignore`, and a daily auto-commit. iCloud backs up the `.git` folder along with everything else, so the history is replicated without involving another service.

## How To

### Initialize the Repo

```bash
cd "/path/to/your/vault"
git init
```

That's it. No `git remote add`, no SSH keys, no GitHub repo to create.

### The .gitignore

A vault has markdown files you want to track, but also binary files, plugin code, and volatile state files that would bloat the repo or create noise.

Here's what I use:

```gitignore
# Binary files — images, media, documents
*.png
*.jpg
*.jpeg
*.gif
*.webp
*.svg
*.mp4
*.mp3
*.pdf
*.epub
*.zip
*.tar.gz

# Obsidian internals — volatile state, not config
.obsidian/workspace.json
.obsidian/workspace-mobile.json
.obsidian/graph.json
.obsidian/vault_vectors.db
.obsidian/plugins/
.obsidian/themes/
.obsidian/icons/
.obsidian/.DS_Store

# Claude Code sessions (large, ephemeral)
.claude/sessions/

# System
.DS_Store
.trash/
```

This tracks all `.md` files, `.canvas` files, Obsidian config (appearance, hotkeys, plugin list, bookmarks, CSS snippets), Claude Code skills, hooks, and settings, plus `CLAUDE.md`. It skips images and PDFs (35 MB of attachments I don't need diffs for), downloaded plugins (59 MB of third-party JavaScript, re-downloadable from `community-plugins.json`), themes (same logic), Omnisearch's 52 MB vector database, and the workspace files Obsidian rewrites every time you switch tabs. My vault is about 2 GB total — the initial Git repo came out to 101 MB, just the text content of ~6,200 markdown files.

### Why Track .claude/ and .obsidian/?

My vault increasingly has code in it — Claude Code skills (markdown files with embedded instructions), shell scripts in hook folders, and JSON configuration for MCP servers. These are things I wrote, things that break if I change them carelessly, and things I'd want to recover if something went wrong. The whole reason I reached for Git was that my vault stopped being purely notes and started having artifacts worth versioning.

I *don't* track `.obsidian/plugins/` or `.obsidian/themes/` because those are downloaded code, not mine. The `community-plugins.json` file — which *is* tracked — records which plugins I have installed, so I can always reinstall them.

### Daily Auto-Commit

I already had a [nightly script](nightly-toggl-summary-obsidian-daily-note) that runs via launchd at 5:15 AM, pulling yesterday's [completed Things tasks](sync-things-tasks-to-daily-notes) and Toggl time entries into my daily note. I added a Git commit step at the end of that same script — no new scheduled job, no new plist to manage.

The commit function stages everything, checks if there are actual changes, and commits with a timestamped message:

```
Daily vault snapshot: 2026-03-11 05:15 — closing out the day
```

If nothing changed, it skips. If `.git` doesn't exist (say, on a fresh vault clone), it skips gracefully. The commit runs whether or not the catchup portion found tasks to insert — it's a separate concern bolted onto the same daily trigger.

### Keeping the Repo Small

Without a remote, rewriting history is painless — there's nobody else pulling from this repo. A couple of maintenance options:

- **Quarterly prune:** Run `git filter-repo --strip-blobs-bigger-than 1M` to remove anything large that crept past the `.gitignore`. Follow up with `git gc --prune=now --aggressive`.
- **Nuclear option:** If the repo gets unwieldy, `rm -rf .git && git init && git add -A && git commit -m "fresh start"`. You lose history but keep all files. For a notes vault, recent history matters most anyway.

## Caveats

### Git Inside iCloud: The Known Risk

iCloud doesn't understand `.git/` as a database. It syncs individual files within `.git/objects/` independently, which can leave the repo in an inconsistent state. The [documented horror stories](https://architchandra.com/articles/a-side-effect-of-storing-a-git-repository-in-icloud-drive) mostly involve multi-device setups where two machines write to `.git/` simultaneously — iCloud creates conflict copies like `HEAD 2` inside `.git/refs/`, and Git doesn't know what to do with them.

My situation sidesteps the worst of this: I edit on one machine. Mobile access is read-mostly. There's never a second writer racing against the Git database.

The safer alternative is to [move .git outside iCloud](https://forum.obsidian.md/t/obsidian-git-users-how-to-put-the-git-folder-outside-of-my-vault-to-avoid-sync-issues-with-icloud/101968) using a gitdir pointer — create a `.git` *file* (not folder) in the vault that says `gitdir: /some/path/outside/icloud`. But that means managing and backing up a separate directory, which defeats part of the simplicity.

I chose to keep `.git` inside iCloud and accept the small risk. If corruption happens, `git fsck` will tell me, and the fix is just reinitializing. The history is nice to have, not mission-critical — this isn't a code repo where losing commits means losing deployable work. It's notes. The notes themselves are always intact thanks to iCloud. Git just adds a layer of "what changed when."

### Not a Substitute for Backups

Git gives you history, not redundancy. I still do periodic vault backups — a script that copies the whole vault (including binaries Git doesn't track) and zips it. The Git repo and the zip backup serve different purposes.

## Related

- [sync-things-tasks-to-daily-notes](/obsidian/syncing-completed-things-3-tasks-into-obsidian-daily-notes/)
- [nightly-toggl-summary-obsidian-daily-note](/obsidian/nightly-toggl-summary-in-your-obsidian-daily-note/)
- [auto-log-accomplishments-claude-code](/obsidian/auto-logging-accomplishments-from-claude-code-sessions/)