Rift:比 Git Worktrees 更好的替代方案
Rift: Better Alternative to Git Worktrees

原始链接: https://github.com/anomalyco/rift

**Rift** 是 Git worktrees 的高性能替代方案,它利用文件系统原生的“写时复制”(CoW)功能来创建近乎即时的开发工作区快照。通过在 Linux 上使用 Btrfs 子卷,以及在 macOS 上使用 APFS 的 `clonefile`,Rift 消除了复制大型项目文件夹所带来的存储开销。 **核心功能:** * **高性能:** 即使是数 GB 大小的目录,也能在 0.1 秒内创建工作区。 * **工作流:** 使用 `rift init` 注册源根目录,使用 `rift create` 快速启动轻量级的可写克隆。 * **管理:** 包含用于追踪父子关系、垃圾回收(`rift gc`)以进行清理的工具,以及用于无缝目录导航的 Shell 集成。 * **灵活性:** 提供快速的命令行工具(CLI),或作为 Node.js (v21+) 和 Bun 的 FFI 库,支持以编程方式管理工作区。 * **状态:** 目前在 Linux (Btrfs) 和 macOS (APFS) 上均已稳定运行,计划支持 Windows。 Rift 有效平衡了本地开发的响应速度与现代文件系统技术的效率,是在管理多个并行功能分支时,避免传统 Git worktrees 磁盘空间消耗的理想工具。

抱歉。
相关文章

原文

rift: better alternative to git worktrees

  • copy on write (saves space)
  • instant (< 0.1s on 10gb folder)
  • fast cli
  • use as FFI lib with bun or node

mac and linux+btrfs for now more support soon

npm install -g rift-snapshot
# or
bun add -g rift-snapshot

Release archives are available from GitHub Releases.

Platform Backend Behavior
Linux x64 Writable btrfs snapshots rift init converts an ordinary directory into a btrfs subvolume.
macOS arm64 / x64 APFS clonefile rift init registers the source directory.
Windows x64 None The package is published; workspace creation is not implemented.

rift init selects an existing Rift root above the current directory, or the nearest Git root when no Rift root exists. Use --here to initialize exactly the selected directory.

On Linux, first initialization of an ordinary btrfs directory performs a reflink import into a new btrfs subvolume and swaps it into the same path. If the selected root is registered already, no conversion occurs. If its .rift marker is missing, rift init restores it and completes any required conversion.

rift create
rift create --name parser-fix
rift create --into /fast/rifts

rift create searches upward for .rift, copies that managed workspace, records the immediate parent, and prints the new workspace path to stdout.

On Linux, it creates a writable btrfs snapshot. On macOS, it uses APFS clonefile.

When the workspace is a Git repository, the new workspace has detached HEAD and retains index and working-tree state.

list prints direct active child workspaces. ancestors prints parent workspaces, nearest first.

Remove And Garbage Collection

rift remove                         # trash the current created rift subtree
rift remove -f ~/code/app           # unregister a source root
rift remove --children ~/code/app   # trash descendants, preserve the selected workspace
rift gc                             # physically delete trash and prune missing entries

Removing a created rift moves its active subtree into adjacent .trash storage. rift gc deletes that storage later.

Removing a source root requires -f in the CLI. The source directory remains on disk. Its .rift marker is removed. Existing registered descendants are moved into trash. Missing descendants are removed from the registry.

eval "$(rift shell-init zsh)" # or bash

The shell wrapper changes directory after init conversion, create, or removal of the current created rift.

Each managed workspace has a .rift marker containing its identifier. An SQLite registry stores paths, parent identifiers, and trash entries.

Default created-workspace storage is adjacent to the registered source root:

~/code/app/                         source workspace
~/code/.rifts/app/parser-fix/       created workspace
~/code/.rifts/app/.trash/            removed workspace storage

The package selects a Bun or Node FFI binding through conditional exports.

import { create, list, remove, gc } from "rift-snapshot";

const workspace = create({ from: process.cwd(), name: "schema-work" });
console.log(list({ of: process.cwd() }));
remove({ at: workspace });
gc();

The Node binding requires the experimental FFI API in Node.js 26.1 or later:

node --experimental-ffi app.mjs

With Node's permission model, also pass --allow-ffi.

init(options?: { at?: string; database?: string }): null
create(options?: { from?: string; name?: string; into?: string; database?: string }): string
remove(options?: { at?: string; all?: false; database?: string }): void
remove(options: { at?: string; all: true; database?: string }): string[]
list(options?: { of?: string; database?: string }): string[]
ancestors(options?: { of?: string; database?: string }): string[]
gc(options?: { database?: string }): string[]

The JavaScript init function initializes exactly at; Git-root selection and --here are CLI behavior.

Operation failures throw RiftError with a code and, when relevant, path.

cargo test --workspace --locked
./scripts/install.sh

scripts/install.sh installs an optimized CLI binary to ${CARGO_HOME:-$HOME/.cargo}/bin/rift.

MIT

联系我们 contact @ memedata.com