g1t/apps/docs/src/content/docs/guides/git.md

256 lines10,875 bytesCodeBlame
1---
2title: Git
3description: Remotes, credentials, private repositories and limits.
4---
5
6g1t speaks git's smart HTTP protocol. Any git client works.
7
8## Remotes
9
10```text
11https://g1t.sh/<workspace>/<repo>.git
12```
13
14Public repositories can be cloned without signing in:
15
16```sh
17git clone https://g1t.sh/flagon-io/g1t.git
18```
19
20If the workspace is [renamed](/guides/workspaces/#rename-a-workspace), the
21old remote redirects to the new one for 90 days. Git follows the redirect
22and warns about it; point the remote at the new address:
23
24```sh
25git remote set-url origin https://g1t.sh/<new-workspace>/<repo>.git
26```
27
28## Authentication
29
30Pushing, and reading private repositories, needs credentials. Use your
31username, and as the password either your account password or an
32[access token](https://g1t.sh/settings/tokens). Tokens are recommended: they can be revoked
33individually and they also work for the API.
34
35To avoid typing it each time, let git store it:
36
37```sh
38git config --global credential.helper store
39```
40
41## Creating a repository by pushing
42
43Pushing to a repository that does not exist, in a workspace you belong to,
44creates it as a private repository, so nothing pushed by mistake is
45published. To make it public, see
46[change who can see a repository](/guides/managing-repositories/#change-who-can-see-a-repository).
47
48```sh
49git push https://g1t.sh/<workspace>/new-repo.git main
50```
51
52## Private repositories
53
54A private repository is visible only to people with a
55[role](/guides/access-and-roles/) on it. Cloning and fetching need
56Read, and pushing needs Write. To
57everyone else it looks exactly like a repository that does not exist, both
58on the site and to git.
59
60On the site, an address you cannot see gives the same page either way, with
61status 404:
62
63| You are | The page says |
64| --- | --- |
65| Signed out | **Nothing here**: this page doesn't exist, or it's private; sign in if it's yours. **Sign in** brings you back to the same address. |
66| Signed in | **Nothing here**: this page doesn't exist, or you don't have access to it, with which account you are signed in as and a link to switch account. If you should have access, ask someone with the Admin role on it to add you. |
67
68Issues, pull requests and workspace pages work the same way. The sidebar
69does not open the project or workspace the address names, so nothing on
70the page hints at whether it exists; a missing file, commit or issue in a
71project you can see keeps that project's sidebar. A profile that does not
72exist says **No one on g1t goes by that name**, since profiles are public.
73
74## Download a ZIP
75
76On a repository's **Files** page, **Code** → **Download ZIP** downloads the
77branch shown as one zip, its files in a folder named `<repo>-<branch>`. It
78works for anyone who can see the repository, and for any branch, tag or
79commit at `g1t.sh/<workspace>/<repo>/archive/<ref>.zip`. A ZIP holds the
80files, not the history; clone for that. A repository with more than 10,000
81files or over 24 MB is too large to download this way, so clone it instead.
82
83## Browsing without an account
84
85Public projects, Explore, Search and profiles are open to everyone, in the
86same sidebar members use. Signed out, the sidebar has Explore and Search,
87and in a project its Code, Issues, Pull requests, Agents, Workflows and
88Deployments; pages only people with a role on the repository see, such as
89Security and Settings, are left out. **Sign in** and **Sign up** sit at the bottom, and both bring you
90back to the page you were on.
91
92## Protected branches
93
94A repository can protect its default branch under **Settings → Branches and
95merging**. Pushing to it is then refused for everyone, whatever their role, and for agents, and
96git says why:
97
98```text
99 ! [remote rejected] main -> main (main is protected: push a branch and open a pull request)
100```
101
102Changes reach a protected branch only by merging a pull request. The first
103push to an empty repository is still allowed.
104
105The same page sets what a merge needs: the
106[required status checks](/guides/pull-requests/#required-status-checks)
107and approvals.
108
109## Branches
110
111Push any branch to a repository you can write to, and open a
112[pull request](/concepts/overview/#pull-requests) from it on the
113repository's **Pull requests** tab.
114
115```sh
116git switch -c my-change
117git push origin my-change
118```
119
120A repository's **Branches** tab, `g1t.sh/<workspace>/<repo>/branches`, lists
121every branch: the default one first, then those with a commit in the last 90
122days (**Active**), then the rest (**Stale**). Each shows its last commit, how
123many commits it is ahead of and behind the default branch, the pull request
124open on it with its checks, and its preview when it has one. A count with a
125`+` ran past how far back g1t reads, 40 commits on the branch and 120 on the
126default. Search narrows the list by name.
127
128The **Tags** tab lists tags newest first, up to 100, each with its commit
129and a ZIP of its files.
130
131**Compare**, `g1t.sh/<workspace>/<repo>/compare/<base>...<head>`, shows
132what one branch has that another does not: its commits, then every change.
133Pick the two branches at the top; **Open a pull request** starts one from
134the compared branch.
135
136On **Files**, each file and folder shows the commit that last changed it and
137when, from up to 300 commits of the branch's history; one changed before
138that shows none. The branch menu at the top switches branch and keeps the
139folder or file you are on.
140
141## Pull request forks
142
143A pull request that was not opened from a branch has its own remote:
144
145```text
146https://g1t.sh/pulls/<pull request id>.git
147```
148
149Only whoever opened the pull request can push to it, or, for one g1t
150made, whoever asked for it. Pushes to a fork
151update the pull request's head commit on its page.
152
153## Limits
154
155### Size limits
156
157Repositories are stored in Cloudflare Artifacts. g1t checks its limits
158before a push is stored, and declines a push that would cross one. git
159prints the reason beside each branch (`! [remote rejected] main (…)`), and
160what to do as `remote:` lines. Nothing in a declined push is stored.
161
162| Limit | Size | What happens past it |
163| --- | --- | --- |
164| A file | 32 MB | The push is declined, naming the file's size. |
165| 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. |
166| 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. |
167| A push | 100 MB | Refused by the network with HTTP `413` before g1t sees it. |
168
169To push a large history in parts:
170
171```sh
172git rev-list --reverse HEAD | awk 'NR % 500 == 0' | xargs -I{} git push origin {}:refs/heads/main
173git push origin main
174```
175
176Each push sends only what the one before did not.
177
178### When the store is busy
179
180If Cloudflare Artifacts is rate limiting g1t or not answering, g1t tries
181reads again for a moment, then answers git with HTTP `429` (rate limited)
182or `503` (unavailable) and a `Retry-After` header saying how many seconds
183to wait. Pushes are never tried again on your behalf: run `git push`
184again. On g1t.sh the page says the git storage is busy instead of failing,
185and [status.g1t.sh](https://status.g1t.sh) shows **Git storage**.
186
187### Git operations
188
189Each clone, fetch and push is a git operation, your agents' included:
190their sandboxes use the same git endpoints you do, and a pull request's
191working copy counts for its repository's workspace. Every workspace has 50,000
192a month included. Past that, a workspace on the g1t plan pays $0.18 per
1931,000, and a free workspace is never charged: past 50,000 in a month, its
194git requests past 60 in an hour are answered `429` with when to try again,
195until the month turns. Counting starts on 2026-10-14. See
196[git operations](/guides/usage-and-billing/#git-operations).
197
198What these limits mean in practice, and what to do instead, is on
199[What g1t can't do yet](/about/limitations/#git).
200
201## Where a slow request's time went
202
203Every answer g1t gives git carries a `Server-Timing` header: how many
204milliseconds each step of the request took. To see it, run git with its
205HTTP trace on:
206
207```sh
208GIT_TRACE_CURL=1 git ls-remote https://g1t.sh/<owner>/<repo>.git 2>&1 | grep -i server-timing
209```
210
211| Step | What it is |
212| --- | --- |
213| `repo` | Finding the repository, and checking your credentials if you sent any |
214| `moved` | Only for an address with no repository: looking for a renamed workspace or a transferred repository to send you to |
215| `access` | Deciding whether you may fetch from or push to it |
216| `kept` | A free workspace's limits, and looking for a ref listing and a store credential made a moment ago |
217| `mint` | Only when no credential was kept: the git store making one for the request |
218| `store` | The git store's answer; for a push, checking it for secrets first |
219| `refs` | Only for a push: recording that the repository's refs changed |
220| `total` | Everything g1t did |
221| `repos` | The same, measured where your request arrived |
222
223Two entries say how a step went rather than how long it took:
224
225| Entry | Values |
226| --- | --- |
227| `refs;desc=` | `hit-colo` or `hit-shared` when the ref listing came from g1t's cache, `miss` when the git store was asked |
228| `pack;desc=` | Only for a fresh clone: `hit` when its pack came from g1t's cache, `miss` when the git store built it |
229| `cred;desc=` | `isolate` or `shared` for a store credential made a moment ago, `mint` for a new one |
230
231The ref listing git asks for first on every clone and fetch is kept for up
232to a minute, and only the same question about the same refs gets the same
233answer: a push, a merge or any other change to a repository's branches and
234tags makes the next fetch ask the git store again. A change can take up to
2355 seconds to reach every fetch.
236
237A fresh clone, one that has no objects yet (shallow clones such as
238`git clone --depth=1` included), has its pack kept too, for up to 7 days
239or until the repository's branches or tags next change. The next clone that
240asks for the same commits in the same way gets the same pack without the
241git store building it again. A fetch into a repository you already have,
242and any pack over 200 MB, always goes to the git store.
243
244Include the header when you report a slow clone, fetch or push.
245
246## SSH
247
248Git over SSH is not available yet. Use HTTPS, which works for clone,
249fetch and push everywhere SSH would.
250
251Why: git over SSH needs raw TCP connections on port 22, and g1t runs
252entirely on Cloudflare's network. Accepting inbound TCP traffic directly
253into Workers is in a beta from Cloudflare that g1t has applied for and is
254waiting on. SSH keys can already be added under
255[Settings → SSH keys](https://g1t.sh/settings/keys),
256and will be used once SSH is on.