存储无关的中间层,让 git 对象存到任意云存储。Rust 实现,CLI + API 双入口。
支持 Cloudflare R2、腾讯 COS、百度网盘 PCS API。
gix (gitoxide) 的存储层与本地文件系统深度耦合,而我们的核心目标是存储无关。git 对象格式本身极其简单 — <type> <size>\0<data> + zlib 压缩 + SHA-1 命名 — 自己实现更灵活,也避免了 60+ 个 gix 子 crate 的依赖负担。
object_store?Apache Arrow 的 object_store 提供成熟的 ObjectStore trait,内置 S3 兼容后端。R2 和 COS 都是 S3 兼容的 — 换个 endpoint 就行,零额外开发。百度网盘需要自定义实现 PCS API 适配器。
git 的二进制 index 格式复杂(含扩展字段、设备号、inode 等)。MVP 阶段用 JSON 存储 staging area,方便调试和手动检查。后续可以无缝切换为二进制格式。
| 后端 | 实现方式 | URL 格式 |
|---|---|---|
| R2 | object_store::AmazonS3 + R2 endpoint |
r2://account:key:secret@bucket/prefix |
| COS | object_store::AmazonS3 + COS endpoint |
cos://region:secret_id:key@bucket/prefix |
| 百度网盘 | reqwest + PCS REST API + OAuth2 |
baidu://access_token@app_path |
所有后端实现同一个 ObjectStorage trait — 对象读写、引用管理、文件操作。上层代码完全不感知底层存储差异:
// 核心抽象 — 所有存储后端实现此 trait
pub trait ObjectStorage: Send + Sync + 'static {
async fn write_object(&self, kind, data) -> Result<ObjectId>;
async fn read_object(&self, id) -> Result<(ObjectKind, Vec<u8>)>;
async fn has_object(&self, id) -> Result<bool>;
async fn write_ref(&self, name, target) -> Result<()>;
async fn read_ref(&self, name) -> Result<Option<ObjectId>>;
async fn list_refs(&self, prefix) -> Result<Vec<(String, ObjectId)>>;
async fn write_file / read_file / delete_file ...
}$ sg --help
Simple Git - A personal git system with cloud storage
Usage: sg <COMMAND>
Commands:
init Initialize a new repository
add Add file contents to the index
commit Record changes to the repository
status Show the working tree status
log Show commit logs
branch List, create, or delete branches
checkout Switch branches or restore working tree files
clone Clone a repository from remote storage
push Push local objects and refs to remote storage
pull Pull objects and refs from remote storage
serve Start the HTTP API server# 初始化 → 提交 → 分支
$ sg init
Initialized empty sg repository in /tmp/sg-test/.sg
$ echo "hello world" > hello.txt
$ sg add hello.txt
$ sg commit -m "initial commit" --author hqking --email test@test.com
[main] 4323781
initial commit
$ sg status
On branch main
nothing to commit, working tree clean
$ sg log
commit 4323781083dfa82fbbeb0864f761537ea6cf61b0
Author: hqking <test@test.com>
Date: Fri May 15 17:48:17 2026 +0000
initial commit
# 分支与切换
$ sg branch -c feature
Created branch feature (was 0a8dbe8)
$ sg checkout feature
Switched to branch 'feature'sg serve 启动 axum 服务器,暴露完整的 REST API:
| 方法 | 端点 | 功能 |
|---|---|---|
POST | /api/repos | 创建仓库 |
GET | /api/repos/{repo}/status | 仓库状态 |
GET | /api/repos/{repo}/log | 提交历史 |
GET/PUT | /api/repos/{repo}/objects/{hash} | 对象读写 |
GET/PUT/DELETE | /api/repos/{repo}/refs/{name} | 引用管理 |
POST | /api/repos/{repo}/stage | 暂存文件 |
POST | /api/repos/{repo}/commits | 创建提交 |
# 创建仓库
$ curl -s -X POST http://localhost:3000/api/repos \
-H 'Content-Type: application/json' \
-d '{"name":"test-repo"}'
{"status":"ok","data":{"name":"test-repo","path":"/tmp/sg-api-test/test-repo"}}
# 暂存 + 提交
$ curl -s -X POST http://localhost:3000/api/repos/test-repo/stage \
-d '{"files":["hello.txt"]}'
{"status":"ok","data":{"staged":["hello.txt"]}}
$ curl -s -X POST http://localhost:3000/api/repos/test-repo/commits \
-d '{"message":"initial commit","author_name":"Test"}'
{"status":"ok","data":{"oid":"1840db6891e7043514f0fa7fc3a0ea0ce0635381"}}
# 查看日志
$ curl -s http://localhost:3000/api/repos/test-repo/log
{"status":"ok","data":[{"oid":"1840db68...","message":"initial commit",...}]}simple-git/
├── Cargo.toml # Workspace root
├── crates/
│ ├── sg-core/ # Git 对象模型 + 仓库操作
│ │ └── src/
│ │ ├── hash.rs # ObjectId, SHA-1
│ │ ├── object.rs # Blob/Tree/Commit/Tag
│ │ ├── index.rs # JSON staging area
│ │ ├── refs.rs # Branch/tag references
│ │ └── repository.rs # Repository abstraction
│ ├── sg-storage/ # 存储抽象 + 4个后端
│ │ └── src/
│ │ ├── traits.rs # ObjectStorage trait
│ │ ├── local.rs # 本地文件系统
│ │ ├── s3_compat.rs # R2/COS (S3兼容)
│ │ ├── baidu.rs # 百度网盘 PCS API
│ │ └── memory.rs # 内存后端(测试)
│ ├── sg-commands/ # 10个CLI命令
│ │ └── src/
│ │ ├── init/add/commit/status/log
│ │ ├── branch/checkout
│ │ └── clone/push/pull
│ ├── sg-cli/ # CLI 入口
│ │ └── src/main.rs
│ └── sg-server/ # HTTP API 服务
│ └── src/lib.rs # axum 路由 + handlers| 阶段 | 内容 | 状态 |
|---|---|---|
| Phase 1 | 本地 git 操作 (init/add/commit/status/log/branch/checkout) | DONE |
| Phase 3 | R2/COS S3 后端 + 百度网盘 PCS API + clone/push/pull | DONE |
| Phase 4 | Axum HTTP API 服务器 (8组 REST 端点) | DONE |
| Phase 2 | diff 命令、Tag 对象支持 | TODO |
| Phase 5 | Packfile、Merge、Rebase、GC | TODO |
完整的 init/add/commit/status/log/branch/checkout 流程,零外部依赖。
S3 兼容后端,一个实现覆盖 Cloudflare R2 和腾讯 COS 两个平台。
PCS REST API + OAuth2,支持上传/下载/列表/删除文件操作。
8 组 REST 端点,覆盖仓库管理、对象读写、引用操作、暂存和提交。
| Crate | 用途 |
|---|---|
sha1 + flate2 | SHA-1 哈希 + zlib 压缩(git 对象格式) |
tokio | 异步运行时 |
object_store | S3 兼容存储抽象(R2/COS) |
reqwest | HTTP 客户端(百度网盘 PCS API) |
axum + tower-http | HTTP 服务器 + 中间件 |
clap | CLI 参数解析 |
serde + serde_json | 序列化(Index、Config) |
thiserror + anyhow | 错误处理 |
chrono | 时间戳(commit author/committer) |