flagon-io/g1t

public

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

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

210 lines8,708 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 required 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 required checks passed.
11
12The merge queue runs in g1t's sandboxes, which need
13[the g1t plan](/guides/usage-and-billing/#the-g1t-plan) or the trial after
14a card check; a public repository can use the open-source pool instead.
15Without one, an entry fails at once with a message saying so; turn the
16queue off to merge directly.
17
18## Turn it on
19
201. Open the project's **Settings → Branches and merging**. You need the Maintain
21 [role](/guides/access-and-roles/) or higher on its repository.
222. Turn on **Merge through a queue**.
233. Save.
244. Add `merge_group` to the `on:` of every workflow behind a
25 [required status check](/guides/pull-requests/#required-status-checks),
26 so that it runs on the queue's states too
27 ([below](#what-each-state-is-held-to)).
28
29From the API, send `merge_queue` to `PATCH /repos/{owner}/{name}/settings`
30(or `update_repo_settings`):
31
32```sh
33curl -X PATCH https://api.g1t.sh/repos/acme/web/settings \
34 -H "Authorization: Bearer $G1T_TOKEN" \
35 -H "Content-Type: application/json" \
36 -d '{"merge_queue": true}'
37```
38
39## What merging does with the queue on
40
41Merging a pull request, from its page (**Add to the merge queue**), with
42the `pull_request` tool's `merge` action, or with
43`POST /repos/{owner}/{name}/pulls/{number}/merge`,
44adds it to the queue instead of changing `main`. Everything a merge needs
45is still checked first: the pull request must be ready for review, every
46[required check](/guides/pull-requests/#required-status-checks) must have
47passed on its head, and it must have the approvals the repository asks
48for. Only people with the Write [role](/guides/access-and-roles/) or higher can add to the
49queue. Merging a pull
50request that is already queued changes nothing.
51
52The pull request's conversation records who added it, and its page shows
53where it is in the queue. Anyone who can merge can take it out with **Remove from the
54queue**. Closing a pull request also takes it out.
55
56## How entries are tested
57
58g1t takes up to four entries from the front of the queue and tests them all
59at once, speculatively, each in its own sandbox. Each sandbox builds `main`
60with that entry and every entry ahead of it merged in, in queue order:
61
62| Entry | Tested as |
63| --- | --- |
64| 1st | `main` + #41 |
65| 2nd | `main` + #41 + #44 |
66| 3rd | `main` + #41 + #44 + #46 |
67| 4th | `main` + #41 + #44 + #46 + #47 |
68
69If every entry passes, the four can land one after another without being
70tested again. The next batch starts when nothing is being tested. A batch
71that takes longer than 45 minutes is tested again.
72
73### What each state is held to
74
75g1t pushes each state it built to a branch of its own, `g1t-queue/<entry>`,
76and runs the repository's [workflows](/guides/actions/) that run on
77`merge_group` on it. The entry waits for them, and passes only if:
78
79- every `merge_group` workflow it started passed; and
80- every [required status check](/guides/pull-requests/#required-status-checks)
81 of the default branch passed on that commit.
82
83So a change that breaks something another change ahead of it relies on is
84caught here, even when it merges without a conflict and its own checks
85passed. The branch is deleted once the entry lands or leaves the queue.
86
87A workflow opts in like this:
88
89```yaml
90on:
91 pull_request:
92 merge_group:
93```
94
95Required checks only report on a queued state if their workflows run on
96`merge_group`. When the branch requires checks and no workflow runs on
97`merge_group`, the entry fails with a message saying so: "the required
98check CI cannot report on it: no workflow runs on merge_group events. Add
99merge_group to the on: of the workflows the branch requires". A required
100check that a workflow did not report on the state fails it the same way.
101A repository that requires no checks and has no `merge_group` workflows
102only has each state built: an entry passes once it merges cleanly with
103what is ahead of it.
104
105## How entries land
106
107Entries land in order. When an entry has passed and everything ahead of it
108has landed, `main` moves to exactly the state that was tested. The issue
109closes and the other pull requests for it are superseded, as with any
110merge.
111
112Before landing, g1t checks that nothing has changed underneath:
113
114- If the pull request was pushed to after it was tested, it and the entries
115 tested on top of it are tested again.
116- If `main` moved outside the queue, every entry is tested again on the new
117 `main`.
118
119A pull request that is already known to conflict with `main` is not added
120to the queue: [its merge box](/guides/pull-requests/#conflicts) says which
121files conflict and how to resolve them first. One that is only behind `main`
122does not need to catch up to join the queue, since the queue tests it on
123top of `main`. Where the repository requires pull requests to be up to
124date, [catch it up](/guides/pull-requests/#catching-up) first: when it and
125`main` changed different files that takes a few seconds and no agent.
126
127## When an entry fails
128
129An entry fails when its `merge_group` workflows or required checks fail
130on the combined state, when it does not merge cleanly with what is ahead of it, or
131when the state cannot be built.
132It leaves the queue, and:
133
1341. Its pull request records the failure, saying why: which workflow failed
135 on the state, which required check did not report, or, for a conflict,
136 the pull request ahead it collided with and the files.
1372. Its conversation records that it was taken out of the queue, and why: a
138 conflict links the pull request it collided with and each conflicting
139 file, which opens in the pull request's changes.
1403. The entries that were tested on top of it are tested again without it.
141
142A g1t agent's pull request is then sent back to revise, as for any failed
143check, starting from `main` as it is now. The revision counts towards
144**Revisions before asking you**. Once it is ready again, a repository with
145**Merge automatically when ready** on adds it to the queue again by itself;
146otherwise it waits for someone to merge it again. A pull request you or
147your own agent opened is yours to fix and merge again.
148
149## The Merge queue page
150
151Every repository has a **Merge queue** page, at
152`g1t.sh/<workspace>/<repo>/queue`, in the repository's sidebar. It
153refreshes on its own while anything is queued.
154
155**In the queue** lists the entries in order, starting from `main`'s commit.
156Each shows:
157
158| | |
159| --- | --- |
160| State | **Waiting**, **Testing** or **Passed**. |
161| Tested as | `main` and the pull requests merged into it, such as `main + #41 + #44`. |
162| Checks | How its state's checks stand. |
163| Who | The agent or person who made the pull request, and who queued it. |
164| Commit | The tested state's commit. |
165
166**Recently** lists the last 20 that left the queue: **Landed**, **Failed**
167or **Removed**. A failed entry shows why.
168
169## From the API or an agent
170
171The `pull_request` tool's `merge_queue` action, or
172`GET /repos/{owner}/{name}/queue`, returns the queue.
173It is public for a public repository.
174
175```sh
176curl https://api.g1t.sh/repos/acme/web/queue
177```
178
179```json
180{
181 "enabled": true,
182 "active": [
183 {
184 "number": 44,
185 "title": "Add a --shout flag",
186 "agent": "g1t-agent",
187 "state": "testing",
188 "ahead": [41],
189 "base_commit": "8f3c2e1…",
190 "combined_commit": null,
191 "results": [],
192 "enqueued_by": "g1t"
193 }
194 ],
195 "recent": []
196}
197```
198
199| Field | |
200| --- | --- |
201| `enabled` | Whether the repository merges through the queue. |
202| `active` | The entries waiting to land, in order. |
203| `recent` | Those that landed or left, newest first. |
204| `state` | `waiting`, `testing`, `passed`, `failed`, `landed` or `removed`. |
205| `ahead` | The pull requests merged ahead of it in the state being tested. Empty when it was tested on `main` alone. |
206| `base_commit` | The commit of `main` the state was built on. |
207| `combined_commit` | The tested state. |
208| `results` | What building the state recorded, each with `command`, `passed` and `output`. The workflow runs on it are on its commit, `combined_commit`. |
209| `error` | Why it failed: a conflict, a workflow that failed on it, a required check that did not report, or what could not be built. |
210| `enqueued_by` | Who added it: a username, or `g1t` when it was merged automatically. |