Summary
Today the daemon’s background refresh only runs git fetch. artifact-fs status can show behind > 0, but HEAD and the FUSE mount stay on the old commit until the user manually fast-forwards or checks out.
For agent/sandbox workflows (the primary audience in the README), we want a simple way to keep the mounted working tree aligned with origin/<branch>, similar to how gh repo sync updates a destination branch to match a source using fast-forward by default.
Motivation / use case
I use ArtifactFS for fast access to large repos without a full clone. I also use gh repo sync day to day: one command, branch matches upstream when FF is possible.
With ArtifactFS I expected “background refresh” to mean the mount stays current. Instead:
refreshLoop fetches periodically (--refresh, default 30s).
behind / ahead / diverged update in status.
- The visible tree does not advance until HEAD moves (manual
git merge --ff-only, git pull, etc.).
That gap is awkward for:
- Read-mostly agent sandboxes that should always read latest
main.
- Disposable CI/dev containers using the Docker example.
- Anyone who treats
status’s behind= as “updates available” and assumes the mount already reflects them.
Proposed behavior (mirror gh repo sync semantics)
Reference: gh repo sync — sync destination from source; fast-forward unless --force (hard reset).
1. New CLI: artifact-fs sync
# Sync registered repo: fetch + fast-forward local branch to origin/<tracked-branch> when safe
artifact-fs sync --name workers-sdk
# Optional branch override
artifact-fs sync --name workers-sdk --branch main
Default (no --force):
git fetch (same as today).
- If
behind > 0 and ahead == 0 and !diverged → fast-forward refs/heads/<branch> to origin/<branch> (reuse logic similar to PrepareFetchedBranch in gitstore).
- Watcher /
onHEADChanged already re-indexes snapshot and reconciles overlay when HEAD moves — mount updates without new FUSE machinery.
Skip FF (exit 0 with message, or exit 1 — maintainers’ choice) when:
overlay_dirty=true (local overlay writes; avoid surprising data loss).
ahead > 0 (local commits not on remote).
diverged=true.
- FF not possible for any other git reason.
Optional --force (advanced, document loudly):
- Analogous to
gh repo sync --force: hard reset local branch to origin/<branch>.
- Only when explicitly requested; never default for daemon auto-sync.
- Must interact safely with overlay (document risks or refuse when
overlay_dirty unless --force).
2. Optional daemon mode: auto-sync after fetch
Complement one-shot sync with an opt-in policy on the repo (not default-on):
artifact-fs add-repo ... --sync-policy ff-only # or: off | ff-only | force
# or
artifact-fs set-sync --name workers-sdk --policy ff-only
When sync-policy=ff-only, after each successful background fetch in refreshLoop, run the same safe FF rules as artifact-fs sync (no --force in the loop).
Default remains fetch-only (off) so local developers aren’t surprised by the tree moving under their editor.
What exists already (implementation sketch)
| Piece |
Location / notes |
| Periodic fetch |
daemon.refreshLoop |
| Ahead/behind/diverged |
gitstore.ComputeAheadBehind, status |
| Overlay dirty |
RepoRuntimeState.DirtyOverlay |
| Branch update after fetch |
gitstore.PrepareFetchedBranch (async prepare path) |
| Mount refresh on HEAD change |
watcher → onHEADChanged |
This is mostly wiring + policy, not a new subsystem.
Non-goals
- Auto-push / two-way sync (separate feature).
- Merge commits on diverged branches (user runs git manually).
- Default-on auto FF for all mounts without an explicit flag.
- Replacing normal
git pull for interactive dev on dirty overlays.
Docs
- Clarify in README: background fetch ≠ fast-forward; link to
sync / sync-policy.
- Fix minor confusion: architecture text suggests watcher runs on fetch; today fetch alone does not move HEAD.
Acceptance criteria (suggested)
Environment
- ArtifactFS (main / 1.0.0-rc.x), macOS + macFUSE or Linux + fuse3.
- Inspiration:
gh repo sync local workflow (gh repo sync / gh repo sync --branch <name>).
Happy to help with a PR if the approach looks right.
Summary
Today the daemon’s background refresh only runs
git fetch.artifact-fs statuscan showbehind > 0, but HEAD and the FUSE mount stay on the old commit until the user manually fast-forwards or checks out.For agent/sandbox workflows (the primary audience in the README), we want a simple way to keep the mounted working tree aligned with
origin/<branch>, similar to howgh repo syncupdates a destination branch to match a source using fast-forward by default.Motivation / use case
I use ArtifactFS for fast access to large repos without a full clone. I also use
gh repo syncday to day: one command, branch matches upstream when FF is possible.With ArtifactFS I expected “background refresh” to mean the mount stays current. Instead:
refreshLoopfetches periodically (--refresh, default 30s).behind/ahead/divergedupdate instatus.git merge --ff-only,git pull, etc.).That gap is awkward for:
main.status’sbehind=as “updates available” and assumes the mount already reflects them.Proposed behavior (mirror
gh repo syncsemantics)Reference:
gh repo sync— sync destination from source; fast-forward unless--force(hard reset).1. New CLI:
artifact-fs syncDefault (no
--force):git fetch(same as today).behind > 0andahead == 0and!diverged→ fast-forwardrefs/heads/<branch>toorigin/<branch>(reuse logic similar toPrepareFetchedBranchingitstore).onHEADChangedalready re-indexes snapshot and reconciles overlay when HEAD moves — mount updates without new FUSE machinery.Skip FF (exit 0 with message, or exit 1 — maintainers’ choice) when:
overlay_dirty=true(local overlay writes; avoid surprising data loss).ahead > 0(local commits not on remote).diverged=true.Optional
--force(advanced, document loudly):gh repo sync --force: hard reset local branch toorigin/<branch>.overlay_dirtyunless--force).2. Optional daemon mode: auto-sync after fetch
Complement one-shot
syncwith an opt-in policy on the repo (not default-on):When
sync-policy=ff-only, after each successful background fetch inrefreshLoop, run the same safe FF rules asartifact-fs sync(no--forcein the loop).Default remains fetch-only (
off) so local developers aren’t surprised by the tree moving under their editor.What exists already (implementation sketch)
daemon.refreshLoopgitstore.ComputeAheadBehind,statusRepoRuntimeState.DirtyOverlaygitstore.PrepareFetchedBranch(async prepare path)watcher→onHEADChangedThis is mostly wiring + policy, not a new subsystem.
Non-goals
git pullfor interactive dev on dirty overlays.Docs
sync/sync-policy.Acceptance criteria (suggested)
artifact-fs sync --name <repo>fetches and FF when safe; mount tree matches new HEAD.overlay_dirtyorahead > 0ordiverged(unless--forcewhere implemented).sync-policyon daemon refresh with defaultoff.Environment
gh repo synclocal workflow (gh repo sync/gh repo sync --branch <name>).Happy to help with a PR if the approach looks right.