Skip to content

Where people and agents ship software together. The open-source git platform for the whole job: issues, agents, checks and deploys to the edge.

Commit

A free workspace's public repositories hold up to 5 GB together. Public repositories are never charged for storage and the only cap was 950 MB a repository, with no limit on how many, so a free workspace could keep any amount at g1t's cost (and in the nightly backups). A push to a public repository now adds up what the workspace's public repositories hold, as g1t counts pushes, and past FREE_PUBLIC_STORAGE_BYTES (5 GB, a wrangler var; 0 is no cap) asks billing whether the workspace is free; if it is, the push is refused on its first request with what it holds and what to do, as pushes to a free workspace's full private repositories already are. On the plan nothing changes, and nothing already stored is touched. The git and usage guides say so.

syntaqxcommitted Parent0ab04ddBrowse files
6 files+78−40/6 viewed
+1−0
326326 | --- | --- | --- |
327327 | A file | 32 MB | The push is declined, naming the file's size. |
328328 | A repository, with its pull requests' forks | 950 MB, as g1t counts what was pushed (the store holds 1 GB) | The push is declined; once full, pushes are refused with the reason before any data is sent. |
329+| A free workspace's repositories | 1 GB private and 5 GB public, together; none on the g1t plan | Pushes to the full kind are refused with the reason before any data is sent; see [usage and billing](/guides/usage-and-billing/). |
329330 | A push that push protection can scan before it lands | Most pushes; very large ones are scanned after they land | A very large push goes through and is scanned after it lands; secrets found are open alerts. To have it checked first, push in parts, oldest commits first. |
330331 | A push | 100 MB | Refused by the network with HTTP `413` before g1t sees it. |
331332
+6−3
3232 - The [audit log](/guides/audit-log/), with export: kept 7 days, or 90 on
3333 the plan.
3434 - Your own agent through [MCP](/reference/mcp/).
35−- 1 GB of private repository storage, and 50,000
36− [git operations](#git-operations) a month.
35+- 1 GB of private repository storage, 5 GB of public repository storage,
36+ and 50,000 [git operations](#git-operations) a month.
3737
3838 None of this is charged, on the plan or not. A free workspace is never
3939 charged for storage: once its private repositories hold 1 GB, pushes to
4040 them are refused at the start of the push, with what to do: make the
4141 repository public, delete what you do not need, or start the plan, where
4242 storage past 1 GB is usage and pushes never stop. Public repositories are
43−never charged for storage.
43+never charged for storage, on any plan; a free workspace's public
44+repositories hold up to 5 GB together, and past it pushes to them are
45+refused the same way. On the plan, pushes to public repositories never
46+stop.
4447
4548 Compute is not free. Agents, workflows, the merge queue,
4649 deployments and semantic search need [the g1t plan](#the-g1t-plan), or a
+37−0
304304 .unwrap_or(1_000_000_000)
305305 }
306306
307+/// What a free workspace's public repositories may hold together:
308+/// `FREE_PUBLIC_STORAGE_BYTES` (5 GB). Public repositories are never
309+/// charged for storage, on any plan; past it, a free workspace's pushes to
310+/// them stop, and on the plan they never do. `0` is no cap.
311+pub fn free_public_bytes(env: &worker::Env) -> i64 {
312+ env.var("FREE_PUBLIC_STORAGE_BYTES")
313+ .ok()
314+ .and_then(|value| value.to_string().parse().ok())
315+ .unwrap_or(5_000_000_000)
316+}
317+
318+/// Whether a free workspace's push to a public repository should be
319+/// refused: its public repositories already hold `free_bytes`.
320+pub fn public_storage_full(public_bytes: i64, free_bytes: i64) -> bool {
321+ free_bytes > 0 && public_bytes >= free_bytes
322+}
323+
324+/// The answer to a push to a public repository a free workspace has no
325+/// room for.
326+pub fn public_storage_full_response(namespace: &str, public_bytes: i64, free_bytes: i64) -> Result<Response> {
327+ let gb = |bytes: i64| bytes as f64 / 1_000_000_000.0;
328+ let message = format!(
329+ "{namespace}'s public repositories hold {:.2} GB, and a workspace on the free plan keeps {:.0} GB of them. Public repositories are never charged for storage, so pushes to them stop here. Delete what you no longer need, or start the g1t plan, where pushes to public repositories never stop: https://g1t.sh/{namespace}/-/billing
330+",
331+ gb(public_bytes),
332+ gb(free_bytes)
333+ );
334+ Response::error(message, 403)
335+}
336+
307337 /// Whether a push to a private repository should be refused: a free
308338 /// workspace whose private repositories already hold its free amount. Free
309339 /// workspaces are never charged for storage; past it, pushes stop instead.
419449 }
420450
421451 #[test]
452+ fn a_free_workspace_pushes_until_its_public_storage_is_full() {
453+ assert!(!public_storage_full(4_999_999_999, 5_000_000_000));
454+ assert!(public_storage_full(5_000_000_000, 5_000_000_000));
455+ assert!(!public_storage_full(50_000_000_000, 0));
456+ }
457+
458+ #[test]
422459 fn a_free_workspace_pushes_until_its_private_storage_is_full() {
423460 assert!(!storage_full(999_999_999, 1_000_000_000));
424461 assert!(storage_full(1_000_000_000, 1_000_000_000));
+15−0
22162216 )));
22172217 }
22182218 }
2219+ if git.service == GitService::ReceivePack && git.endpoint == "info/refs" && !repo.is_private {
2220+ let free = git_ops::free_public_bytes(env);
2221+ if free > 0 {
2222+ let held = self.registry.public_bytes(&namespace).await.unwrap_or(0);
2223+ if git_ops::public_storage_full(held, free)
2224+ && git_ops::is_free(env.service("BILLING").ok().as_ref(), &namespace).await
2225+ {
2226+ return Ok(Some((
2227+ git_ops::public_storage_full_response(&namespace, held, free)?,
2228+ 403,
2229+ "Free public storage is full.",
2230+ )));
2231+ }
2232+ }
2233+ }
22192234 Ok(None)
22202235 }
22212236
+15−0
636636 }
637637
638638 /// What one workspace's private repositories are counted as holding.
639+ pub async fn public_bytes(&self, namespace: &str) -> Result<i64> {
640+ #[derive(Deserialize)]
641+ struct Row {
642+ bytes: Option<f64>,
643+ }
644+ Ok(self
645+ .db
646+ .prepare("SELECT SUM(stored_bytes) AS bytes FROM repos WHERE namespace = ? AND is_private = 0 AND fork_of IS NULL AND deleted_at IS NULL")
647+ .bind(&[namespace.into()])?
648+ .first::<Row>(None)
649+ .await?
650+ .and_then(|row| row.bytes)
651+ .unwrap_or(0.0) as i64)
652+ }
653+
639654 pub async fn private_bytes(&self, namespace: &str) -> Result<i64> {
640655 #[derive(Deserialize)]
641656 struct Row {
+4−1
6565 // a workspace on the plan pays at cost plus 20% and is never slowed.
6666 // FREE_PRIVATE_STORAGE_BYTES: a free workspace's private repositories may
6767 // hold this much (1 GB); past it, pushes to them stop. Billing reads the
68− // same amount.
68+ // same amount. FREE_PUBLIC_STORAGE_BYTES: a free workspace's public
69+ // repositories may hold this much together (5 GB); past it, pushes to
70+ // them stop. 0 is no cap.
6971 //
7072 // The git store:
7173 // REPO_STORAGE_LIMIT_BYTES: pushes stop before a repository holds this
106108 "GIT_OPERATIONS_FREE_CAP": "50000",
107109 "GIT_OPERATIONS_FREE_HOURLY": "60",
108110 "FREE_PRIVATE_STORAGE_BYTES": "1000000000",
111+ "FREE_PUBLIC_STORAGE_BYTES": "5000000000",
109112 "REPO_STORAGE_LIMIT_BYTES": "950000000",
110113 "LARGE_PUSHES": "unscanned",
111114 "FORK_RETENTION_DAYS": "1",

Comments

Sign in to comment.