Skip to content

Define branch file view cascade for cheap COW branches #6

@adamziel

Description

@adamziel

Context

ForkPress needs cheap copy-on-write branches, but users should still be able to point normal software at branch files: editors, build tools, WP-CLI, PHP, backup tools, scanners, and diff tools should see ordinary paths whenever possible.

There are three broad ways to expose branch files:

  1. Materialize files with COW support: every branch has a real directory tree, but unchanged file contents share storage through reflinks/file clones.
  2. Expose a native mount or mount-like view: branch paths look like normal files, while ForkPress lazily resolves reads and captures writes.
  3. Do not expose local paths directly: expose files through an API/protocol such as SFTP/WebDAV. This can be portable and cheap, but normal local software may need extra mounting/client support.

A plain full copy should be the last chance fallback. Before copying every file, ForkPress should try every credible COW or mount-like option that preserves normal local file access.

Proposed Cascade

At forkpress init, detect actual host capabilities instead of assuming by OS. Use a temp source file and temp clone/copy target, write to the target, verify the source is unchanged, and record the selected branch file view strategy.

Suggested order:

  1. Reflink/materialized COW in the current location

    • Use APFS clonefile on macOS.
    • Use Btrfs/XFS reflink on Linux where available.
    • Use ReFS block clone on Windows Dev Drive/ReFS where available.
    • Branches are materialized as real directories, but unchanged file contents share storage blocks.
    • This is the best compatibility/performance tradeoff when supported.
  2. Automatically or interactively move to COW-capable storage

    • If the current location has no reflinks, try to create or guide the user to a COW-capable location before falling back.
    • macOS: offer an APFS sparse disk image/sparsebundle for sites stored on non-APFS disks. This should be rootless and can still expose normal files through the mounted APFS volume.
    • Windows: offer a guided ReFS Dev Drive flow on Windows 11 24H2+, including clear messaging that setup may need local admin/elevation.
    • Linux: suggest or detect a Btrfs/XFS-backed path. A loopback Btrfs image usually needs mount privileges, so do not promise it as a rootless default unless proven on that distro.
    • This keeps normal paths and avoids ForkPress-specific filesystem hooks.
  3. Native lazy mount/mount-like adapters

    • Try platform-native lazy filesystem mechanisms before full copying.
    • macOS: FSKit is the long-term native user-space filesystem direction; File Provider may work for sync-root-shaped workflows; macFUSE/FUSE-T may be useful with their packaging/security caveats.
    • Windows: ProjFS is close to the desired lazy projected tree model, but it is an optional Windows component; Cloud Files API is useful but sync-root-shaped; WinFsp/Dokany require drivers.
    • Linux: FUSE/fuse-overlayfs are practical when /dev/fuse and user permissions are available; rootless overlayfs/user namespace paths should be probed rather than assumed.
    • These can make branches lazy while still providing normal-looking paths, but each adapter needs platform-specific packaging, tests, and user messaging.
  4. Built-in local network mount tricks

    • If native filesystem adapters are unavailable, try protocol-backed local mounts that the OS already understands.
    • ForkPress could run an embedded localhost file server and ask the OS to mount/map it as a local volume/share.
    • WebDAV is attractive because macOS and Windows have built-in clients, and many Linux desktops can access it through GVfs/GIO or davfs2 where installed.
    • SMB would give broad OS support, but implementing a correct pure-Rust SMB server is larger and riskier.
    • SFTP is good as a protocol, but transparent local mounting usually requires sshfs or platform-specific client support.
    • This tier may not be as seamless as a real local filesystem, but it is still preferable to a full copy when it gives tools a usable path.
  5. Protocol/API access without a mounted path

    • Provide SFTP/WebDAV/API access for debugging, remote integrations, hosted environments, or users who explicitly choose not to mount anything.
    • This should not be the primary local developer UX because many tools expect POSIX/Win32 paths.
  6. Full materialization last-resort fallback

    • Copy the branch tree normally only after the COW, storage relocation, native mount, local network mount, and protocol options are unavailable, rejected, or too fragile for the current environment.
    • This is not cheap COW, but it is universally compatible and still useful as a safety net.
    • The CLI must be explicit: strategy=file-copy, expected disk usage, why better options were not selected, and how to migrate later.

Important Constraint

If the host filesystem has no reflinks and ForkPress cannot mount/intercept writes, we cannot have all three at once:

  • cheap COW storage,
  • ordinary writable local paths,
  • zero extra OS setup.

One of those must give: use/create a COW-capable volume, enable/install a mount layer, mount a local protocol server, expose files through an API, or finally copy more data. The product should make that tradeoff explicit and choose the least surprising option.

Database Implications

The file view strategy only solves branch files. Database branching needs its own matching cascade:

  • branch-local SQLite files can use the same reflink/materialized approach when SQLite is acceptable;
  • Dolt/MySQL-compatible backends can expose branch databases via branch-aware connection strings;
  • future backends should implement a common strategy interface so file and database branch behavior is selected together and stored in .forkpress site config.

Implementation Notes

  • Add a capability probe command, e.g. forkpress doctor storage.
  • Record detected support and chosen strategy in site config.
  • Make forkpress init explain the selected mode, why higher-priority options were unavailable, and what guarantees the selected mode provides.
  • Add tests that prove writing a branch file does not mutate the canonical file.
  • Add docs showing the cascade and the tradeoff matrix.
  • Treat plain full-copy materialization as an explicit last resort, not the normal fallback.

References

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions