git is the industry standard for revision control for 20
years or so while git CLI is equally widely hated. No need to
list git's quirks all over again, we know it is a jungle. Its
labyrinthine UI is such a contrast to its own key abstraction:
the blob, tree and commit model that I can only compare to IP
and HTTP in its power and minimalism. In fact, that brilliant
hourglass waist architecture let git survive decades of
code accretion, use and abuse while staying on top.
Beagle is a 100% git-compatible SCM for modern workflows.
As of now, Beagle employs pack logs for object storage, which
are pretty close to what git does, except append-only and
simplified. To get some performance, there are LSM-ish sorted
indexes, which are totally Databases 101. Metadata is kept in
plain text files: ref logs, worktree states, these are mainly
lists of hashes with annotations. Assuming this very basic
architecture gets the Big-O right, it will take some time to
find its limits of scalability. At which point changes can
always be made, as long as the "waist" interface holds.
There have been attempts to reimplement git in Rust which I
believe are less interesting. There is no need to do so, like
there is no need to reimplement MS Internet Explorer in Rust.
Just take HTTP and HTML and work from there. That codebase is
not the best part of the story. git's repo data formats also
evolved by code accretion with 100% backward compatibility;
such codebases are almost inevitably ugly.
I toyed with cloning and updating various larger git repos,
including the Linux kernel. It worked, and the performance
bottleneck was on the server side. In the long run, there is
no need to work with even larger repos because Beagle can glue
together a bunch of smaller repos to form a larger sharded
(mono)repo through its seamless submodules mechanics.
In part because of that submodule machinery, Beagle prefers
sharded stores that host multiple repos. Ideally, you only have
one store in $HOME/.be/ while all the worktrees in the system
are "flat". Another strong argument for this approach is tens of
agentic worktrees per a repo, being forked and rm-rf'd all the
time. We do not want to copy all the git objects over each and
every time we do it, that makes no sense. Objects are identified
by their hash, they are immutable, one store is enough.
This rebalanced git model now looks subtly different from
the original. As a result, Beagle deals with the following stack
of entities:
git object store of blobs, trees, and
commits, sharded by a repo. Most often, at $HOME/.be/.
The most boring part of it all, nothing happens here.
:du to check the disk usage, per-repo.:todo (TUI) or jab todo to see open tickets;:work lists the active worktrees;git/GitHub repo, a versioned file tree
with its commit history, mostly source code.
:commit #33295788 - read the commit object,:tree #a9617facfbd03debba40a2c4b091fa74d9066064,:blob main.js#33295788 - read a blob,:log - read the commit log, also :log ?branch
or :log #332957, or just click around in TUI.:work list the active worktrees,://ABC-123 switches to a worktree,:get //ABC-123 update from another worktree,:get update the current three from the upstream,:put dir/file.js stage a file,:post "my changes" commit,:work ABC-123 create a worktree,:done ABC-123 merge, rm -rf, close the ticket,:done close the current worktree itself.