@@ -1,10 +1,12 @@ |
| 1 |
# dumbforge |
1 |
# dumbforge |
| 2 |
|
2 |
|
|
|
3 |
**the following text is not LLM generated** |
|
|
4 |
|
| 3 |
Well, everyone's [been talking about GitHub alternatives](https://mitchellh.com/writing/ghostty-leaving-github) lately. I'm pretty sympathetic to that on an ideological level (and just the fundamental problem of it being down all the time), but historically the alternatives kind of suck, and I think still miss the point of Git being decentralized in the first place. [Gitea](https://gitea.com/)/[Forgejo](https://forgejo.org/) are cool, but require you to set up a server and configure it. Even though it's pretty easy, it's still annoying and requires you to pay for and babysit a VPS or whatever to run the forge program. [Codeberg](https://codeberg.org/) has been a platform of choice for freedom-heads to get away from GitHub, but they recently instituted a no-crypto and no-LLM rule. I respect what they're doing, but I'm pretty AI-pilled so that's not going to work for me. |
5 |
Well, everyone's [been talking about GitHub alternatives](https://mitchellh.com/writing/ghostty-leaving-github) lately. I'm pretty sympathetic to that on an ideological level (and just the fundamental problem of it being down all the time), but historically the alternatives kind of suck, and I think still miss the point of Git being decentralized in the first place. [Gitea](https://gitea.com/)/[Forgejo](https://forgejo.org/) are cool, but require you to set up a server and configure it. Even though it's pretty easy, it's still annoying and requires you to pay for and babysit a VPS or whatever to run the forge program. [Codeberg](https://codeberg.org/) has been a platform of choice for freedom-heads to get away from GitHub, but they recently instituted a no-crypto and no-LLM rule. I respect what they're doing, but I'm pretty AI-pilled so that's not going to work for me. |
| 4 |
|
6 |
|
| 5 |
It occurred to me that you don't actually need to run a forge or git daemon at all, since Git supports cloning via the so-called ["dumb" HTTP protocol](https://git-scm.com/book/en/v2/Git-Internals-Transfer-Protocols). You could theoretically just throw your git repo into an s3 bucket, and it would be clone-able, no daemon or VPS required. So that's cool, and even more decentralized; but the problem with self-hosting git like that, is that then you don't have the nice landing page, file browser, commit log, etc etc. It's small, but it makes a big difference to have a GitHubby UI for each project. [SourceHut](https://sourcehut.org/) and [Savannah](https://savannah.gnu.org/) struggle with this I think, since they're pretty alien to normies. |
7 |
It occurred to me that you don't actually need to run a forge or git daemon at all, since Git supports cloning via the so-called ["dumb" HTTP protocol](https://git-scm.com/book/en/v2/Git-Internals-Transfer-Protocols). You could theoretically just throw your git repo into an s3 bucket, and it would be clone-able, no daemon or VPS required. So that's cool, and even more decentralized; but the problem with self-hosting git like that, is that then you don't have the nice landing page, file browser, commit log, etc etc. It's small, but it makes a big difference to have a GitHubby UI for each project. [SourceHut](https://sourcehut.org/) and [Savannah](https://savannah.gnu.org/) struggle with this I think, since they're pretty alien to normies. |
| 6 |
|
8 |
|
| 7 |
So I slopped `dumbforge` together as a proof of concept; it's a static-site-generator like thing that functions as a git remote helper which pushes directly to an s3 bucket, and generates a GitHub-like UI. So you get some really nice advantages: |
9 |
So I slopped `dumbforge` together as a proof of concept; it's a static-site-generator-like-thing that functions as a git remote helper which pushes directly to an s3 bucket, and generates a GitHub-like UI. So you get some really nice advantages: |
| 8 |
|
10 |
|
| 9 |
1. It's super fast to browse, since it's just static HTML. GitLab and GitHub itself are really slow clunky beasts. |
11 |
1. It's super fast to browse, since it's just static HTML. GitLab and GitHub itself are really slow clunky beasts. |
| 10 |
2. You don't need to administer a git daemon or forge server. |
12 |
2. You don't need to administer a git daemon or forge server. |
@@ -13,6 +15,8 @@ So I slopped `dumbforge` together as a proof of concept; it's a static-site-gene |
| 13 |
|
15 |
|
| 14 |
I'll grant that the implementation could most certainly use some improvement but this is mostly just to show off the idea. I hope it piques your curiosity. 🤔 |
16 |
I'll grant that the implementation could most certainly use some improvement but this is mostly just to show off the idea. I hope it piques your curiosity. 🤔 |
| 15 |
|
17 |
|
|
|
18 |
**the following text is LLM generated** |
|
|
19 |
|
| 16 |
## Install |
20 |
## Install |
| 17 |
|
21 |
|
| 18 |
```sh |
22 |
```sh |
@@ -24,44 +28,142 @@ create packfiles instead of reimplementing its storage format. |
| 24 |
|
28 |
|
| 25 |
## Configure an R2 remote |
29 |
## Configure an R2 remote |
| 26 |
|
30 |
|
| 27 |
Create an R2 Object Read & Write token scoped to the target bucket and save it |
31 |
An R2 remote has two addresses: |
| 28 |
in an AWS-compatible profile: |
32 |
|
|
|
33 |
- the **S3 API endpoint**, which dumbforge uses to push with your credentials; |
|
|
34 |
- a **public URL**, which browsers and ordinary Git use without credentials. |
|
|
35 |
|
|
|
36 |
The S3 API endpoint is not the public URL. It normally looks like |
|
|
37 |
`https://ACCOUNT_ID.r2.cloudflarestorage.com`. The public URL is either an |
|
|
38 |
`r2.dev` development URL or a custom domain such as `https://git.example.com`. |
|
|
39 |
|
|
|
40 |
### 1. Create a bucket and make it public |
|
|
41 |
|
|
|
42 |
In the Cloudflare dashboard, open **Storage & databases → R2**, create a bucket, |
|
|
43 |
and open its **Settings** page. Give it either a Public Development URL or a |
|
|
44 |
custom domain. A custom domain is preferable for anything you intend to keep; |
|
|
45 |
the `r2.dev` URL is fine for testing. |
|
|
46 |
|
|
|
47 |
You do not need to configure CORS. You should now have these three values: |
|
|
48 |
|
|
|
49 |
```text |
|
|
50 |
Bucket: my-bucket |
|
|
51 |
S3 endpoint: https://ACCOUNT_ID.r2.cloudflarestorage.com |
|
|
52 |
Public URL: https://git.example.com |
|
|
53 |
``` |
|
|
54 |
|
|
|
55 |
### 2. Create credentials for dumbforge |
|
|
56 |
|
|
|
57 |
From the R2 overview, select **Manage R2 API tokens → Create API token**. Give |
|
|
58 |
the token **Object Read & Write** access and scope it to the new bucket. When |
|
|
59 |
Cloudflare creates it, copy the **Access Key ID** and **Secret Access Key**. The |
|
|
60 |
secret is only shown once. |
|
|
61 |
|
|
|
62 |
These are S3 credentials, not your normal Cloudflare API bearer token. You do |
|
|
63 |
not need an AWS account. R2 implements the S3 protocol, and dumbforge directs |
|
|
64 |
the S3 client to Cloudflare's endpoint. |
|
|
65 |
|
|
|
66 |
The easiest way to save the credentials is with the AWS CLI: |
| 29 |
|
67 |
|
| 30 |
```sh |
68 |
```sh |
| 31 |
aws configure --profile my-r2 |
69 |
aws configure --profile my-r2 |
| 32 |
``` |
70 |
``` |
| 33 |
|
71 |
|
| 34 |
Use region `auto`, then add a remote from inside a local repository: |
72 |
Answer its prompts like this: |
|
|
73 |
|
|
|
74 |
```text |
|
|
75 |
AWS Access Key ID: <the R2 Access Key ID> |
|
|
76 |
AWS Secret Access Key: <the R2 Secret Access Key> |
|
|
77 |
Default region name: auto |
|
|
78 |
Default output format: <press Enter> |
|
|
79 |
``` |
|
|
80 |
|
|
|
81 |
`aws configure` only writes a standard local credentials file. It does not |
|
|
82 |
contact AWS or copy anything there. You can confirm that the profile can reach |
|
|
83 |
your bucket before involving Git: |
| 35 |
|
84 |
|
| 36 |
```sh |
85 |
```sh |
| 37 |
dumbforge remote add origin \ |
86 |
aws s3api list-objects-v2 \ |
|
|
87 |
--profile my-r2 \ |
|
|
88 |
--bucket my-bucket \ |
|
|
89 |
--endpoint-url https://ACCOUNT_ID.r2.cloudflarestorage.com \ |
|
|
90 |
--max-items 1 |
|
|
91 |
``` |
|
|
92 |
|
|
|
93 |
An empty bucket may return no objects, which is fine. An `AccessDenied` error |
|
|
94 |
usually means the token was scoped to a different bucket or was not given |
|
|
95 |
Object Read & Write access. |
|
|
96 |
|
|
|
97 |
If you do not want to install the AWS CLI, export the standard |
|
|
98 |
`AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, and `AWS_REGION=auto` environment |
|
|
99 |
variables instead. Omit `--profile` from the next command in that case, and |
|
|
100 |
make sure those variables are present in every shell from which you push. |
|
|
101 |
|
|
|
102 |
### 3. Add the Git remote |
|
|
103 |
|
|
|
104 |
Run this inside the local Git repository you want to publish: |
|
|
105 |
|
|
|
106 |
```sh |
|
|
107 |
dumbforge remote add forge \ |
| 38 |
--bucket my-bucket \ |
108 |
--bucket my-bucket \ |
| 39 |
--prefix projects/example.git \ |
109 |
--prefix projects/example.git \ |
| 40 |
--endpoint https://ACCOUNT_ID.r2.cloudflarestorage.com \ |
110 |
--endpoint https://ACCOUNT_ID.r2.cloudflarestorage.com \ |
| 41 |
--profile my-r2 \ |
111 |
--profile my-r2 \ |
| 42 |
--public-url https://pub-EXAMPLE.r2.dev |
112 |
--public-url https://git.example.com |
| 43 |
``` |
113 |
``` |
| 44 |
|
114 |
|
| 45 |
This configures separate URLs: |
115 |
`forge` is merely the local name of the Git remote; choose another name if you |
|
|
116 |
prefer. Using `forge` also leaves an existing `origin` remote alone. |
|
|
117 |
|
|
|
118 |
The prefix is where this repository lives inside the bucket. It should normally |
|
|
119 |
end in `.git`. You can host multiple repositories in one bucket by giving each |
|
|
120 |
one a different prefix. Pass only the base domain to `--public-url`; dumbforge |
|
|
121 |
appends the prefix itself. |
|
|
122 |
|
|
|
123 |
The command configures separate fetch and push URLs: |
|
|
124 |
|
|
|
125 |
- fetch: `https://git.example.com/projects/example.git`; |
|
|
126 |
- push: a `dumbforge://` URL containing the bucket, endpoint, and profile. |
| 46 |
|
127 |
|
| 47 |
- fetch: public HTTPS, usable by unmodified Git; |
128 |
Check them with: |
| 48 |
- push: `dumbforge://`, handled by `git-remote-dumbforge`. |
|
|
| 49 |
|
129 |
|
| 50 |
Now push normally: |
130 |
```sh |
|
|
131 |
git remote -v |
|
|
132 |
``` |
|
|
133 |
|
|
|
134 |
### 4. Push |
|
|
135 |
|
|
|
136 |
Push the repository's current branch. Most new repositories call it `main`: |
| 51 |
|
137 |
|
| 52 |
```sh |
138 |
```sh |
| 53 |
git push --set-upstream origin main |
139 |
git push --set-upstream forge main |
| 54 |
``` |
140 |
``` |
| 55 |
|
141 |
|
| 56 |
Anyone can clone without dumbforge: |
142 |
If your branch has another name, replace `main` with the output of |
|
|
143 |
`git branch --show-current`. The first push publishes the complete Git history |
|
|
144 |
and builds the initial website. Later pushes upload only new Git objects and use |
|
|
145 |
the old and new commits to rebuild changed files and affected shared pages. |
|
|
146 |
|
|
|
147 |
Open the repository URL in a browser: |
|
|
148 |
|
|
|
149 |
```text |
|
|
150 |
https://git.example.com/projects/example.git |
|
|
151 |
``` |
|
|
152 |
|
|
|
153 |
Anyone can clone that same URL with ordinary Git. They do not need dumbforge, |
|
|
154 |
an R2 account, or your credentials: |
| 57 |
|
155 |
|
| 58 |
```sh |
156 |
```sh |
| 59 |
git clone https://pub-EXAMPLE.r2.dev/projects/example.git |
157 |
git clone https://git.example.com/projects/example.git |
| 60 |
``` |
158 |
``` |
| 61 |
|
159 |
|
| 62 |
The repository browser is served from that exact URL. Git appends |
160 |
The repository browser is served from that exact URL. Git appends |
| 63 |
`/info/refs`; browsers receive the HTML object stored at the repository prefix. |
161 |
`/info/refs`; browsers receive the HTML object stored at the repository prefix. |
| 64 |
|
162 |
|
|
|
163 |
If Git reports that `remote-dumbforge` is not a Git command, the npm global bin |
|
|
164 |
directory is not on your `PATH`. `command -v git-remote-dumbforge` should print |
|
|
165 |
the installed helper's path before you push. |
|
|
166 |
|
| 65 |
## Development |
167 |
## Development |
| 66 |
|
168 |
|
| 67 |
```sh |
169 |
```sh |