Does the rules:changes work properly?
I have the following gitlab-ci pipeline:
stages:
- choose
choose:
stage: choose
rules:
- if: $CI_COMMIT_BRANCH
changes:
paths:
- file1
variables:
variable: "name1"
- if: $CI_COMMIT_BRANCH
changes:
paths:
- file2
variables:
variable: "name2"
- if: $CI_COMMIT_BRANCH
changes:
paths:
- file3
variables:
variable: "name3"
script:
- echo "variable=$variable" >> build.env && cat build.env
- echo "changed files = " && git diff-tree --no-commit-id --name-only -r $CI_COMMIT_SHA
artifacts:
reports:
dotenv: build.env
Everything works correctly when I add something to one of the files. In this case $variable
equals name of the file that has been changed.
But in case when I delete something in the file 2 or file 3 (without adding any info to the files!), then the $variable
equals name1
but git diff-tree --no-commit-id --name-only -r $CI_COMMIT_SHA
correctly shows that there were only changes in file 2 or file 3. I expected that $variable
would be equal the name of the changed file (2 or 3).
So what’s the problem with rules:changes
or I don’t get something?
- GitLab Enterprise Edition 15.11.2-ee
- Runner gitlab-runner 15.1.0
Hi @Butovoboy
welcome to the GitLab Community forum! 
The problem you’re encountering seems to be related to the order in which your rules are evaluated.
GitLab’s CI/CD pipeline evaluates rules in the order they are defined until it finds a match, and then it stops.
This means that if more than one rule could potentially match a commit, only the first matching rule will be applied.
In your case, if you delete something in file2
or file3
, the first rule matches because file1
has not changed, and the $variable
is set to name1
.
To resolve this issue, you might consider revising your CI job or reordering your rules. For example, if you change the rules for file2
and file3
come before the rule for file1
. That way, if file2
or file3
are changed, their rules will match first and set $variable
accordingly.
You can find more detailed information about the rules:changes
keyword in the GitLab documentation.
I hope this helps! Let us know if you have any other questions. Happy coding! 
1 Like
Hi @gitlab-greg!
Thanks a lot for your answer!
But I face with this issue even if I delete something only in file2
, and keep file1
unchanged. I thought that in this case the first rule would not match, but the second does and the $variable
will be equal name2
.
On the other hand, when I add something only to file2 everything goes right and $variable
equals name2
.
So I can’t figure out where is the problem in my pipeline.
Thank you, Greg, for trying to help me 
I found out where it’s all.
When you branch from master, gitlab-ci thinks that all files file1, file2 and file3 have been changed so the first if is true and $variable
equals name1
.
So I modified the pipeline to compare files to master branch adding compare_to: 'refs/heads/master'
. But in this case stage choose does not work when you merge dev branch to master so in this case I added another three ifs and now the whole pipeline looks like this:
stages:
- choose
choose:
stage: choose
rules:
- if: $CI_COMMIT_BRANCH
changes:
compare_to: 'refs/heads/master'
paths:
- file1
variables:
variable: "name1"
- if: $CI_COMMIT_BRANCH
changes:
compare_to: 'refs/heads/master'
paths:
- file2
variables:
variable: "name2"
- if: $CI_COMMIT_BRANCH
changes:
compare_to: 'refs/heads/master'
paths:
- file3
variables:
variable: "name3"
- if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH'
changes:
paths:
- file1
variables:
variable: "name1"
- if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH'
changes:
paths:
- file2
variables:
variable: "name2"
- if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH'
changes:
paths:
- file3
variables:
variable: "name3"
script:
- echo "variable=$variable" >> build.env && cat build.env
artifacts:
reports:
dotenv: build.env