How to trigger a job when specific files have changed at any commit in the branch

I have a CI pipeline that uses a template for the build job and a couple of other jobs that utilize that. Something similar to this:

.build_job:
  stage: build
  script:
    - echo "Build $APP"

build-one:
  extends: .build_job
  before_script:
    - APP=one
  rules:
    - changes:
      - src/one/**/*

build-two:
  extends: .build_job
  before_script:
    - APP=two
  rules:
    - changes:
      - src/two/**/*

The intention is to only build the components of our software that have changed.

The problem is that job will only trigger if a file in the specified directory has changed for the current commit. I would like to have that job run if a file in the specified directory has changed at any commit in the branch. So if I change something in src/one/* and push that commit, it would run the build-one job. But if, for the next push, I change something outside that I would like that job to still run. For example, I might change the top level CMakeLists.txt file and push that change. I would like that build-one job to still run.

Is this possible?

Pipelines are triggered per-commit and don’t know what happened in the past. But you can have multiple conditions which are evaluated with “OR”, so you can do

rules:
  - changes:
    - src/one/**/*
    - ./*

I don’t know if it helps.

Thanks, but it does not. I tried using a bash conditional in the script, but the problem is that there’s no way of determining the source branch of the current branch. There’s no $CI_... variable for that and git does not store that info anywhere. If I had that info, I could do something like

if git diff --quiet $CI_COMMIT_BRANCH <SOURCE_BRANCH> -- "src/one/**"; then
...
fi

I might just have to settle for checking each commit and building everything on a merge request.

If you need some really complex logic which files are changed you need to use Merge Requests where you can compare diff between branches:

- if [ "${CI_MERGE_REQUEST_TARGET_BRANCH_NAME}x" != "x" ]; then git fetch origin "${CI_MERGE_REQUEST_TARGET_BRANCH_NAME}"; export FILES=$(git diff --name-only origin/${CI_MERGE_REQUEST_TARGET_BRANCH_NAME}...); fi
- if [ "${CI_COMMIT_REF_NAME}" = "${CI_DEFAULT_BRANCH}" ]; then git fetch origin "${CI_COMMIT_REF_NAME}"; export FILES=$(git diff --name-only "${CI_COMMIT_BEFORE_SHA}" HEAD); fi

to get list of changed files.
The first line is for MR, the second for branch commits comparing against previous commit.

In case you’re not tied to GitLab’s own pipelines feature and want more control you could consider CircleCI’s dynamic configuration feature (disclaimer - I work for CircleCI)

It essentially splits the pipeline into two parts, where in the first part you can evaluate special conditions like paths that have diverged from a specific branch, and then either toggle parameters in the continuation of the pipeline, or even generate your own config on the fly.

I found it particularly useful for monorepo-style projects where you might have a frontend, API, or backend in the same repo.

I am tied to it for now. But thank you.