diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index f3ac32241531741c22d24395777d40aff7a1dab6..04a0e7c67654cb5747cc6c520b58b046be84f0bd 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -5,8 +5,15 @@ variables:
   PRE_COMMIT_HOME: "${CI_PROJECT_DIR}/.cache/pre-commit"
 
 
+before_script:
+  - git config --global --add safe.directory ${CI_PROJECT_DIR}
+  - python3 ./bob/devtools/bootstrap.py -vv build
+  - source ${CONDA_ROOT}/etc/profile.d/conda.sh
+  - conda activate base
+
 # Definition of our build pipeline order
 stages:
+  - qa
   - build
   - deploy
   - pypi
@@ -31,10 +38,6 @@ stages:
     - bob
     - docker
   image: quay.io/condaforge/linux-anvil-cos7-x86_64
-  before_script:
-    - python3 ./bob/devtools/bootstrap.py -vv build
-    - source ${CONDA_ROOT}/etc/profile.d/conda.sh
-    - conda activate base
   artifacts:
     paths:
       - dist/*.zip
@@ -53,10 +56,6 @@ stages:
     - bob
     - macos
     - intel
-  before_script:
-    - python3 ./bob/devtools/bootstrap.py -vv build
-    - source ${CONDA_ROOT}/etc/profile.d/conda.sh
-    - conda activate base
   artifacts:
     paths:
       - ${CONDA_ROOT}/conda-bld/osx-64/*.conda
@@ -70,10 +69,6 @@ stages:
   tags:
     - macos
     - arm
-  before_script:
-    - python3 ./bob/devtools/bootstrap.py -vv build
-    - source ${CONDA_ROOT}/etc/profile.d/conda.sh
-    - conda activate base
   artifacts:
     paths:
       - ${CONDA_ROOT}/conda-bld/osx-arm64/*.conda
@@ -82,6 +77,25 @@ stages:
     key: "macos-arm-cache"
 
 
+code_quality:
+  tags:
+    - docker
+  stage: qa
+  image: quay.io/condaforge/linux-anvil-cos7-x86_64
+  cache:
+    key: "$CI_JOB_STAGE"
+    paths:
+      - ${PRE_COMMIT_HOME}
+
+  before_script:
+    - git config --global --add safe.directory ${CI_PROJECT_DIR}
+
+  script:
+    - sudo yum install -y git python3-pip
+    - pip3 install pre-commit
+    - pre-commit run --all-files --show-diff-on-failure
+
+
 build_linux_bob_devel:
   extends: .build_linux_template
   variables:
@@ -107,8 +121,6 @@ build_linux_deps:
 build_linux_bob_devtools:
   extends: .build_linux_template
   script:
-    - pip install pre-commit
-    - pre-commit run --all-files --show-diff-on-failure
     - python3 ./bob/devtools/build.py -vv build-devtools --twine-check
 
 build_macos_intel_bob_devel:
@@ -150,28 +162,24 @@ build_macos_arm_deps:
 build_macos_intel_bob_devtools:
   extends: .build_macos_intel_template
   script:
-    - pip install pre-commit
-    - pre-commit run --all-files --show-diff-on-failure
     - python3 ./bob/devtools/build.py -vv build-devtools
 
 build_macos_arm_bob_devtools:
   extends: .build_macos_arm_template
   script:
-    - pip install pre-commit
-    - pre-commit run --all-files --show-diff-on-failure
     - python3 ./bob/devtools/build.py -vv build-devtools
 
 
 # Deploy targets
-.deploy_template:
-  stage: deploy
-  script:
+.release_template:
+  before_script:
     - python3 ./bob/devtools/bootstrap.py -vv local base
     - source ${CONDA_ROOT}/etc/profile.d/conda.sh
     - conda activate base
-    - bdt ci base-deploy -vv
-    - bdt ci deploy -vv
+
+  after_script:
     - bdt ci clean -vv
+
   dependencies:
     - build_linux_bob_devel
     - build_linux_deps
@@ -182,6 +190,7 @@ build_macos_arm_bob_devtools:
     - build_macos_arm_bob_devel
     - build_macos_arm_deps
     - build_macos_arm_bob_devtools
+
   tags:
     - docker
     - bob
@@ -190,6 +199,15 @@ build_macos_arm_bob_devtools:
       - miniconda.sh
 
 
+.deploy_template:
+  extends: .release_template
+
+  stage: deploy
+  script:
+    - bdt ci base-deploy -vv
+    - bdt ci deploy -vv
+
+
 deploy_beta:
   extends: .deploy_template
   environment: beta
@@ -207,6 +225,7 @@ deploy_stable:
 
 
 pypi:
+  extends: .release_template
   stage: pypi
   environment: pypi
   only:
@@ -214,24 +233,4 @@ pypi:
   except:
     - branches
   script:
-    - python3 ./bob/devtools/bootstrap.py -vv local base
-    - source ${CONDA_ROOT}/etc/profile.d/conda.sh
-    - conda activate base
     - bdt ci pypi -vv dist/*.zip
-    - bdt ci clean -vv
-  dependencies:
-    - build_linux_bob_devel
-    - build_linux_deps
-    - build_linux_bob_devtools
-    - build_macos_intel_bob_devel
-    - build_macos_intel_deps
-    - build_macos_intel_bob_devtools
-    - build_macos_arm_bob_devel
-    - build_macos_arm_deps
-    - build_macos_arm_bob_devtools
-  tags:
-    - bob
-    - docker
-  cache:
-    paths:
-      - miniconda.sh
diff --git a/bob/devtools/data/gitlab-ci/docs.yaml b/bob/devtools/data/gitlab-ci/docs.yaml
index 15770377f756bd197c139f68fa136c2e9cc4c64b..7cac3f2fac84ab16714b7098205a432a8402e2fe 100644
--- a/bob/devtools/data/gitlab-ci/docs.yaml
+++ b/bob/devtools/data/gitlab-ci/docs.yaml
@@ -29,6 +29,7 @@ stages:
     - python3 bootstrap.py -vv channel base
     - source ${CONDA_ROOT}/etc/profile.d/conda.sh
     - conda activate base
+    - git config --global --add safe.directory ${CI_PROJECT_DIR}
     - conda clean --all
   cache:
     paths:
diff --git a/bob/devtools/data/gitlab-ci/nightlies.yaml b/bob/devtools/data/gitlab-ci/nightlies.yaml
index e0c268ec49675bda8a0fe84b2f44e74ed209619c..82eff798d4d69f84449161e9d740410478cadf2a 100644
--- a/bob/devtools/data/gitlab-ci/nightlies.yaml
+++ b/bob/devtools/data/gitlab-ci/nightlies.yaml
@@ -22,6 +22,7 @@ stages:
     - curl --silent "${BOOTSTRAP}" --output "bootstrap.py"
     - python3 bootstrap.py -vv channel base
     - source ${CONDA_ROOT}/etc/profile.d/conda.sh
+    - git config --global --add safe.directory ${CI_PROJECT_DIR}
     - conda activate base
     - conda clean --all
   cache:
diff --git a/bob/devtools/data/gitlab-ci/noarch.yaml b/bob/devtools/data/gitlab-ci/noarch.yaml
index 41db138151687f2dc85d1c0ec5eae6ac3d40bd83..a3ffb0139d6dd01156f50aeb4b992d1b4f14f284 100644
--- a/bob/devtools/data/gitlab-ci/noarch.yaml
+++ b/bob/devtools/data/gitlab-ci/noarch.yaml
@@ -25,6 +25,7 @@ stages:
     - python3 bootstrap.py -vv channel base
     - source ${CONDA_ROOT}/etc/profile.d/conda.sh
     # for conda inspect during builds (on macos)
+    - git config --global --add safe.directory ${CI_PROJECT_DIR}
     - conda activate base
     - bdt ci check -vv
     - conda clean --all
diff --git a/bob/devtools/data/gitlab-ci/python-package.yaml b/bob/devtools/data/gitlab-ci/python-package.yaml
index f86bb1178ec35d099bec57ea517ec6fedf752131..3bb9f85142c111450d963b1a15d6840269b8fa68 100644
--- a/bob/devtools/data/gitlab-ci/python-package.yaml
+++ b/bob/devtools/data/gitlab-ci/python-package.yaml
@@ -27,6 +27,7 @@ build:
     - docker
   stage: build
   before_script:
+    - git config --global --add safe.directory ${CI_PROJECT_DIR}
     - pip install twine pre-commit sphinx sphinx-rtd-theme
   script:
     - "[ -r .pre-commit-config.yaml ] && pre-commit run --all-files --show-diff-on-failure --verbose"
diff --git a/bob/devtools/data/gitlab-ci/single-package.yaml b/bob/devtools/data/gitlab-ci/single-package.yaml
index ff4f38cd03fdf447ec47252d48024bce7d09f46d..346579238f69bf625786224179b5ce15198be61c 100644
--- a/bob/devtools/data/gitlab-ci/single-package.yaml
+++ b/bob/devtools/data/gitlab-ci/single-package.yaml
@@ -26,6 +26,7 @@ stages:
     - source ${CONDA_ROOT}/etc/profile.d/conda.sh
     # for conda inspect during builds (on macos)
     - conda activate base
+    - git config --global --add safe.directory ${CI_PROJECT_DIR}
     - bdt ci check -vv
     - conda clean --all
   cache: