If your vault is a git repository, ft git sync is a one-shot
commit + pull + push. The same operation is available from inside the
TUI on a background thread (g s), so you can keep working while it
completes.
ft git sync is unavailable when there's no .git/ anywhere up the
tree from the vault root. The discovery walks up from vault.path,
so the repo doesn't have to be the vault itself — a parent repo
containing the vault works just as well.
ft git sync # commit, pull, push
ft git sync -m "msg override" # override the auto-generated message
ft git sync --dry-run # plan only — no writes, no networkStep by step:
- Upstream pre-check. Look up the current branch's
@{u}. No upstream → error out before touching the tree, so you don't end up with a stray local commit on a branch that doesn't track anything. - Snapshot.
git add -A(modified, deleted, untracked, all in) thengit commit -m "ft sync <iso8601-utc>"if there's anything to stage. Override the auto-generated message with-m..gitignoreis honored — git's normal staging rules apply. - Pull.
git pull --no-rebaseby default,--rebaseif[git].pull_strategy = "rebase"is in your config. - Push.
git push. Authentication uses your existing credential helper / SSH agent / GPG signing —ftinherits the process environment.
If the pull (merge or rebase) hits a conflict, ft leaves the working
tree in its conflicted state — markers in the files, merge or rebase
in progress — and exits 2 with the conflicted file list on stderr.
Resolve manually, then git commit (merge) or git rebase --continue
(rebase), then sync again.
The exit code is deliberately separate from the "no upstream" or
"network failure" case (exit 1) so scripts can distinguish "you
have work to do" from "the operation failed before it really started."
[git]
pull_strategy = "merge" # default; also: rebaseThat's the only knob. Everything else inherits from the user's normal git environment (credential helpers, SSH config, GPG signing, hooks). The two strategies map straight to git:
"merge"→git pull --no-rebase"rebase"→git pull --rebase
g arms the git-leader (you'll see a status-bar hint). s triggers
the sync. The sync runs on a background thread:
- The status bar's right cell shows
⟳ syncwhile in progress. - You can keep navigating, editing tasks, opening notes — the UI doesn't block.
- A toast announces success on the next event tick after the worker finishes.
- Conflicts pop a status-bar message + toast naming the affected
files; resolve from
$EDITOR(or any tool you prefer) and re-run.
Pair ft git sync with cron or a systemd timer for "every N minutes,
push whatever I changed":
*/15 * * * * /usr/bin/env -i HOME=$HOME PATH=$HOME/.cargo/bin:/usr/bin \
FT_VAULT=$HOME/my-vault ft git sync >/dev/null 2>&1--json-errors at the top level is handy if you want structured
failures in the cron job log:
ft --json-errors git syncA pre-launch hook that pulls before the GUI opens:
ft git sync && obsidianft git sync --dry-runprints the upstream, the strategy, and the working-tree summary, then
exits 0 for "would sync cleanly", 2 for "would hit conflicts",
1 for the structural errors (no repo, no upstream). Useful in
pre-commit checks or CI guards.
- Not a replacement for
git.ft git synconly does the three-step round-trip; any non-trivial git operation (rebases, branches, history rewrites, stashes) belongs ingititself. - Not a conflict resolver. When markers appear,
ftsteps aside. - Not multi-vault. The operation runs against whichever vault the current invocation discovered.
- Not networked beyond the pull and push. There's no Git LFS handling
beyond whatever
git lfsfilters you've already wired in.