GitLab Merge Trains Explained: Keep Main Green at High Velocity
Two MRs that pass alone can break main together. Here's how GitLab merge trains catch that, when they're worth it, and how I keep the train fast instead of stuck.
- #gitlab
- #cicd
- #merge-trains
- #merge-requests
- #velocity
- #automation
Here’s a bug that has burned every fast-moving team I’ve worked with. Two merge requests each pass CI perfectly on their own. They get merged minutes apart. And main is suddenly broken — because neither one was ever tested against the other’s changes.
This is the “semantic merge conflict,” and it’s invisible to normal CI. GitLab merge trains exist specifically to kill it. After running them on busy repos for years, here’s how they work, when they earn their cost, and how to keep the train from grinding to a halt.
The problem merge trains solve
Normal CI tests each MR against the current main. But by the time your MR merges, main may have moved. The combination of your change plus everything that landed while your pipeline ran was never actually tested together.
At low volume this rarely bites. At high volume — dozens of MRs a day touching shared code — it bites constantly, and you get a broken main that blocks everyone until someone reverts.
How a merge train works
A merge train builds each MR against the projected result of every MR ahead of it in the queue. When you add an MR to the train, GitLab runs its pipeline against main plus all the earlier, not-yet-merged MRs combined.
If that combined pipeline passes, the MR merges. If it fails — because it conflicts semantically with something ahead of it — it’s kicked off the train and main stays green. The two-MRs-break-each-other bug becomes impossible to merge.
You enable it in the merge request settings, and once on, the “Merge” button becomes “Add to merge train”:
# Jobs can detect they're running on a train:
test:
script: ./run-tests.sh
rules:
- if: '$CI_MERGE_REQUEST_EVENT_TYPE == "merge_train"'
- if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
The cost: pipeline time matters more than ever
Merge trains have one enemy — slow pipelines. Because each train pipeline depends on the ones ahead, a 40-minute pipeline means throughput collapses under load. The train serializes, and a queue forms behind your slowest CI run.
So merge trains are a forcing function: if you want them, you have to invest in fast pipelines first. Caching, DAG with needs, and parallel test sharding aren’t optional once you’re on a train — they’re what keeps it moving.
Use train-specific optimizations
GitLab lets you skip some redundant work on the train. The most useful is merged results pipelines as the foundation, plus careful use of rules to avoid running expensive jobs twice. Some teams run the full suite on the train but a lighter smoke suite on individual MR pushes, reserving the heavy run for the moment that actually protects main.
You can also tune the train to merge multiple MRs in parallel when they’re independent, rather than strictly one at a time, which helps throughput considerably on a busy repo.
When merge trains are worth it
I reach for merge trains when all of these are true:
- High merge volume — many MRs a day into a shared branch.
- A
mainthat must stay deployable at all times. - Pipelines fast enough that serializing them doesn’t strangle throughput.
If your team merges a handful of MRs a day, merge trains add complexity you don’t need. A protected branch with required pipelines is plenty. Don’t cargo-cult the train just because a bigger company uses it.
Keep the train from getting stuck
The classic failure mode is a flaky test. On a normal MR a flake is annoying; on a merge train it kicks a good MR off and re-shuffles the queue, wasting everyone’s time. So flakiness becomes a high-priority bug, not a “rerun and ignore” nuisance.
A few practices keep mine healthy:
- Quarantine flaky tests aggressively instead of letting them re-shuffle the train.
- Watch train wait time as a key metric — when it climbs, your pipeline is too slow.
- Keep the train short by not adding speculative MRs that aren’t actually ready.
Where AI helps
The subtle bugs merge trains catch — semantic conflicts — are exactly the kind a reviewer can miss by reading two diffs separately. Before adding an MR to a busy train, I’ll paste both changesets into a model and ask: “Do these two changes touch the same behavior in a way that could conflict at runtime even though they don’t conflict textually?” It catches incompatible assumptions a line-by-line review glosses over. I keep GitLab CI prompts for this and route risky MRs through our Code Review tool before they board the train.
The bottom line
Merge trains trade pipeline efficiency for a main branch that simply can’t be broken by concurrent merges. That’s a fantastic trade for high-velocity teams and unnecessary overhead for small ones.
If you adopt them, do the prerequisite work first: make your pipelines fast and your tests reliable. A merge train on top of a slow, flaky pipeline is misery. A merge train on top of a fast, solid one is the thing that lets a big team merge all day without ever breaking the build.
AI suggestions about merge conflicts and pipeline design are assistive, not authoritative. Always confirm train behavior on a real high-volume branch before relying on it.
Download the Free 500-Prompt DevOps AI Toolkit
500 battle-tested, copy-paste AI prompts engineered by a senior systems engineer — every one with fill-in placeholders and safety/back-out notes. Drop your email and it's yours.
- 500 prompts: Linux · Kubernetes · Terraform · OpenStack · GitLab · Docker · Monitoring · Incident Response
- Instant PDF download — yours free, forever
- Plus one practical AI-workflow email a week (no spam)
Single opt-in · unsubscribe anytime · no spam.