GitLab CI中rules配合changes可精准触发作业:仅当指定目录文件变更时执行,适用于MR和push流水线,但不支持schedule等类型;changes基于代码差异而非文件系统监听,需结合if条件与多rules顺序控制实现包含/排除逻辑。

在 GitLab CI 中,用 rules 配合 changes 实现“仅当某目录下文件变动时才触发对应 job”,是精准控制流水线执行的关键技巧。核心在于:GitLab 会基于当前 pipeline 的 commit 范围(如 merge request 的 source branch 对比 target branch),检查指定路径是否发生了变更。
明确 changes 的作用范围
changes 不是监听文件系统变化,而是比较本次 pipeline 所关联的代码差异(例如 MR 的 diff 或 push 的 commit diff)。它只在以下场景生效:
- Merge Request pipeline(最常用、最可靠)
- Push pipeline(需注意:对全量 push 有效,但对单 commit push 也只比对该 commit 与父提交的差异)
- 手动触发(
changes默认不生效,除非显式指定include: ['merge_request']或使用workflow: rules控制 pipeline 创建时机)
⚠️ 注意:changes 在 schedule、pipeline(API 触发)、external 等类型 pipeline 中**不工作**。
基础写法:按目录匹配触发 job
在 job 级别使用 rules:changes,路径支持 glob 模式(类似 shell):
build-frontend:
image: node:18
script: npm ci && npm run build
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
changes:
- "frontend/**/*"
- if: $CI_PIPELINE_SOURCE == "push" && $CI_COMMIT_TAG == null
changes:
- "frontend/**/*"说明:
-
"frontend/**/*"匹配frontend/下所有子目录和文件(包括frontend/a.js、frontend/src/main.ts) - 第一段规则确保 MR 中只要 frontend 目录有改动就构建;第二段覆盖普通 push 场景(排除 tag 构建)
- 若只想匹配文件(不含目录创建/删除),可写
"frontend/**/*.{js,ts,css,html}"
组合多个条件:避免误触发
单靠 changes 可能不够——比如你希望“仅当 frontend 改动 且 当前是 MR”才运行,同时排除 draft MR:
deploy-staging:
script: ./scripts/deploy.sh staging
rules:
- if: >
$CI_PIPELINE_SOURCE == "merge_request_event" &&
$CI_MERGE_REQUEST_DRAFT == "false"
changes:
- "frontend/**/*"
- "infra/staging/**/*"关键点:
-
if和changes是“与”关系:两者都满足 job 才启用 - 可以写多个
changes条目,表示“任意一个路径匹配即满足”(逻辑或) -
if表达式换行需用>+ 缩进,提升可读性
高级技巧:排除无关变更 & 多目录协同判断
有时需“包含 A 目录,但排除 B 目录下的特定文件”——GitLab 原生不支持 exclude,但可用多条 rules 拆解:
test-backend:
script: pytest tests/backend/
rules:
# 允许 backend 目录变更(含其子目录)
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
changes:
- "backend/**/*"
# 显式跳过 docs/ 下的变更(即使 backend/ 也有改动,只要 docs/ 有改就不跑)
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
changes:
- "docs/**/*"
when: never原理:GitLab rules 按顺序匹配,第一条满足即启用 job;第二条若也满足(即 docs 有改动),则因 when: never 直接跳过该 job。等效于“backend 有改 且 docs 无改”。
其他实用路径写法:
-
"*.md"—— 仓库根目录下的所有 .md 文件 -
"src/**/package.json"—— src 下任意深度的 package.json -
"Dockerfile"—— 根目录 Dockerfile(注意大小写敏感)
不复杂但容易忽略:始终用 MR pipeline 测试 changes 行为,push pipeline 要确认 commit 范围是否符合预期;路径匹配区分大小写;修改 .gitlab-ci.yml 本身不会触发自身定义的 changes 规则(它走的是“配置变更”路径,需用 workflow: rules 单独控制)。


















