From 4c0ef93a026539fbee59142df2e2757e47f4bf62 Mon Sep 17 00:00:00 2001 From: Mehdi ABAAKOUK Date: Wed, 29 Jul 2026 13:08:44 +0200 Subject: [PATCH] docs: state that a renamed file counts at both of its paths The rename semantics of file-pattern scopes, `barrier_files` and the `files` / `added-files` / `removed-files` / `modified-files` condition attributes were written down nowhere, so the only way to learn that a rename is treated as a removal at the source plus an addition at the destination was to try it. Document the rule where each surface is described, with the `git mv` example spelled out attribute by attribute, and note that `#files` is GitHub's own changed-file count and so does not equal the length of `files` on a pull request containing a rename. While verifying the rename example against the engine's actual glob matcher, two things turned out to be wrong on this page and are fixed here too: - the rename example used `git mv api/auth.py web/auth.py`, but `web/auth.py` matches none of the `frontend` patterns (they are `.js`/`.jsx`/`.ts`/`.tsx`), so it reported one scope, not both; - the multi-language example declared `apps/web/**/*.{js,jsx,ts,tsx}`. Brace expansion is not supported by the matcher, so that pattern matched nothing and the `frontend` scope in that example could never fire. Expanded into one pattern per extension. Related to MRGFY-8248 Change-Id: I6cda667056c5aef19df77caace5438d458b92c7a --- src/content/docs/configuration/conditions.mdx | 19 ++++++++++++++++++ src/content/docs/merge-queue/scopes.mdx | 3 +++ .../docs/merge-queue/scopes/file-patterns.mdx | 20 ++++++++++++++++++- 3 files changed, 41 insertions(+), 1 deletion(-) diff --git a/src/content/docs/configuration/conditions.mdx b/src/content/docs/configuration/conditions.mdx index 34cb580325..63ed3cc2d3 100644 --- a/src/content/docs/configuration/conditions.mdx +++ b/src/content/docs/configuration/conditions.mdx @@ -90,6 +90,25 @@ into Mergify attributes and a read-only set loaded from GitHub. +#### Renamed Files + +A rename touches two paths. Mergify treats it the way `git` does with rename detection +turned off: the file is **removed** at its previous path and **added** at its new one. + +For `git mv critical/guard.txt ignored/guard.txt`: + +- `files` contains both `critical/guard.txt` and `ignored/guard.txt` +- `removed-files` contains `critical/guard.txt` +- `added-files` contains `ignored/guard.txt` +- `modified-files` contains neither, even when the move also changed the file's content +- `scope` reports the scopes owning both paths + +So `removed-files ~= ^critical/` matches a pull request that moves a file out of +`critical/`, and a `-files ~= ^critical/` gate is not satisfied by one. + +`#files` is GitHub's own changed-file count, which counts a renamed file **once**. It +therefore does not equal the length of `files` on a pull request containing a rename. + ### GitHub Rulesets and Branch Protection Attributes Mergify loads these attributes from the GitHub rulesets and branch protection diff --git a/src/content/docs/merge-queue/scopes.mdx b/src/content/docs/merge-queue/scopes.mdx index 47e4122af6..897940bd81 100644 --- a/src/content/docs/merge-queue/scopes.mdx +++ b/src/content/docs/merge-queue/scopes.mdx @@ -217,6 +217,9 @@ constraints: through the API instead (see below), and a configuration with no source has no scopes to impact. Mergify rejects `barrier_files` in either case. +A renamed file is matched at both of its paths, so moving a file *out of* a barrier pattern makes +the pull request a barrier too: the barrier file is gone from the location you declared. + You can also manage these patterns from the dashboard: the **Barrier files** editor in the queue configuration **Scopes** section edits the same `barrier_files` filters for file-pattern scopes. diff --git a/src/content/docs/merge-queue/scopes/file-patterns.mdx b/src/content/docs/merge-queue/scopes/file-patterns.mdx index 86475f307f..f440b61bfd 100644 --- a/src/content/docs/merge-queue/scopes/file-patterns.mdx +++ b/src/content/docs/merge-queue/scopes/file-patterns.mdx @@ -108,7 +108,10 @@ scopes: - services/users/**/*.go frontend: include: - - apps/web/**/*.{js,jsx,ts,tsx} + - apps/web/**/*.js + - apps/web/**/*.jsx + - apps/web/**/*.ts + - apps/web/**/*.tsx shared-config: include: - config/**/* @@ -139,6 +142,21 @@ the merge queue batch. This ensures: - Batching decisions remain consistent even as the queue changes - Tests run for the correct scopes regardless of what else is in the batch +### Renamed Files Count at Both Paths + +A rename touches two paths: the file disappears from where it was and appears where it +went. Mergify matches your patterns against **both**, so moving a file out of a scope +reports that scope just as deleting the file would. + +With the multi-language scopes above, `git mv services/api/settings.py config/settings.py` +reports **both** `python-api` (the path the file left) and `shared-config` (the path it +arrived at). That matters when a scope guards something: a pull request that moves a file +out of `services/api/` is a change to `services/api/`, so the `python-api` scope's CI jobs +and batching rules apply to it. + +The same rule applies to `barrier_files`: renaming a file out of a barrier pattern makes +the pull request a barrier, because the barrier file is gone from its declared location. + ### Path Filtering vs Scopes GitHub Actions offers path filtering (`on.pull_request.paths`), but it has critical limitations in