GitWave 文档

GitWave

一个跑在 Cloudflare 边缘网络上的 GitHub 式代码托管平台。

GitWave 把完整的 Git 服务搬到了 Cloudflare Workers 上:HTTP 服务由 Workers 提供,元数据放在 D1(SQLite),
Git 对象放在 R2 对象存储里。没有服务器、没有 SSH、没有 CI 配置——wrangler deploy 之后你就有了一个
可以 git clone / git push 的代码托管站点。

浏览器 ─┐
        ├─► Cloudflare Workers ─┬─► D1  (用户 / 仓库 / 议题 / 评论 / 星标)
git CLI ┘                       └─► R2  (Git 对象:blob / tree / commit)

功能一览

类别能力
Git 传输智能 HTTP 协议 v0,完整支持 clone / fetch / pull / push,含增量协商(ACK/NAK)、side-band-64k、ofs-delta / ref-delta 解包
仓库公开 / 私有仓库、分支与标签、文件浏览、原始文件下载、提交历史、单提交详情与文件变更
协作议题(issue)、拉取请求(pull request)、评论、关闭 / 重开、快进合并
社区加星、关注、复刻(fork)、用户主页、活动流、仓库与用户搜索
账号注册 / 登录 / 登出、会话 Cookie、HTTP Basic 认证(给 git 用)、Bearer 令牌(给 API 用)
API/api/v1 下的 REST 接口:用户、仓库、分支、提交、文件内容、议题、评论、星标、事件流、统计
界面服务端渲染,无需前端构建;响应式布局、浅色 / 深色主题、无外部字体与 CDN 依赖

快速开始

1. 环境要求

2. 安装依赖

npm install

3. 创建 Cloudflare 资源

npx wrangler login            # 登录 Cloudflare

npx wrangler d1 create gitwave
# 记下返回的 database_id,稍后填入 wrangler.toml

npx wrangler r2 bucket create gitwave-objects

把 wrangler.toml 里的 database_id 换成上一步拿到的真实 ID:

[[d1_databases]]
binding = "DB"
database_name = "gitwave"
database_id = "你的-database-id"

4. 本地开发

npm run db:migrate      # 应用 D1 迁移(本地模拟数据库)
npm run dev             # 启动 http://localhost:8787

本地开发时 wrangler dev 会自动使用 .wrangler/state/ 下的本地 D1 与 R2 模拟器,
不需要任何云端资源。

5. 部署上线

npm run db:migrate:remote   # 把迁移应用到线上 D1
npm run deploy              # 发布 Worker

或者直接用一键脚本,它会依次完成资源创建检查、迁移和部署:

./scripts/deploy.sh

部署完成后,把 gitwave.<你的子域>.workers.dev(或你绑定的自定义域名)分享出去即可。


使用方式

网页端

打开站点 → 注册账号 → 新建仓库 → 在仓库页复制 clone 地址。

命令行

# 克隆
git clone https://gitwave.example.com/alice/demo.git

# 推送(首次会提示输入用户名和密码,即你的 GitWave 账号)
git push origin main

推送时使用 HTTP Basic 认证,填 GitWave 的用户名和密码即可。
私有仓库在未认证时会返回 401 并带上 WWW-Authenticate: Basic 质询,git 客户端会自动带上凭据重试。

REST API

注册接口会直接返回一个令牌:

curl -X POST https://gitwave.example.com/api/v1/users \
  -H 'Content-Type: application/json' \
  -d '{"login":"alice","email":"alice@example.com","password":"supersecret123","name":"Alice"}'

之后用 Authorization: Bearer <令牌> 访问需要认证的接口:

curl -H "Authorization: Bearer $TOKEN" \
  https://gitwave.example.com/api/v1/user/repos

常用端点:

方法路径说明
POST/api/v1/users注册(返回令牌)
GET/api/v1/users、/api/v1/users/:login用户列表 / 用户详情
GET/api/v1/user、/api/v1/user/repos当前用户 / 其仓库
GET POST/api/v1/repos、/api/v1/user/repos仓库列表 / 创建仓库
GET/api/v1/repos/:owner/:repo仓库详情
GET/api/v1/repos/:owner/:repo/branches分支列表
GET/api/v1/repos/:owner/:repo/commits提交历史
GET/api/v1/repos/:owner/:repo/contents/:path文件内容
GET POST/api/v1/repos/:owner/:repo/issues议题列表 / 创建(?kind=issue|pull|all、?state=open|closed|all)
POST/api/v1/repos/:owner/:repo/issues/:number/comments添加评论
GET/api/v1/repos/:owner/:repo/stargazers星标用户
GET/api/v1/events、/api/v1/stats活动流 / 站点统计
GET/api/v1/health健康检查:真实读写一次 D1 与 R2,并自检 Git 引擎
GET/api/v1/selftest?key=<密钥>端到端自检:在 Worker 内部跑一遍注册 → push → clone

项目结构

gitwave/
├── migrations/
│   └── 0001_gitwave_init.sql # D1 表结构
├── public/
│   ├── style.css            # 全站样式(浅色 / 深色主题、响应式)
│   └── guide.html           # 由 scripts/build-docs.mjs 从本文件生成的手册
├── scripts/
│   ├── build-docs.mjs       # README.md → public/guide.html + README-BOM.md
│   ├── deploy.sh            # 一键部署脚本
│   └── smoke-test.sh        # 端到端冒烟测试脚本
├── src/
│   ├── index.tsx            # 应用入口:挂载 API、Git 传输、网页
│   ├── types.ts             # 前后端共享的数据结构
│   ├── auth/                # 密码哈希、会话、请求认证
│   ├── db/                  # D1 数据访问层
│   ├── git/                 # Git 引擎(见下)
│   ├── lib/html.ts          # JSX → HTML 渲染
│   ├── routes/              # web.tsx(网页)/ api.ts(REST)/ git.ts(Git 传输)
│   ├── selftest.ts          # 生产环境端到端自检(注册 → push → clone)
│   ├── services/            # 仓库服务(分支、提交、文件、README)
│   ├── util/encoding.ts     # 字符集判定、base64 等编码工具
│   └── views/               # 服务端渲染的页面组件
└── test/                    # Node 原生测试

Git 引擎

src/git/ 下是一套自己实现的 Git 引擎,没有依赖任何第三方 git 库:

模块职责
sha1.ts纯 TypeScript 实现的 SHA-1
inflate.ts手写 DEFLATE 解码器,精确跟踪消费的字节数(这是顺序解析 packfile 的前提,Web DecompressionStream 做不到)
zlib.ts基于 CompressionStream 的 zlib 压缩,以及基于上面解码器的解压
objects.tsblob / tree / commit 的编码、解析与哈希
tree.ts树遍历、路径解析、目录列表
pack.tspack v2 的生成与解析,支持 ofs-delta / ref-delta
revwalk.ts可达对象遍历、提交历史、树差异
protocol.tspkt-line 组帧、ref 广播、upload-pack / receive-pack 协议
store.ts对象存储抽象(R2 / 内存 / 带缓存)

Git 对象按内容寻址存放在 R2 的 objects/ 前缀下,因此复刻仓库共享同一份对象,
fork 出来的仓库几乎不占额外空间。


字符集与「乱码」

中文乱码绝大多数不是数据坏了,而是接收端猜错了字符集——文本响应没写
charset 时,浏览器和各类文本查看器在中文环境里会按 GBK 去解 UTF-8 的字节。
GitWave 里统一按下面几条规则处理:

场景处理方式
HTML 页面响应头 text/html; charset=UTF-8,页面内再写一遍 <meta charset="utf-8">
REST API响应头 application/json; charset=utf-8
仓库里的原始文件文本返回 text/plain; charset=utf-8,二进制返回 application/octet-stream + nosniff
文件预览只有能以 fatal 模式完整解码成 UTF-8 的内容才按文本展示,其余按二进制处理(避免出现 U+FFFD 替换字符)
纯文本 / Markdown 文件额外提供 README-BOM.md(带 UTF-8 BOM),让记事本等编辑器明确按 UTF-8 解码

src/util/encoding.ts 集中实现文本 / 二进制判定与 base64 编码。

生成在线手册

public/guide.html 是由本文件自动生成的手册页(站点上的 /guide),带目录、
深浅色主题和移动端适配:

npm run build:docs

改完 README 后重新执行一次即可,生成物同时会写出带 BOM 的 README-BOM.md。


测试

npm test        # 61 个用例:Git 引擎、协议、视图层、编码
npm run typecheck

测试覆盖了真实 git 的行为:

端到端冒烟测试

对任何已经跑起来的实例(本地或线上)都可以跑一遍完整的端到端验证:

./scripts/smoke-test.sh                                   # 默认测本地
BASE_URL=https://gitwave.example.com ./scripts/smoke-test.sh

它会依次验证:注册 → 建仓库 → 克隆空仓库 → 提交推送 → 二次克隆并 git fsck →
增量推送与拉取 → 推送分支与标签 → 创建议题 → 创建拉取请求并合并。


安全说明

—— 迭代次数取的是 Cloudflare Workers WebCrypto 的上限:超过 100000 会直接抛
NotSupportedError,而本地 miniflare 不做限制,这个坑只有部署到线上才会暴露


生产环境自检

线上部署之后,有两个不依赖外部网络的检查入口:

# 健康检查:真实读写一次 D1 与 R2,并自检 Git 引擎的哈希
curl https://<你的域名>/api/v1/health
# => {"status":"ok","checks":{"d1":{"ok":true,...},"r2":{"ok":true,...},"git":{"ok":true,...}}}

# 端到端自检:在 Worker 内部跑一遍「注册 → 建仓库 → push → clone」
npx wrangler secret put SELFTEST_KEY     # 先设置密钥
curl "https://<你的域名>/api/v1/selftest?key=<你设置的值>"

端到端自检走的是真实的路由处理器、真实的 D1 与真实的 R2,结束后会清理自己创建的
账号、仓库与 Git 对象。未设置 SELFTEST_KEY 时该端点直接返回 404,等于关闭。

这两个端点存在的意义:本地 miniflare 和线上 Workers 的运行时限制并不完全一致
(比如 PBKDF2 的迭代次数上限),只靠本地测试发现不了。


已知限制


许可证

MIT