Rust Project

Simple-Git 个人云存储 Git 系统 — sg

存储无关的中间层,让 git 对象存到任意云存储。Rust 实现,CLI + API 双入口。
支持 Cloudflare R2、腾讯 COS、百度网盘 PCS API。

🧠 Rust 1.95 R2 S3-Compatible Tencent COS Baidu PCS API Axum HTTP Clap CLI
← 返回文档索引

🏗️ 系统架构

CLI / API
sg-cli (clap) sg-server (axum)
Commands
init add commit status log branch checkout clone push pull
sg-core
ObjectId Blob Tree Commit Tag Index Refs Repository
sg-storage
ObjectStorage trait LocalStorage S3CompatStorage (R2/COS) BaiduStorage MemoryStorage

💡 核心设计决策

为什么自定义 git 对象模型(不用 gix)?

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 适配器。

为什么 MVP 用 JSON Index?

git 的二进制 index 格式复杂(含扩展字段、设备号、inode 等)。MVP 阶段用 JSON 存储 staging area,方便调试和手动检查。后续可以无缝切换为二进制格式。

☁️ 三大云存储后端

Cloudflare R2 Tencent COS Baidu Netdisk
后端实现方式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

所有后端实现同一个 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 ... }

⌨️ CLI 命令一览

$ 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'

🌐 HTTP API 服务

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创建提交

API 验证实况

# 创建仓库 $ 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 3R2/COS S3 后端 + 百度网盘 PCS API + clone/push/pullDONE
Phase 4Axum HTTP API 服务器 (8组 REST 端点)DONE
Phase 2diff 命令、Tag 对象支持TODO
Phase 5Packfile、Merge、Rebase、GCTODO

🟢 本地存储

完整的 init/add/commit/status/log/branch/checkout 流程,零外部依赖。

🔵 R2 / COS

S3 兼容后端,一个实现覆盖 Cloudflare R2 和腾讯 COS 两个平台。

🟣 百度网盘

PCS REST API + OAuth2,支持上传/下载/列表/删除文件操作。

🟡 HTTP API

8 组 REST 端点,覆盖仓库管理、对象读写、引用操作、暂存和提交。

📦 关键依赖

Crate用途
sha1 + flate2SHA-1 哈希 + zlib 压缩(git 对象格式)
tokio异步运行时
object_storeS3 兼容存储抽象(R2/COS)
reqwestHTTP 客户端(百度网盘 PCS API)
axum + tower-httpHTTP 服务器 + 中间件
clapCLI 参数解析
serde + serde_json序列化(Index、Config)
thiserror + anyhow错误处理
chrono时间戳(commit author/committer)

⚠️ 已知限制与风险