Optimistic merging parallelizes tests but still runs one CI job per PR. For projects with very slow test suites — think 45 minutes to an hour — even parallel jobs are expensive. Batching takes a different approach: instead of testing PRs one at a time, it groups them together and tests the whole group as a single unit.
The "Bus" Method
Tools like Bors-NG (used by the Rust programming language project) and Prow/Tide (used by the Kubernetes project) implement batching. The mechanics:
- The queue accumulates
Napproved PRs (e.g.,N = 10). - It creates a single temporary branch:
main + PR1 + PR2 + ... + PR10. - It runs the test suite once on this combined branch.
- Success: All 10 PRs merge to
main. You ran 1 CI job instead of 10. 90% cost reduction. - Failure: The system doesn't know which PR caused the failure. It performs a binary bisect:
- Split into two batches:
[PR1–PR5]and[PR6–PR10]. Test both. - The failing half is split again:
[PR1–PR2],[PR3–PR5]. Test both. - Continue until the single bad PR is isolated, ejected, and the rest are merged.
- Split into two batches:
In the worst case (one bad PR in a batch of 10), bisection requires log₂(10) ≈ 4 additional CI runs to isolate the culprit. You still save 5 CI runs compared to testing each PR individually.
When to Use Batching vs. Optimistic Merging
| Scenario | Recommended Strategy |
|---|---|
| Fast CI (< 5 min), high PR volume | Optimistic merging |
| Slow CI (> 30 min), high pass rate | Batching |
| Slow CI, unknown pass rate | Optimistic merging with small depth |
| Kubernetes-scale (hundreds of PRs/day) | Batching with bisect (Tide) |