Aller au contenu principal
Nicolas Cousin Tech SolutionsNicolas Cousin Tech Solutions
Module 5 of 6

Installing pre-commit and triggering a block

What you're going to do

This module doesn't depend on the previous one (module 4, on reading devcontainer.json): it's a second, independent topic, that touches neither Docker nor Dev Containers. You'll install the pre-commit tool, configure it with a single simple hook, then deliberately trigger a blocked commit to see, with your own eyes, what that looks like — exactly the scenario described in module 2.

Prerequisite: module 1 must be green (git installed and configured). You'll also need Python 3 with pip available on your machine — most recent systems already have them. If not, install Python from python.org, or use pipx if you'd rather keep the install isolated in its own environment.

Step 1 — install pre-commit

pip install pre-commit

Alternative with pipx, if you'd rather not install Python tools globally:

pipx install pre-commit

Verify:

pre-commit --version

Expected healthy output: a version number, for example pre-commit 4.6.0 — the exact value doesn't matter, only that you get a number back (not an error).

Step 2 — create a git repo for the exercise

mkdir my-pre-commit-project
cd my-pre-commit-project
git init

Expected output:

Initialized empty Git repository in .../my-pre-commit-project/.git/

If git has never been used on this machine, a few hint: lines about the default branch name may print before this line — ignore them, that's not an error.

Step 3 — write .pre-commit-config.yaml

At the root of this folder, create a .pre-commit-config.yaml file with exactly this content:

repos:
-   repo: https://github.com/pre-commit/pre-commit-hooks
    rev: v6.0.0
    hooks:
    -   id: trailing-whitespace

What this file says: repos is a list of source repositories for hooks. Here, a single repo, pre-commit/pre-commit-hooks — an official collection of generic hooks. rev pins the exact version (the v6.0.0 tag) of that repo to use, so the configuration is reproducible across machines, as discussed in module 2. hooks lists the hooks to enable among those the repo offers; here just one, identified by id: trailing-whitespace, which detects (and fixes) trailing whitespace.

Step 4 — install the git hook

pre-commit install

Expected output:

pre-commit installed at .git/hooks/pre-commit

This command writes a script into .git/hooks/pre-commit, the native hook that git automatically runs before every commit in this repo. You'll inspect this script in detail in the next module — for now, just note that it exists and is now active.

Step 5 — trigger a block

Create a file with a line ending in extra whitespace:

printf 'hello everyone   \n' > example.txt

Stage it and try to commit:

git add example.txt
git commit -m "add example"

Expected output — the commit is rejected:

Trim Trailing Whitespace.................................................Failed
- hook id: trailing-whitespace
- exit code: 1
- files were modified by this hook

Fixing example.txt

What happened: the trailing-whitespace hook inspected example.txt, stripped the trailing whitespace directly on the file on disk, then returned a non-zero exit code because it modified something. A hook that returns a non-zero exit code fails the whole check, and git aborts the commit — the original content (with the extra whitespace) never enters the history.

Verify it:

git status

You'll see example.txt listed twice: under "Changes to be committed" (the original version, still pending in the index) and under "Changes not staged for commit" (the version the hook fixed on disk). That's expected: the commit never happened, so the index still holds the old version, while the hook modified the file on disk afterward.

Step 6 — fix and commit again

The file is already fixed on disk (the hook did that). All that's left is to re-stage it and commit again:

git add example.txt
git commit -m "add example"

This time, the hook passes:

Trim Trailing Whitespace.................................................Passed

And the commit is accepted:

[main (root-commit) a1b2c3d] add example
 1 file changed, 1 insertion(+)
 create mode 100644 example.txt

(The branch name shown — main or master — depends on your machine's init.defaultBranch setting; either is normal, only the rest of the line matters.)

What you just did

You installed pre-commit, wrote a minimal configuration pointing to an official, versioned hook, activated the git hook that runs it, then confirmed in practice — not just in theory — that a commit containing a detectable problem gets rejected before entering the history. This is exactly the safety net described in module 2: nothing broken ever ships into the shared repo without passing through this check.

In the next module, you'll open the .git/hooks/pre-commit file generated in step 4 to understand what it actually contains, and how it differs from a native git hook you'd have written yourself.

Check your understanding

In .pre-commit-config.yaml, what is the rev field for?

During the first commit attempt with the file containing trailing whitespace, what actually happened?

Which command created the .git/hooks/pre-commit file used to block your commit?

Want to hear about the next modules?

The Academy stays free and open-access, no sign-up required. If you'd just like to be notified by email when a new module ships, here you go — no obligation, unsubscribe anytime with one click.