Let's say you want to enforce checks (e.g. linting, or the format of a Git commit message) as early as possible. At the same time, you want to avoid killing the developer experience (e.g. because of a buggy or long-running local Git pre-commit hook).<p>I researched the topic and found 3 ways to implement such kinds of checks - I'm wondering whether you know other ones, or what your experience has been using any of these (or possibly a combination of them):<p>1) Local(!) Git hooks:<p>Useful ones are e.g. "pre-commit" or "pre-push". They offer the fastest feedback, but are unreliable, because developers need to install them explicitly. They are also either limited to bash, or require extra tooling to be present on the developer's machine (e.g. a linter). One could do this in two ways:<p>1.a) Use any tooling installed _natively_ on the developer's machine, e.g. a Python script, or pre-commit.org. Pro: hooks terminate quickly; con: requires installing the tools, version drift may happen (e.g. outdated Python interpreter)<p>1.b) Docker-based: package the tools into a Docker image. Pro: allows fixing the tooling and auto-update it when needed; Con: requires running Docker, may be slow if a new container has to be created<p>Slow pre-_commit_ hooks are especially bad for DX, particularly if devs commit often! For pre-_push_ hooks, a slower hook might be less terrible.<p>===<p>2) Remote(!) Git hooks, particularly the "pre-receive" hook.<p>Pro: avoids having to rewrite already-pushed history if any checks are violated<p>Cons: complicated to set up on some platforms, or sometimes not possible at all (e.g. github.com); limited to bash<p>===<p>3) CI jobs: you run the checks in CI as jobs, once the developer pushed the code.<p>Cons: feedback is provided quite late, compared to local Git hooks; requires dangerous force-push to rewrite history, e.g. if the checks demand that the commit messages have to be rephrased.<p>Pros: CI jobs are reliable; you can use any tooling you want (beyond Bash), and there are sometimes ready-made jobs/tasks, e.g. https://commitsar.aevea.ee<p>====<p>One can of course combine multiple approaches from above, but it would require more maintenance. For instance, you could have a local pre-commit hook or local pre-push hook that checks the branch name and commit message formats prior to pushing them, but additionally have CI jobs that validate the same data. However, there is maintenance effort to ensure that both approaches are in sync (e.g. check the same commit message regex) and do not contradict each other.