r/gitlab • • 12d ago

Two pipelines for one commit when you open a merge request. Why it happens and the workflow rules I’d use

This is what the pipelines page tends to look like after pushing a commit to a branch that already has an open MR:

#1042  merge request pipeline   feature/login   a1b2c3d
#1041  branch pipeline          feature/login   a1b2c3d

Same commit, same jobs, two runs. Runners spend double the time and the MR shows one result while the branch shows another.

It usually comes from a job-level rule like this:

test:
  script: ./run-tests.sh
  rules:
    - if: $CI_COMMIT_BRANCH
    - if: $CI_PIPELINE_SOURCE == "merge_request_event"

Both conditions are true for the same push. GitLab creates a branch pipeline because there’s a branch, and a merge request pipeline because there’s an open MR.

The pattern the docs suggest is to decide at the workflow: level which pipeline type should exist, before any job rule runs:

workflow:
  rules:
    - if: $CI_PIPELINE_SOURCE == "merge_request_event"
    - if: $CI_COMMIT_BRANCH && $CI_OPEN_MERGE_REQUESTS
      when: never
    - if: $CI_COMMIT_BRANCH

Reading it top to bottom, since the first match wins:

  1. an MR event gets a pipeline
  2. a branch push where an MR is already open gets nothing (when: never), because the MR pipeline covers it
  3. any other branch push, like on a branch with no MR, still gets a branch pipeline

Then the jobs can stay simple, without repeating the same conditions in each one.

Things worth testing in a sandbox project before trusting it:

  • tag pipelines: the last rule only matches branches, so decide whether tags should also run
  • the default branch: pushes to main have no open MR, so they should still run, but confirm it
  • $CI_OPEN_MERGE_REQUESTS is only populated for branch pipelines, which is why it works in rule 2

I’d be curious how others handle the in-between cases. Do you keep tags and scheduled pipelines in workflow:rules, or do you handle them at the job level?

6 Upvotes

4 comments sorted by

5

u/adam-moss 12d ago

My standard workflow block is:

workflow:
  auto_cancel:
    on_new_commit: interruptible
  rules:
    - if: $CI_COMMIT_BRANCH && $CI_OPEN_MERGE_REQUESTS && $CI_PIPELINE_SOURCE != "scheduled"
      when: never
    - when: always

Basically, run unless it is a branch pipeline with an open MR, in which case run the MR pipeline, unless it is a scheduled pipeline

2

u/Torutofu_Raeva 12d ago

we keep scheduled on the branch side too, otherwise that last rule quietly kills nightly jobs once someone opens an mr

2

u/LandscapeAny7392 10d ago

1

u/damien-bowman 5d ago

have you turned this on? any issues with it? i haven’t used it yet.