diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 077b8580898af5b52b9c1c244d752b702c1792b4..4709bd6d549359626411fa2016a9c7bb47c8ff3d 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -58,9 +58,17 @@ workflow:
         - ${PRE_COMMIT_HOME}
 
 Check licenses:
-  extends: .common_pre_commit
+  extends:
+    - .colorized
+    - .common_pre_commit
   script:
-    - pre-commit run --color=always --hook-stage manual reuse
+    - |
+      # pre-commit run --hook-stage manual reuse
+      pre-commit run --color=always --hook-stage manual reuse || {
+        printf "${RED}You can reproduce this check locally with \`pre-commit run --hook-stage manual reuse\`.
+      See also ${CI_PROJECT_URL}/-/blob/${CI_DEFAULT_BRANCH}/CONTRIBUTING.md#coding-style.\n${DEFAULT}"
+        exit 1
+      }
   rules:
     - if: $CI_PIPELINE_SOURCE == "web"
       when: manual
@@ -68,9 +76,37 @@ Check licenses:
   interruptible: true
 
 Check style:
-  extends: .common_pre_commit
+  extends:
+    - .colorized
+    - .common_pre_commit
+  variables:
+    STYLE_PATCH: style.patch
   script:
-    - pre-commit run --show-diff-on-failure --color=always --all-files
+    - |
+      # pre-commit run --all-files
+      pre-commit run --color=always --all-files || {
+        git diff --ignore-submodules --patch-with-raw > "${STYLE_PATCH}" && {
+          test -s "${STYLE_PATCH}" && {
+            printf "${RED}At least some of the issues can be resolved with the patch (see artifacts):
+        ${CI_JOB_URL}/artifacts/raw/${STYLE_PATCH}.\n${DEFAULT}"
+          } || {
+            printf "${RED}The issues cannot be resolved with a patch.\n${DEFAULT}"
+            rm -f "${STYLE_PATCH}"
+          }
+        } || {
+          printf "${RED}Failed to generate a patch file.\n${DEFAULT}"
+          rm -f "${STYLE_PATCH}"
+        }
+        printf "${RED}You can reproduce this check locally with \`pre-commit run --all-files\`.
+      See also ${CI_PROJECT_URL}/-/blob/${CI_DEFAULT_BRANCH}/CONTRIBUTING.md#coding-style.\n${DEFAULT}"
+        exit 1
+      }
+  artifacts:
+    paths:
+      - ${STYLE_PATCH}
+    expose_as: 'Style Patch'
+    when: on_failure
+
   rules:
     - if: $CI_PIPELINE_SOURCE == "web"
       when: manual
@@ -144,7 +180,7 @@ include:
         printf "${DEFAULT}"
         exit 1
       }
-      rm -rf "${BUILD_LOG}" "${compiler_warnings}"
+      rm -f "${BUILD_LOG}" "${compiler_warnings}"
     - |
       # Check if there are untracked files
       untracked_files=$( \
@@ -154,7 +190,7 @@ include:
         --exclude-standard \
       )
       test -z "${untracked_files}" || {
-        printf "${RED}The job produced unexpected files:\n${untracked_files}\n\
+        printf "${RED}The job produced unexpected files:\n${untracked_files}
       Update the '.gitignore' file.\n${DEFAULT}"
         exit 1
       }
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 3a86addc11af6c128ba291b982e32ebdeb4dd22e..becbb1ec274f17056fdaeb8b0960ae717a8d35fb 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -1,4 +1,4 @@
-# Formatting and linting
+# Coding style
 We use [`pre-commit`](https://pre-commit.com) hooks to maintain a set of
 formatting and linting rules. Although there is a CI job that runs for each
 merge request and checks whether the contribution does not break the rules, we