diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 13a2aa9239..86cd0db448 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -15,6 +15,7 @@ include:
 
 stages:
   - 'preparation'
+  - 'check'
   - 'build'
   - 'test'
   # Use the resulting binaries
@@ -34,8 +35,7 @@ variables:
 
   FEDORA_AMD64_SUFFIX: 'amd64/fedora'
   DEBIAN_AMD64_SUFFIX: 'amd64/debian'
-  INDENT_AMD64_SUFFIX: 'amd64/gst-indent'
-  COMMITLINT_AMD64_SUFFIX: 'amd64/commitlint'
+  CHECKS_AMD64_SUFFIX: 'amd64/checks'
   WINDOWS_AMD64_SUFFIX: 'amd64/windows'
   ABI_CHECK_AMD64_SUFFIX: 'amd64/abi-check'
 
@@ -200,41 +200,23 @@ debian amd64 docker:
   # (which has faster network connectivity to the registry).
   tags: [ 'placeholder-job' ]
 
-.gst-indent image:
+.checks image:
   tags: [ 'placeholder-job' ]
   variables:
     FDO_DISTRIBUTION_VERSION: 'bookworm'
-    FDO_REPO_SUFFIX: "$INDENT_AMD64_SUFFIX"
-    FDO_DISTRIBUTION_TAG: "$INDENT_TAG-$GST_UPSTREAM_BRANCH"
-    FDO_DISTRIBUTION_PACKAGES: 'curl indent git findutils ca-certificates'
-    FDO_DISTRIBUTION_EXEC: 'ci/docker/indent/prepare.sh'
+    FDO_REPO_SUFFIX: "$CHECKS_AMD64_SUFFIX"
+    FDO_DISTRIBUTION_TAG: "$CHECKS_TAG-$GST_UPSTREAM_BRANCH"
+    FDO_DISTRIBUTION_PACKAGES: 'curl git findutils ca-certificates python3-pip'
+    FDO_DISTRIBUTION_EXEC: 'bash ci/docker/checks/prepare.sh'
 
-gst-indent amd64 docker:
+checks amd64 docker:
   extends:
-    - '.gst-indent image'
+    - '.checks image'
     - '.fdo.container-build@debian'
   stage: 'preparation'
   # Do not depend on the trigger, as we want to run indent always
   needs: []
 
-.commitlint image:
-  tags: [ 'placeholder-job' ]
-  variables:
-    FDO_DISTRIBUTION_VERSION: '37'
-    FDO_REPO_SUFFIX: "$COMMITLINT_AMD64_SUFFIX"
-    FDO_DISTRIBUTION_TAG: "$LINT_TAG-$GST_UPSTREAM_BRANCH"
-    FDO_DISTRIBUTION_PACKAGES: 'python3-pip git'
-    FDO_DISTRIBUTION_EXEC: 'ci/docker/lint/prepare.sh'
-    FDO_USER: "ciuser"
-
-commitlint docker:
-  extends:
-    - '.commitlint image'
-    - '.fdo.container-build@fedora'
-  stage: 'preparation'
-  # Do not depend on the trigger, as we want to run indent always
-  needs: []
-
 windows amd64 docker:
   stage: "preparation"
   timeout: '3h'
@@ -287,66 +269,26 @@ abi-check docker:
     - 'fedora amd64 docker'
 
 # ---- Preparation ----- #
-#
-# gst-indent!!
-#
-gst indent:
+pre-commit checks:
   extends:
-    - '.gst-indent image'
-    - '.fdo.suffixed-image@debian'
-  stage: 'preparation'
+    - '.checks image'
+    - '.fdo.suffixed-image@fedora'
+  stage: 'check'
   needs:
-    - job: 'gst-indent amd64 docker'
+    - job: 'checks amd64 docker'
       artifacts: false
-  script:
-    - ./scripts/check-format-c
-    - ./scripts/format-csharp --check
-    # We want both wraps to use the same version, overkill to create a separate job for this
-    - cmp subprojects/gtk-sharp.wrap subprojects/gstreamer-sharp/subprojects/gtk-sharp.wrap
-  rules:
-    - !reference [.upstream-branch-rules, rules]
-    - if: '$CI_PROJECT_NAMESPACE != "gstreamer" || $CI_COMMIT_BRANCH != $GST_UPSTREAM_BRANCH'
-      when: 'always'
-
-rustfmt:
-  extends:
-    - '.fedora image'
-    - '.fdo.suffixed-image@fedora'
-  stage: 'preparation'
-  needs:
-    - "fedora amd64 docker"
-  tags: [ 'placeholder-job' ]
-  script:
-    - export RUSTUP_HOME="/usr/local/rustup"
-    - export PATH="/usr/local/cargo/bin:$PATH"
-    - ./scripts/format-rust --check
-  rules:
-    - changes:
-        compare_to: "$GST_UPSTREAM_BRANCH"
-        paths:
-          - .gitlab-ci.yml
-          - .gitlab-image-tags.yml
-          - subprojects/gstreamer/**/*.rs
-          - subprojects/gst-examples/**/*.rs
-          - ci/**/*
-          - ./scripts/format-rust
-
-commitlint:
-  extends:
-    - '.commitlint image'
-    - '.fdo.suffixed-image@fedora'
-  stage: 'preparation'
   variables:
     GIT_STRATEGY: fetch
     GIT_DEPTH: 100
-  needs:
-    - job: 'commitlint docker'
-      artifacts: false
-  before_script:
-    - git config --global --add safe.directory $CI_PROJECT_DIR
+    PRE_COMMIT_HOME: '/cache/${CI_PROJECT_NAMESPACE}/pre-commit'
+    RUSTUP_HOME: '/usr/local/rustup'
+    before_script:
+      git config --global --add safe.directory $CI_PROJECT_DIR
   script:
+    - export PATH="/usr/local/cargo/bin:$PATH"
     - echo $CI_MERGE_REQUEST_DIFF_BASE_SHA
     - gitlint --commits $CI_MERGE_REQUEST_DIFF_BASE_SHA..HEAD
+    - pre-commit run --show-diff-on-failure --from-ref $CI_MERGE_REQUEST_DIFF_BASE_SHA --to-ref HEAD
   rules:
     # Only run on MR as we need CI_MERGE_REQUEST_DIFF_BASE_SHA to know
     # what commits to check
diff --git a/.gitlab-image-tags.yml b/.gitlab-image-tags.yml
index 87196acabd..73bba18ef2 100644
--- a/.gitlab-image-tags.yml
+++ b/.gitlab-image-tags.yml
@@ -9,9 +9,7 @@ variables:
 
   DEBIAN_TAG:  '2025-01-11.0'
 
-  INDENT_TAG: '2024-05-28.0'
-
-  LINT_TAG: '2024-02-20.0'
+  CHECKS_TAG: '2025-01-22.0'
 
   ABI_CHECK_TAG: '2025-01-29.0'
 
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
new file mode 100644
index 0000000000..75339faa4e
--- /dev/null
+++ b/.pre-commit-config.yaml
@@ -0,0 +1,27 @@
+fail_fast: false
+repos:
+-   repo: https://github.com/jorisroovers/gitlint
+    rev: v0.19.1
+    hooks:
+    -   id: gitlint-ci
+-   repo: local
+    hooks:
+    # Use dotnet format installed on your machine
+    -   id: dotnet-format
+        name: dotnet-format
+        language: system
+        files: ^subprojects/gstreamer-sharp/.*
+        entry: dotnet format subprojects/gstreamer-sharp/gstreamer-sharp.sln -v normal --include
+        types_or: ["c#", "vb"]
+    -   id: gst-indent
+        name: gst-indent
+        language: python
+        entry: ./scripts/gst-indent.py
+        types_or: ["c"]
+    # The rust hook uses cargo fmt, which requires a Cargo.toml
+    # We use a local hook to run rustfmt directly
+    -   id: rustfmt
+        name: rustfmt
+        language: system
+        entry: rustfmt --verbose --edition 2021
+        types_or: ["rust"]
diff --git a/ci/docker/README b/ci/docker/README
index 1e99ca0a6f..6e2f952fff 100644
--- a/ci/docker/README
+++ b/ci/docker/README
@@ -1,2 +1,4 @@
 GStreamer Docker images
 
+* `fedora`: main image used to build GStreamer
+* `checks`: image with pre-commit and gitlint used in the check stage
diff --git a/ci/docker/indent/prepare.sh b/ci/docker/checks/prepare.sh
similarity index 67%
rename from ci/docker/indent/prepare.sh
rename to ci/docker/checks/prepare.sh
index 4ee196c8f3..6dbb930176 100755
--- a/ci/docker/indent/prepare.sh
+++ b/ci/docker/checks/prepare.sh
@@ -2,6 +2,7 @@
 
 set -e
 set -x
+
 # Install dotnet-format
 apt update -yqq
 apt install -y gnupg apt-transport-https
@@ -20,7 +21,9 @@ ln -s ~/.dotnet/tools/dotnet-format /usr/local/bin/dotnet-format
 # Build and install gst-indent-1.0
 echo "deb-src http://deb.debian.org/debian/ bookworm main" >> /etc/apt/sources.list
 apt update
-apt-get install --assume-yes devscripts build-essential dpkg-dev wget meson ninja-build
+
+apt-get install --assume-yes devscripts build-essential dpkg-dev wget  meson ninja-build pkg-config libssl-dev
+
 apt-get build-dep --assume-yes indent
 
 git clone https://gitlab.freedesktop.org/gstreamer/gst-indent.git
@@ -50,10 +53,42 @@ gst-indent-1.0 \
   gstbayer2rgb.c
 done;
 
-# clean up
+# Clean up gst-indent
 cd ..
 rm -rf gst-indent
 
-apt-get remove --assume-yes devscripts build-essential dpkg-dev wget meson ninja-build
+export PIP_BREAK_SYSTEM_PACKAGES=1
+# Install pre-commit
+python3 -m pip install --upgrade pip
+python3 -m pip install pre-commit==3.6.0
+
+# Install gitlint
+python3 -m pip install gitlint
+
+# Install Rust
+RUSTUP_VERSION=1.27.1
+RUST_VERSION=1.81.0
+RUST_ARCH="x86_64-unknown-linux-gnu"
+
+RUSTUP_URL=https://static.rust-lang.org/rustup/archive/$RUSTUP_VERSION/$RUST_ARCH/rustup-init
+curl -o rustup-init $RUSTUP_URL
+
+export RUSTUP_HOME="/usr/local/rustup"
+export CARGO_HOME="/usr/local/cargo"
+export PATH="/usr/local/cargo/bin:$PATH"
+
+chmod +x rustup-init;
+./rustup-init -y --no-modify-path --default-toolchain $RUST_VERSION;
+rm rustup-init;
+chmod -R a+w $RUSTUP_HOME $CARGO_HOME
+
+cargo install cargo-c --version 0.10.4+cargo-0.82.0 --locked
+
+rustup --version
+cargo --version
+rustc --version
+
+# Clean up
+apt-get remove --assume-yes devscripts build-essential dpkg-dev wget meson ninja-build pkg-config libssl-dev
 apt-get remove --assume-yes libtext-unidecode-perl  libxml-namespacesupport-perl  libxml-sax-base-perl  libxml-sax-perl  libxml-libxml-perl texinfo
 apt-get autoremove --assume-yes
diff --git a/ci/docker/lint/prepare.sh b/ci/docker/lint/prepare.sh
deleted file mode 100755
index 7fa1d94447..0000000000
--- a/ci/docker/lint/prepare.sh
+++ /dev/null
@@ -1,6 +0,0 @@
-#! /bin/bash
-
-set -eux
-
-python3 -m pip install gitlint
-
diff --git a/meson.build b/meson.build
index fa57997fb9..1f9ce6557f 100644
--- a/meson.build
+++ b/meson.build
@@ -31,9 +31,7 @@ if cmdres.returncode() != 0
   error('Do not run `ninja reconfigure` or `meson` for gst-build inside the development environment, you will run into problems')
 endif
 
-# Install gst-indent pre-commit hook
-run_command(python3, '-c', 'import shutil; shutil.copy("scripts/git-hooks/multi-pre-commit.hook", ".git/hooks/pre-commit")', check: false)
-
+# pre-commit hooks are not interactive so we use gitlint's hook to check commit messages
 gitlint_req = '>= 0.18'
 gitlint = find_program('gitlint', version: gitlint_req, required: false)
 if gitlint.found()
@@ -42,6 +40,14 @@ else
   message('gitlint not found or too old, please install it with your package manager or `python3 -m pip install gitlint` to enable the commit message hook')
 endif
 
+pre_commit_req = '>= 3.6.0'
+pre_commit = find_program('pre-commit', version: pre_commit_req, required: false)
+if pre_commit.found()
+  run_command(pre_commit, 'install', '-f', check: true)
+else
+  warning('pre-commit not found or too old, please install it with your package manager or `python3 -m pip install pre-commit`')
+endif
+
 # On macOS, you have to run "Install Certificates.command" otherwise Python
 # doesn't have access to the latest SSL CA Certificates, and Meson will fail to
 # download wrap files from websites that use, for example, Let's Encrypt.
diff --git a/scripts/git-hooks/multi-pre-commit.hook b/scripts/git-hooks/multi-pre-commit.hook
deleted file mode 100755
index bf05bb3e17..0000000000
--- a/scripts/git-hooks/multi-pre-commit.hook
+++ /dev/null
@@ -1,49 +0,0 @@
-#!/bin/sh
-# Git pre-commit hook that runs multiple hooks specified in $HOOKS.
-# Make sure this script is executable. Bypass hooks with git commit --no-verify.
-
-# This file is inspired by a set of unofficial pre-commit hooks available
-# at github.
-# Link:    https://github.com/githubbrowser/Pre-commit-hooks
-# Contact: David Martin, david.martin.mailbox@googlemail.com
-
-
-###########################################################
-# SETTINGS:
-# pre-commit hooks to be executed. They should be in the same .git/hooks/ folder
-# as this script. Hooks should return 0 if successful and nonzero to cancel the
-# commit. They are executed in the order in which they are listed.
-###########################################################
-
-HOOKS="scripts/git-hooks/pre-commit.hook scripts/git-hooks/pre-commit-invoke-python.hook"
-
-# exit on error
-set -e
-
-if [ "$GST_DISABLE_PRE_COMMIT_HOOKS" = "1" ]
-then
-  echo "Pre-commits hooks disabled by env GST_DISABLE_PRE_COMMIT_HOOKS."
-  exit 0
-fi
-
-echo $PWD
-
-for hook in $HOOKS
-do
-    echo "Running hook: $hook"
-    # run hook if it exists
-    # if it returns with nonzero exit with 1 and thus abort the commit
-    if [ -f "$PWD/$hook" ]; then
-        "$PWD/$hook"
-        if [ $? != 0 ]; then
-            exit 1
-        fi
-    else
-        echo "Error: file $hook not found."
-        echo "Aborting commit. Make sure the hook is at $PWD/$hook and executable."
-        echo "You can disable it by removing it from the list"
-        echo "You can skip all pre-commit hooks with --no-verify (not recommended)."
-        exit 1
-    fi
-done
-
diff --git a/scripts/git-hooks/pre-commit-invoke-python.hook b/scripts/git-hooks/pre-commit-invoke-python.hook
index eeb073173a..db4e5d1b01 100755
--- a/scripts/git-hooks/pre-commit-invoke-python.hook
+++ b/scripts/git-hooks/pre-commit-invoke-python.hook
@@ -1,12 +1,3 @@
 #!/bin/bash
 
-PYTHON="python3"
-if [[ $OS =~ Windows ]]; then
-  if type -p py &>/dev/null; then
-    PYTHON="py -3"
-  elif type -p python &>/dev/null; then
-    PYTHON="python"
-  fi
-fi
-
-$PYTHON "`dirname $0`/pre-commit-python.hook"
+echo "This hook is deprecated, please run 'meson setup' to update your configuration"
diff --git a/scripts/git-hooks/pre-commit-python.hook b/scripts/git-hooks/pre-commit-python.hook
deleted file mode 100755
index efe815aedc..0000000000
--- a/scripts/git-hooks/pre-commit-python.hook
+++ /dev/null
@@ -1,233 +0,0 @@
-#!/usr/bin/env python3
-import os
-import subprocess
-import sys
-import tempfile
-import json
-import glob
-from pathlib import Path
-from typing import Dict, Optional, Set, Tuple
-
-NOT_PYCODESTYLE_COMPLIANT_MESSAGE_PRE = \
-    "Your code is not fully pycodestyle compliant and contains"\
-    " the following coding style issues:\n\n"
-
-NOT_PYCODESTYLE_COMPLIANT_MESSAGE_POST = \
-    "Please fix these errors and commit again, you can do so "\
-    "from the root directory automatically like this, assuming the whole "\
-    "file is to be committed:"
-
-NO_PYCODESTYLE_MESSAGE = \
-    "You should install the pycodestyle style checker to be able"\
-    " to commit in this repo.\nIt allows us to guarantee that "\
-    "anything that is committed respects the pycodestyle coding style "\
-    "standard.\nYou can install it:\n"\
-    "  * on ubuntu, debian: $sudo apt-get install pycodestyle \n"\
-    "  * on fedora: #yum install python3-pycodestyle \n"\
-    "  * on arch: #pacman -S python-pycodestyle \n"\
-    "  * or `pip install --user pycodestyle`"
-
-
-def system(*args, **kwargs):
-    kwargs.setdefault('stdout', subprocess.PIPE)
-    proc = subprocess.Popen(args, **kwargs)
-    out, err = proc.communicate()
-    if isinstance(out, bytes):
-        out = out.decode()
-    return out
-
-
-def copy_files_to_tmp_dir(files):
-    tempdir = tempfile.mkdtemp()
-    for name in files:
-        filename = os.path.join(tempdir, name)
-        filepath = os.path.dirname(filename)
-        if not os.path.exists(filepath):
-            os.makedirs(filepath)
-        with open(filename, 'w', encoding="utf-8") as f:
-            system('git', 'show', ':' + name, stdout=f)
-
-    return tempdir
-
-def find_builddir() -> Optional[Path]:
-    # Explicitly-defined builddir takes precedence
-    if 'GST_DOC_BUILDDIR' in os.environ:
-        return Path(os.environ['GST_DOC_BUILDDIR'])
-
-    # Now try the usual suspects
-    for name in ('build', '_build', 'builddir', 'b'):
-        if Path(name, 'build.ninja').exists():
-            return Path(name)
-
-    # Out of luck, look for the most recent folder with a `build.ninja` file
-    for d in sorted([p for p in Path('.').iterdir() if p.is_dir()], key=lambda p: p.stat().st_mtime):
-        if Path(d, 'build.ninja').exists():
-            print ('Found', d)
-            return d
-
-    return None
-
-def hotdoc_conf_needs_rebuild(conf_path: Path, conf_data: Dict, modified_fpaths):
-    if not isinstance(conf_data, dict):
-        return False
-
-    for (key, value) in conf_data.items():
-        if key.endswith('c_sources'):
-            if any(['*' in f for f in value]):
-                continue
-            conf_dir = conf_path.parent
-            for f in value:
-                fpath = Path(f)
-                if not fpath.is_absolute():
-                    fpath = Path(conf_dir, fpath)
-
-                fpath = fpath.resolve()
-                if fpath in modified_fpaths:
-                    return True
-
-    return False
-
-
-def get_hotdoc_confs_to_rebuild(builddir, modified_files) -> Tuple[Set, Set]:
-    srcdir = Path(os.getcwd())
-    modified_fpaths = set()
-    for f in modified_files:
-        modified_fpaths.add(Path(srcdir, f))
-
-    confs_need_rebuild = set()
-    caches_need_rebuild = set()
-    for path in glob.glob('**/docs/*.json', root_dir=builddir, recursive=True):
-        conf_path = Path(srcdir, builddir, path)
-        with open(conf_path) as f:
-            conf_data = json.load(f)
-
-        if hotdoc_conf_needs_rebuild(conf_path, conf_data, modified_fpaths):
-            confs_need_rebuild.add(conf_path)
-            caches_need_rebuild.add(conf_data.get('gst_plugin_library'))
-
-    return (confs_need_rebuild, caches_need_rebuild)
-
-def build(builddir):
-    subprocess.run(['ninja', '-C', builddir], check=True)
-    for subproject in ('gstreamer', 'gst-plugins-base', 'gst-plugins-good', 'gst-plugins-bad', 'gst-plugins-ugly', 'gst-rtsp-server', 'gst-libav', 'gst-editing-services'):
-        subprocess.run(['ninja', '-C', builddir, f'subprojects/{subproject}/docs/hotdoc-configs.json'], check=True)
-
-def build_cache(builddir, subproject, targets, subdir):
-    if not targets:
-        return
-
-    print (f'Rebuilding {subproject} cache with changes from {targets}')
-
-    cmd = [
-        os.path.join(builddir, f'subprojects/gstreamer/docs/gst-plugins-doc-cache-generator'),
-        os.path.join(os.getcwd(), f'subprojects/{subproject}/docs/{subdir}gst_plugins_cache.json'),
-        os.path.join(builddir, f'subprojects/{subproject}/docs/gst_plugins_cache.json'),
-    ] + targets
-
-    subprocess.run(cmd)
-
-class StashManager:
-    def __enter__(self):
-        print ('Stashing changes')
-        # First, save the difference with the current index to a patch file
-        tree = subprocess.run(['git', 'write-tree'], capture_output=True, check=True).stdout.strip()
-        result = subprocess.run(['git', 'diff-index', '--ignore-submodules', '--binary', '--no-color', '--no-ext-diff', tree], check=True, capture_output=True)
-        # Don't delete the temporary file, we want to make sure to prevent data loss
-        with tempfile.NamedTemporaryFile(delete_on_close=False, delete=False) as f:
-            f.write(result.stdout)
-            self.patch_file_name = f.name
-
-        # Print the path to the diff file, useful is something goes wrong
-        print ("unstaged diff saved to ", self.patch_file_name)
-
-        # Now stash the changes, we do not use git stash --keep-index because it causes spurious rebuilds
-        subprocess.run(['git', '-c', 'submodule.recurse=0', 'checkout', '--', '.'], check=True)
-        return self
-
-    def __exit__(self, exc_type, exc_val, exc_tb):
-        # Now re-apply the non-staged changes
-        subprocess.run(['git', 'apply', '--allow-empty', self.patch_file_name], check=True)
-        print ('Unstashed changes')
-
-def run_doc_checks(modified_files):
-    builddir = find_builddir()
-
-    if builddir is None:
-        raise Exception('cannot run doc pre-commit hook without a build directory')
-
-    builddir = builddir.absolute()
-
-    build(builddir)
-
-    # Each subproject holds its own cache file. For each we keep track of the
-    # dynamic library associated with the hotdoc configuration files that need
-    # rebuilding, and only update the caches using those libraries.
-    # This is done in order to minimize spurious diffs as much as possible.
-    caches = {}
-
-    (confs_need_rebuild, caches_need_rebuild) = get_hotdoc_confs_to_rebuild(builddir, modified_files)
-
-    for libpath in caches_need_rebuild:
-        cache_project = Path(libpath).relative_to(builddir).parts[1]
-        if cache_project not in caches:
-            caches[cache_project] = [libpath]
-        else:
-            caches[cache_project].append(libpath)
-
-    for (subproject, libpaths) in caches.items():
-        cache_subdir = 'plugins/' if subproject in ['gst-plugins-bad', 'gst-plugins-base', 'gst-rtsp-server', 'gstreamer', 'gst-plugins-rs'] else ''
-        build_cache(builddir, subproject, libpaths, cache_subdir)
-
-    try:
-        subprocess.run(['git', 'diff', '--ignore-submodules', '--exit-code'], check=True)
-    except subprocess.CalledProcessError as e:
-        print ('You have a diff in the plugin cache, please commit it')
-        raise e
-
-    print ('No pending diff in plugin caches, checking since tags')
-
-    for conf_path in confs_need_rebuild:
-        subprocess.run(['hotdoc', 'run', '--fatal-warnings', '--disable-warnings', '--enabled-warnings', 'missing-since-marker', '--conf-file', conf_path, '--previous-symbol-index', 'subprojects/gst-docs/symbols/symbol_index.json'], check=True)
-
-def main():
-    modified_files = system('git', 'diff-index', '--cached',
-                            '--name-only', 'HEAD', '--diff-filter=ACMR').split("\n")[:-1]
-
-    if os.environ.get('GST_ENABLE_DOC_PRE_COMMIT_HOOK', '0') != '0':
-        with StashManager():
-            try:
-                run_doc_checks(modified_files)
-            except Exception as e:
-                print (e)
-                sys.exit(1)
-
-    non_compliant_files = []
-    output_message = None
-
-    for modified_file in modified_files:
-        try:
-            if not modified_file.endswith(".py"):
-                continue
-            pycodestyle_errors = system('pycodestyle', '--repeat', '--ignore', 'E402,E501,E128,W605,W503', modified_file)
-            if pycodestyle_errors:
-                if output_message is None:
-                    output_message = NOT_PYCODESTYLE_COMPLIANT_MESSAGE_PRE
-                output_message += pycodestyle_errors
-                non_compliant_files.append(modified_file)
-        except OSError as e:
-            output_message = NO_PYCODESTYLE_MESSAGE
-            break
-
-    if output_message:
-        print(output_message)
-        if non_compliant_files:
-            print(NOT_PYCODESTYLE_COMPLIANT_MESSAGE_POST)
-            for non_compliant_file in non_compliant_files:
-                print("autopep8 -i --max-line-length 120", non_compliant_file, "; git add ",
-                      non_compliant_file)
-            print("git commit")
-        sys.exit(1)
-
-
-if __name__ == '__main__':
-    main()
diff --git a/scripts/git-hooks/pre-commit.hook b/scripts/git-hooks/pre-commit.hook
index 6a071d4f28..0b62f79ef4 100755
--- a/scripts/git-hooks/pre-commit.hook
+++ b/scripts/git-hooks/pre-commit.hook
@@ -3,121 +3,4 @@
 # Check that the code follows a consistant code style
 #
 
-# Check for existence of indent, and error out if not present.
-# On some *bsd systems the binary seems to be called gnunindent,
-# so check for that first.
-
-
-version=$(gst-indent-1.0 --version 2>/dev/null)
-if test -z "$version"; then
-  version=$(gnuindent --version 2>/dev/null)
-  if test -z "$version"; then
-    version=$(gindent --version 2>/dev/null)
-    if test -z "$version"; then
-      version=$(indent --version 2>/dev/null)
-      if test -z "$version"; then
-        echo "GStreamer git pre-commit hook:"
-        echo "Did not find GNU indent, please install it before continuing."
-        exit 1
-      else
-        INDENT=indent
-      fi
-    else
-      INDENT=gindent
-    fi
-  else
-    INDENT=gnuindent
-  fi
-else
-  INDENT=gst-indent-1.0
-fi
-
-case $($INDENT --version) in
-  GNU*)
-      ;;
-  default)
-      echo "GStreamer git pre-commit hook:"
-      echo "Did not find GNU indent, please install it before continuing."
-      echo "(Found $INDENT, but it doesn't seem to be GNU indent)"
-      exit 1
-      ;;
-esac
-
-INDENT_PARAMETERS="--braces-on-if-line \
-	--case-brace-indentation0 \
-	--case-indentation2 \
-	--braces-after-struct-decl-line \
-	--line-length80 \
-	--no-tabs \
-	--cuddle-else \
-	--dont-line-up-parentheses \
-	--continuation-indentation4 \
-	--honour-newlines \
-	--tab-size8 \
-	--indent-level2 \
-	--leave-preprocessor-space"
-
-echo "--Checking style--"
-for file in $(git diff-index --cached --name-only HEAD --diff-filter=ACMR| grep "\.c$") ; do
-    # nf is the temporary checkout. This makes sure we check against the
-    # revision in the index (and not the checked out version).
-    nf=$(git checkout-index --temp ${file} | cut -f 1)
-    newfile=$(mktemp /tmp/${nf}.XXXXXX) || exit 1
-    $INDENT ${INDENT_PARAMETERS} \
-	$nf -o $newfile 2>> /dev/null
-    # FIXME: Call indent twice as it tends to do line-breaks
-    # different for every second call.
-    $INDENT ${INDENT_PARAMETERS} \
-        $newfile 2>> /dev/null
-    diff -u -p "${nf}" "${newfile}"
-    r=$?
-    rm "${newfile}"
-    rm "${nf}"
-    if [ $r != 0 ] ; then
-        ERROR_FILES="$ERROR_FILES $file"
-echo "================================================================================================="
-echo " Code style error in: $file                                                                      "
-echo "================================================================================================="
-echo ""
-    fi
-done
-
-if [ -n "$ERROR_FILES" ];then
-echo "================================================================================================="
-echo " Code style error in:                                                                            "
-for file in $ERROR_FILES ; do
-echo "   $file"
-done
-echo "                                                                                                 "
-echo " Please fix before committing. Don't forget to run git add before trying to commit again.        "
-echo " If the whole file is to be committed, this should work (run from the top-level directory):      "
-echo "   scripts/gst-indent$ERROR_FILES ; git add$ERROR_FILES ; git commit"
-echo "                                                                                                 "
-echo "================================================================================================="
-  exit 1
-fi
-
-csharp_files=$( git diff-index --cached --name-only HEAD --diff-filter=ACMR| grep "^subprojects/gstreamer-sharp/.*cs$" )
-if test -n "$csharp_files"; then
-  version=$(dotnet-format --version 2>/dev/null)
-  if test -z "$version"; then
-      echo "GStreamer git pre-commit hook:"
-      echo "Did not find dotnet-format required to format C# files, please install it before continuing."
-      exit 1
-  fi
-  scripts/format-csharp --check
-  r=$?
-  if [ $r != 0 ] ; then
-echo "================================================================================================="
-echo " Code style error:                                                                               "
-echo "                                                                                                 "
-echo " Please fix before committing, running from the top-level directory:                             "
-echo "   scripts/format-chsarp                                                                         "
-echo "                                                                                                 "
-echo " Don't forget to run git add before trying to commit again.                                      "
-echo "================================================================================================="
-    exit 1
-  fi
-fi
-
-echo "--Checking style pass--"
+echo "This hook is deprecated, please run 'meson setup' to update your configuration"
diff --git a/scripts/gst-indent b/scripts/gst-indent
deleted file mode 100755
index 50ec6181f5..0000000000
--- a/scripts/gst-indent
+++ /dev/null
@@ -1,45 +0,0 @@
-#!/bin/sh
-
-for execname in gst-indent-1.0 gnuindent gindent indent; do
-  version=`$execname --version 2>/dev/null`
-  if test "x$version" != "x"; then
-    INDENT=$execname
-    break
-  fi
-done
-
-if test -z $INDENT; then
-  echo "GStreamer git pre-commit hook:"
-  echo "Did not find GNU indent, please install it before continuing."
-  exit 1
-fi
-
-case `$INDENT --version` in
-  GNU*)
-      ;;
-  default)
-      echo "Did not find GNU indent, please install it before continuing."
-      echo "(Found $INDENT, but it doesn't seem to be GNU indent)"
-      exit 1
-      ;;
-esac
-
-# Run twice. GNU indent isn't idempotent
-# when run once
-for i in 1 2; do
-$INDENT \
-  --braces-on-if-line \
-  --case-brace-indentation0 \
-  --case-indentation2 \
-  --braces-after-struct-decl-line \
-  --line-length80 \
-  --no-tabs \
-  --cuddle-else \
-  --dont-line-up-parentheses \
-  --continuation-indentation4 \
-  --honour-newlines \
-  --tab-size8 \
-  --indent-level2 \
-  --leave-preprocessor-space \
-  $* || exit $?
-done