Beagle SCM 的 URI 和 HTTP 动词与 git
摘要
Beagle 是一个兼容 git 的源代码管理系统,它利用 HTTP URI 和动词为合并、变基等复杂的 git 工作流提供更简单、更正交的操作集。
<p><a href="https://lobste.rs/s/ybmrcg/beagle_scm_uris_http_verbs_with_git">评论</a></p>
查看缓存全文
缓存时间: 2026/06/15 02:48
# Beagle: Git、URI 与所有那些棘手的术语
来源:https://replicated.wiki/blog/uris.html
https://replicated.wiki/Human authored
Git 的基本模型是一套极其简单的 blob 树和提交链系统,五分钟就能向任何人解释清楚。但在更高层次的抽象中,这种美妙的简洁性退化成了各种命令和标志的混乱组合,连拥有 20 年 Git 经验的开发者都难以记住。
当与 LLM 进行多任务协作时,这种混乱加倍严重。“我记得我们周二实现了这个功能,但这里怎么没有?它去哪了?”“哪个分支对应那个远程仓库?”等等。
要是我们有某种通用语言来寻址和访问本地与远程资源、文件以及文件中的位置就好了!哦等等,我们有 HTTP 和 URI,它们是最标准的协议了。它们本来就是为此设计的,被众多应用和库所支持。我们能把它应用到 Git 上吗?
当然可以。以 GitHub URI 为例,它们将 Git 空间映射到 HTTP URI 空间。这项工作的有趣之处在于定义一组正交操作(一个基),这样任何 Git 魔法都能被表示为这样一系列步骤,且没有歧义,但同时没有一个步骤可以被其他基本步骤的组合所表示。稍后会在 merge/rebase/cherry-pick 的例子中说明这一点。
## URI
我们都牢记在心的 URI 布局:
1. `scheme:` —— 访问协议/寻址方案,
2. `//authority` —— 通常是网络主机,
3. `/path` —— 远程文件系统中的路径,
4. `?query` —— 其他信息(如参数),
5. `#fragment` —— 文档**内部**的位置。
我们能把它改造后用于版本化存储吗?嗯,如果所有版本信息都放到查询部分,其余部分就很明显了。例如:`http://somehost/dir/file?branch#L101`。事实上,[Beagle](https://github.com/gritzko/beagle) 就是一个完全这样做的、兼容 Git 的版本控制系统。
## HTTP 动词
HTTP 的情况更有趣。最初,HTTP 有一组动词词汇:GET、HEAD、PUT、POST、PATCH、DELETE(参见 [RFC 7231](https://datatracker.ietf.org/doc/html/rfc7231))。虽然现在人们只用 GET 和 POST,但其他动词的存在是有理由的,对吧?
- GET “检索信息”
- HEAD 类似于 GET,但没有响应体
- POST 让服务器“接受实体”
- PUT 请求“存储”实体
- DELETE 顾名思义
- PATCH(参见 [RFC 5789](https://www.rfc-editor.org/info/rfc5789/#section-2))请求“应用更改”
虽然这个词汇表有点模糊,但本质上它源自访问远程文件系统的需求。这自然符合 Git 模型,因为 Git 描述的是一个[内容寻址文件系统](https://git-scm.com/book/en/v2/Git-Internals-Git-Objects)。因此,Beagle **只使用** HTTP 动词。
等等,但它只有 **patch**?那 merge 和 rebase 呢?
## Git 的那些棘手术语
围绕 merge、rebase、squash、cherry-pick 以及所有与 Git 处理混乱编辑历史相关的技术,总是存在大量混淆。每个命令都做了几个通常不相关的事情,而每一件事情又可能由几个命令以微妙不同的方式完成。
Beagle 将这些实践分解为一组正交操作,构建在 Git 那个美妙简单的基础模型之上:
- GET:将数据从仓库移动到工作目录(包括远程仓库)
- HEAD:类似 GET 的预演——fetch 并报告
- POST:将数据从工作目录移动到仓库(提交)
- PUT:仅编辑 reflog(设置分支/标签,暂存)
- DELETE:类似 PUT,但用于删除
- PATCH:将另一个版本的更改应用到工作目录
正如你可能看到的,没有哪个操作可以被另一个操作替代:它们是严格正交的。我们来看看这如何应用于 merge/rebase/squash/cherry-pick 的混乱。
让我们看看所有 Git merge 变体做了什么:
1. 它们应用来自一个分叉提交或分支的更改,
2. 它们重用(rebase)或添加新消息(merge、squash),
3. 它们引用原始提交(merge)或不引用(rebase、squash)。
因此,我们有 8 种组合:提交/分支、重用/重命名、引用/遗忘。实际上,这 8 种中只有部分有相应的 Git 术语。例如,要 squash,我们必须完整应用一个分叉分支,添加一条新的提交消息,并且不引用原始分支。要 rebase,我们逐个应用提交,重用消息,不引用回去。要 merge,我们应用整个分支,添加一条新消息,并引用回去(父提交头)。
在 Beagle CLI 中的表达方式:
```
# 变基一个提交:首先将其应用到工作目录...
be patch ?feature
# 然后用相同的作者/消息提交,不引用父提交
be post #!
# 合并一个分支:应用所有提交...
be patch ?feature!
# 然后用新消息提交(保留父提交引用)
be post '#merge the feature'
# 压缩一个分支:首先应用所有更改...
be patch ?feature!
# 然后用新消息提交,不引用父提交
be post '#add a new feature!'
# 变基整个分支,逐个提交
while be patch ?feature; do
# 检查每个树的状态是否有效,然后提交
make && make test && be post #!;
done
# 挑选一个提交:只应用差异
be patch #391a0d33
# 然后提交(相同作者/消息,不引用父提交)
be post #!
```
这里我们使用感叹号修饰符:
1. `?branch!` 应用整个分支(默认:一个提交),
2. `#message!` 遗忘原始提交(跳过父引用)。
当我们不提供消息时,会重用原始消息。对于变基,我们可能保留消息/作者但丢弃原始引用,所以咒语是:`#!`(重用消息,遗忘父提交)。
这里的分支变基只能通过循环进行,因为我们有多少个提交就做多少次 post。这也确保了所有提交的修订版本都能构建并通过测试(这是 Git 模型中的一个明显缺口)。
总体而言,这个模型更注重形式正确性和无歧义性,其总体思路是大部分时间 URI 将由 LLM 来拼写。
## FAQ
### 那么,PUT 和 POST 有什么不同?
POST 执行提交和/或快进。PUT 重置一个分支或标记一个文件为已提交/删除(仅 reflog 操作)。
### 这与 Git 使用的 URI 相比如何?
Git 只使用 URI 来访问仓库,例如 `git://github.com/gritzko/beagle.git`。这非常有限,所以我们想扩展这个寻址方案,以访问文件、修订版本以及文件中的位置。
### 这与 GitHub URI 相比如何?
GitHub URI 具有典型的 web 应用结构,这使它们在我们的场景中不太方便。
`https://github.com/gritzko/beagle/blob/main/keeper/README.md`
具体来说,beagle URI 将所有版本信息正交化到查询部分,以避免过度使用路径来表示所有东西(项目、用户、分支、路径)。Beagle 的分支是类似文件系统的树状结构,顶层条目是项目主干,因此上面的 GitHub URI 变成了:
`be://replicated.live/keeper/README.md?/beagle`
注意,一个 Beagle 仓库可以托管任意数量的项目,默认传递项目的方式是查询。如果我们想查看一个分支,URI 变为:
`be://replicated.live/keeper/README.md?/beagle/MEM-issues`
相似文章
[开源] 我用 Go 编写了一个完整的 Git MCP 服务器,不是简单地封装 bash。它使用了 tree-sitter,处理真正的底层操作(write-tree),并且 100% 本地运行。
git-courer 是一个用 Go 编写的完整 Git MCP 服务器,它使用 tree-sitter 进行语义代码分析,通过结构化 JSON 进行通信,支持 13 个客户端,并以本地优先的方式运行。
Git history 命令值得更多关注
文章重点介绍了新的 `git history` 命令及其 `fixup`、`reword` 和 `split` 子命令,这些命令提供了原子化且感知分支的提交历史编辑功能,带来了类似 jj 的益处,而无需切换版本控制系统。
git rebase -i 并不可怕
解释 git 中的交互式变基命令,揭示其功能并强调通过中止和 reflog 的安全性。
Emacs 与 Bzr 的坎坷往事
文章回顾了 2008 年 GNU Emacs 开发者决定采用 Bazaar 而非 Git 作为版本控制系统的决策过程,重点强调了性能方面的顾虑,以及 Richard Stallman 坚持使用 GNU 软件包的立场,尽管技术基准测试显示 Git 更具优势。
Git并不好
本文对Git进行了批评,认为它并不像人们通常认为的那样好,并链接到Lobste.rs上的讨论。