g1t/apps/docs/src/content/docs/guides/merge-queue.md

190 lines7,224 bytesCodeBlame
1---
2title: Merge queue
3description: Test each pull request together with the ones ahead of it, so main only moves to a state whose checks passed.
4---
5
6Merging one pull request at a time, each caught up with `main`, keeps every
7merge clean as text. It does not prove the result works: two changes can
8merge without a conflict and still break each other. With the merge queue
9on, a pull request is tested together with everything ahead of it before it
10lands, and `main` only ever moves to a state whose checks passed.
11
12The merge queue runs in g1t's sandboxes, which work in any workspace with
13[its own model provider](/guides/models/) and in those g1t's hosted models
14are open to. Elsewhere, an entry fails at once with a message saying so;
15turn the queue off to merge directly.
16
17## Turn it on
18
191. Open the repository's **Settings** tab. You need to be a member of its
20 workspace.
212. Turn on **Merge through a queue**.
223. Save.
23
24From the API, send `merge_queue` to `PATCH /repos/{owner}/{name}/settings`
25(or `update_repo_settings`):
26
27```sh
28curl -X PATCH https://api.g1t.sh/repos/acme/web/settings \
29 -H "Authorization: Bearer $G1T_TOKEN" \
30 -H "Content-Type: application/json" \
31 -d '{"merge_queue": true}'
32```
33
34## What merging does with the queue on
35
36Merging a pull request, from its page (**Add to the merge queue**), with
37`merge_pull_request`, or with `POST /repos/{owner}/{name}/pulls/{number}/merge`,
38adds it to the queue instead of changing `main`. Everything a merge needs
39is still checked first: the pull request must be ready for review, its
40checks must have passed and it must have the approvals the repository asks
41for. Only members of the workspace can add to the queue. Merging a pull
42request that is already queued changes nothing.
43
44The pull request's conversation records who added it, and its page shows
45where it is in the queue. A member can take it out with **Remove from the
46queue**. Closing a pull request also takes it out.
47
48## How entries are tested
49
50g1t takes up to four entries from the front of the queue and tests them all
51at once, speculatively, each in its own sandbox. Each sandbox builds `main`
52with that entry and every entry ahead of it merged in, in queue order:
53
54| Entry | Tested as |
55| --- | --- |
56| 1st | `main` + #41 |
57| 2nd | `main` + #41 + #44 |
58| 3rd | `main` + #41 + #44 + #46 |
59| 4th | `main` + #41 + #44 + #46 + #47 |
60
61If every entry passes, the four can land one after another without being
62tested again. The next batch starts when nothing is being tested. A batch
63that takes longer than 45 minutes is tested again.
64
65### What each state is held to
66
67Each tested state runs:
68
69- the acceptance checks of every pull request in it; and
70- the **contract**: the checks of issues already completed on the
71 repository, from the 30 most recently closed. Once an issue lands, its
72 checks become part of what `main` promises, and every later change is
73 held to them.
74
75So a change that breaks something that landed before it is caught here,
76even when it merges without a conflict and its own checks pass.
77
78Once those pass, the repository's [GitHub Actions](/guides/actions/)
79workflows that run `on: merge_group` run on the state too, with the same
80`merge_group` event GitHub sends, on the branch `g1t-queue/<entry>`. The
81entry waits for them, and lands only if they pass:
82
83```yaml
84on:
85 pull_request:
86 merge_group:
87```
88
89A contract check that fails is run again on `main` alone. If it fails there
90too, it was broken already: it is marked as passing with a note, "already
91failing on the default branch; not held against this", and does not hold
92the change back.
93
94## How entries land
95
96Entries land in order. When an entry has passed and everything ahead of it
97has landed, `main` moves to exactly the state that was tested. The issue
98closes and the other pull requests for it are superseded, as with any
99merge.
100
101Before landing, g1t checks that nothing has changed underneath:
102
103- If the pull request was pushed to after it was tested, it and the entries
104 tested on top of it are tested again.
105- If `main` moved outside the queue, every entry is tested again on the new
106 `main`.
107
108## When an entry fails
109
110An entry fails when its checks or its `merge_group` workflows fail in the
111combined state, when it does not merge cleanly with what is ahead of it, or
112when the state cannot be built.
113It leaves the queue, and:
114
1151. Its pull request gets a failed check run. Each command is named with the
116 state it ran in, such as `cargo test (merge queue, on the default branch
117 with #41 merged in first)`, and the run says why it failed. A conflict
118 names the pull request ahead it collided with.
1192. Its conversation records that it was taken out of the queue, and why.
1203. The entries that were tested on top of it are tested again without it.
121
122A g1t agent's pull request is then sent back to revise, like any failed
123check, starting from `main` as it is now. The revision counts towards
124**Revisions before asking you**. Once it is ready again, a repository with
125**Merge automatically when ready** on adds it to the queue again by itself;
126otherwise it waits for a member to merge it again. A pull request you or
127your own agent opened is yours to fix and merge again.
128
129## The Merge queue page
130
131Every repository has a **Merge queue** page, at
132`g1t.sh/<workspace>/<repo>/queue`, in the repository's sidebar. It
133refreshes on its own while anything is queued.
134
135**In the queue** lists the entries in order, starting from `main`'s commit.
136Each shows:
137
138| | |
139| --- | --- |
140| State | **Waiting**, **Testing** or **Passed**. |
141| Tested as | `main` and the pull requests merged into it, such as `main + #41 + #44`. |
142| Checks | How many of the checks passed. |
143| Who | The agent or person who made the pull request, and who queued it. |
144| Commit | The tested state's commit. |
145
146**Recently** lists the last 20 that left the queue: **Landed**, **Failed**
147or **Removed**. A failed entry shows why, and the output of the checks that
148failed.
149
150## From the API or an agent
151
152`get_merge_queue`, or `GET /repos/{owner}/{name}/queue`, returns the queue.
153It is public for a public repository.
154
155```sh
156curl https://api.g1t.sh/repos/acme/web/queue
157```
158
159```json
160{
161 "enabled": true,
162 "active": [
163 {
164 "number": 44,
165 "title": "Add a --shout flag",
166 "agent": "g1t-agent",
167 "state": "testing",
168 "ahead": [41],
169 "baseCommit": "8f3c2e1…",
170 "combinedCommit": null,
171 "results": [],
172 "enqueuedBy": "g1t"
173 }
174 ],
175 "recent": []
176}
177```
178
179| Field | |
180| --- | --- |
181| `enabled` | Whether the repository merges through the queue. |
182| `active` | The entries waiting to land, in order. |
183| `recent` | Those that landed or left, newest first. |
184| `state` | `waiting`, `testing`, `passed`, `failed`, `landed` or `removed`. |
185| `ahead` | The pull requests merged ahead of it in the state being tested. Empty when it was tested on `main` alone. |
186| `baseCommit` | The commit of `main` the state was built on. |
187| `combinedCommit` | The tested state. |
188| `results` | The checks run against it, each with `command`, `passed` and `output`. |
189| `error` | Why it failed: a conflict, or what could not be run. |
190| `enqueuedBy` | Who added it: a username, or `g1t` when it was merged automatically. |