GitLab CI runs even when `changes:` field doesn't match any files
14:00 12 Dec 2025

I want my GitLab CI job to run only when one of my doc files at docs/**/*.md or docs/**/*.mdx changes. When I put these patterns in the rules:changes: field, the job always seems to run, even when there are no changes to these files.

I have a minimal reproduction in https://gitlab.com/timothymcmackin/gitlabcichangestest.

In job #12422985923 for MR !1, there are no changes to MD/MDX files in the branch/MR but the job runs anyway. There's a call to the gitlab API to get the changed MD/MDX files that returns nothing.

My CI file looks like this. How can I make sure that the job runs only when a doc file changes in the MR?

image: alpine:3.21.2

stages:
- test

tests:
  stage: test
  image: node:20
  # Run only if the MR changed some MD or MDX files
  # But it always runs on the initial MR creation
  rules:
  - changes:
    - 'docs/**/*.md'
    when: on_success

  script:

  # Get comma-separated list of changed files
  - apt update && apt install -y jq
  # Call gitlab API to get MR metadata
  - curl "$CI_API_V4_URL/projects/$CI_PROJECT_ID/merge_requests/$CI_MERGE_REQUEST_IID/changes" > results.json
  # Get all changed files
  - jq -r '.changes[].new_path' results.json > all_changed_files.txt
  # Filter to MD/MDX files
  - touch changed_md_files.txt
  - grep -E '^.*\.mdx?$' all_changed_files.txt > changed_md_files.txt || echo "NULL" > changed_md_files.txt
  # Change to comma-separated list
  - tr < changed_md_files.txt '\n' ',' > comma_separated.txt
  # Remove trailing comma (important, or else it shows up as a blank item at the end of the list and includes every file)
  - sed -i 's/,$//' comma_separated.txt
  # Set an environment variable to use later
  - export CHANGED_FILES=$(cat comma_separated.txt)
  - echo $CHANGED_FILES
gitlab-ci