GitLab CI rules:changes Always Matches - Detached MR Has No Compare Base
rules:changes diffs the current commit against a base. In branch pipelines that base is the previous commit; in detached MR pipelines without compare_to, GitLab has no reliable base and treats changes as matching, so the job always runs.
What this error means
A job guarded by rules:changes runs on every pipeline regardless of which files changed, or never runs as expected. It happens specifically in merge-request (detached) pipelines.
# Detached MR pipeline: rules:changes evaluates to "matched"
# even though none of the listed paths changed in this MR.
build:
rules:
- changes:
- src/**/*Common causes
No compare base in a detached pipeline
A detached MR pipeline (no merged-results pipeline) lacks a stable base to diff against, so GitLab conservatively treats changes as matched.
Missing compare_to for branch pipelines
On branch pipelines, changes diffs against the previous commit on the branch, which may not reflect the full set of changes you intend to gate on.
How to fix it
Set changes:compare_to explicitly
Pin the base ref so the diff is deterministic for both branch and MR pipelines.
build:
rules:
- changes:
paths:
- src/**/*
compare_to: 'refs/heads/main'Use merged results pipelines
- Enable merged results pipelines so MRs get a real base from the target branch.
- Confirm CI_MERGE_REQUEST_TARGET_BRANCH_NAME is populated in the job log.
- Re-test the rule by changing an out-of-scope file and verifying the job is skipped.
How to prevent it
- Always set compare_to when using rules:changes on protected paths.
- Prefer merged-results pipelines so MRs have a stable compare base.
- Verify gating behavior with a no-op change that should skip the job.