1---
2title: Git
3description: A pluggable, embeddable, self-hostable git server on Cloudflare Workers, Durable Objects, and R2. Smart HTTP for any client, a typed REST plane with pull requests, and a GitHub-compatible API.
4---
5
6`alchemy/Git` is a pluggable, embeddable, self-hostable git server. It
7speaks git's smart HTTP to any client, serves a typed REST plane with
8pull requests, and answers the GitHub REST v3 API for `gh` and Octokit.
9It runs on Cloudflare Workers, Durable Objects, and R2, embeds in your
10own `HttpApi`, and each part of it is an Effect Layer you can replace:
11
12```typescript
13import * as Cloudflare from "alchemy/Cloudflare";
14import * as Git from "alchemy/Git";
15import * as Effect from "effect/Effect";
16import * as Layer from "effect/Layer";
17import * as HttpRouter from "effect/http/HttpRouter";
18import * as Http from "alchemy/Http";
19import { Authentication } from "./api.ts";
20
21export const GitObjects = Cloudflare.R2.Bucket("GitObjects");
22
23const GitLive = Git.ApiLive.pipe( // ordinary routes beside your application API
24 Layer.provide(Git.ApiHandlersLive), // shared Git handlers
25 Layer.provide(Authentication.layer), // your middleware: who may call what
26 Layer.provide(Git.ReposDurableObject), // refs, objects, pull requests
27 Layer.provide(Git.RegistryDurableObject), // owner/name → repo
28 Layer.provide(Git.HasherInline), // push verification
29 Layer.provide(Git.BlobStoreR2(GitObjects)), // packs, bundles, large pushes
30);
31
32export default Cloudflare.Worker(
33 "Git",
34 { main: import.meta.url, ...Git.GIT_WORKER_OPTIONS },
35 Effect.gen(function* () {
36 const fetch = yield* HttpRouter.toHttpEffect(GitLive.pipe(Layer.provide(Http.Platform)));
37 return { fetch };
38 }),
39);
40```
41
42`Authentication` is the application's route middleware. [Getting Started](/git/getting-started)
43defines it; [HTTP routes](/git/blocks/server#add-git-to-your-application) explains their composition.
44
45Each line of the graph is one decision with its own implementations.
46Changing a line changes the decision and nothing else:
47
48```diff lang="typescript"
49-const GitObjects = Cloudflare.R2.Bucket("GitObjects");
50+const GitObjects = AWS.S3.Bucket("GitObjects");
51
52const GitLive = Git.ApiLive.pipe(
53 Layer.provide(Git.ApiHandlersLive),
54 Layer.provide(Authentication.layer),
55 Layer.provide(Git.ReposDurableObject),
56 Layer.provide(Git.RegistryDurableObject),
57 Layer.provide(Git.HasherInline),
58- Layer.provide(Git.BlobStoreR2(GitObjects)),
59+ Layer.provide(Git.BlobStoreS3(GitObjects)),
60);
61```
62
63Bytes now live in S3. Application authorization stays in your HTTP handlers.
64
65The engine holds no users, no credentials, and no policy. Who may call
66a route is the middleware applied to its route layer, so the same host
67runs behind a shared secret, behind Better Auth, or behind any other
68authentication. Your handler decodes the push, authorizes its proposed changes,
69then calls `Git.Engine.preparePush` and `commitPush`. Endpoints use Effect's `HttpApiEndpoint`; implementations use
70`HttpApiBuilder.group` and `handleAll`. Add your own groups or replace a
71handler in a Git group before registering it.
72[git.alchemy.run](https://git.alchemy.run) runs this file. The alchemy
73monorepo, 44,051 objects in a 67 MiB pack, is hosted on it and clones
74back byte-identical under `git fsck --strict`.
75
76## Build one
77
78[Getting Started](/git/getting-started) is a complete shared-credential quickstart.
79The tutorial starts with a Git push and builds one behavior at a time. Every
80part ends with a deployment and a check you can run:
81
821. [Push your first repository](/git/tutorial/part-1) — deploy Git, push a commit,
83 and clone it back.
842. [Control access](/git/tutorial/part-2) — require a shared credential and verify
85 anonymous requests fail.
863. [Publish a repository](/git/tutorial/part-3) — allow anonymous clones while
87 keeping writes protected.
884. [Give users their own credentials](/git/tutorial/part-4) — use accounts and
89 individual API keys.
905. [Add your application's API](/git/tutorial/part-5) — serve `/me` beside Git
91 with the same authenticated user.
926. [Protect a branch](/git/tutorial/part-6) — reject deletion of `main` with an
93 application policy.
94
95## Use it
96
97- [Cloning & pushing](/git/clone-and-push) — standard clients, what
98 the wire supports, credentials.
99- [Repositories](/git/repositories) — create, fork, import, and manage
100 over the typed REST plane.
101- [Pull requests](/git/pull-requests) — server-side merge base, diffs,
102 and merges.
103- [GitHub API compatibility](/git/github-api) — `gh api` and Octokit
104 against your host.
105
106## Shape it
107
108[Building blocks](/git/blocks) is the reference for each line of the
109graph: the contract, what ships, how to write your own.
110[Recipes](/git/recipes) maps requirements to lines, with
111[Scaling](/git/recipes/scaling) as the why behind the table and complete
112stack files to copy.
113
114## Not a GitHub replacement
115
116No issues, reviews, comments, checks, Actions, or GraphQL. `gh api`
117works. `gh pr create` and the rest of the porcelain do not. What it is:
118a git remote you own, with an API, that you can build on.
119
120Looking for the GitHub *provider*, which manages repos, Actions
121secrets, and webhooks on github.com? That is [GitHub](/github).