PHP / Magento Dev Blog

  • Publikacje
  • O autorze
  • Kontakt

Git course #6 – hooks and automation: pre-commit, PHPStan, commit-msg, DDEV

by Henryk Tews / Saturday, 16 May 2026 / Published in Bez kategorii

Git hooks are scripts that run automatically on Git operations. A pre-commit hook run before every commit eliminates a class of errors before they enter history. Commit-msg enforces message conventions. Pre-push protects the remote branch from broken code. I show how to configure this in a Magento 2 project with DDEV.

Hook types

Hook When Typical use
pre-commit Before saving the commit phpcs, phpstan, check for debuggers
commit-msg After entering the message Validate Conventional Commits format
pre-push Before sending to remote Full unit test suite
post-merge After merge/pull composer install, cache flush

pre-commit – phpcs and phpstan

#!/bin/bash
# .git/hooks/pre-commit
set -e

echo "Running PHP CS Fixer..."
files=$(git diff --cached --name-only --diff-filter=ACMR | grep \.php$)
if [ -n "$files" ]; then
    vendor/bin/phpcs --standard=PSR12 $files
fi

echo "Running PHPStan..."
if [ -n "$files" ]; then
    vendor/bin/phpstan analyse $files --level=8 --no-progress
fi

# Check for var_dump or dd()
if git diff --cached | grep -E "^\+.*var_dump|^\+.*dd\("; then
    echo "ERROR: var_dump() or dd() found in staged files"
    exit 1
fi

echo "Pre-commit checks passed!"

commit-msg – format validation

#!/bin/bash
# .git/hooks/commit-msg
COMMIT_MSG=$(cat "$1")
PATTERN="^(feat|fix|refactor|docs|test|chore|perf)(\([a-z-]+\))?: .{10,72}"

if ! echo "$COMMIT_MSG" | grep -qE "$PATTERN"; then
    echo "ERROR: Commit message format invalid."
    echo "Required: type(scope): description (10-72 chars)"
    echo "Example: feat(catalog): add product export service"
    exit 1
fi

pre-push – tests before sending

#!/bin/bash
# .git/hooks/pre-push
BRANCH=$(git symbolic-ref HEAD | sed 's/refs\/heads\///')

# Only for main and develop
if [[ "$BRANCH" == "main" || "$BRANCH" == "develop" ]]; then
    echo "Running full test suite before push to $BRANCH..."
    vendor/bin/phpunit --testsuite=Unit
fi

Sharing hooks across the team

The .git/hooks/ directory is not version-controlled. Best practice: store hooks in .githooks/ and configure the path.

# Configure hooks directory for the whole project
git config core.hooksPath .githooks

# Or add to composer.json post-install-cmd:
# "git config core.hooksPath .githooks"
# "chmod +x .githooks/*"

DDEV integration

#!/bin/bash
# .githooks/pre-commit - DDEV version
set -e

files=$(git diff --cached --name-only --diff-filter=ACMR | grep \.php$)
[ -z "$files" ] && exit 0

# Run phpcs and phpstan inside the DDEV container
ddev exec vendor/bin/phpcs --standard=PSR12 $files
ddev exec vendor/bin/phpstan analyse $files --level=8 --no-progress

echo "All checks passed!"

Summary

Git hooks are the first line of defence against errors in history. Pre-commit with phpcs and phpstan eliminates code quality issues before they reach the repo. Commit-msg enforces readable messages. Storing hooks in .githooks/ and configuring via git config core.hooksPath shares them with the whole team. Next post: debugging and rescue – bisect, reflog, reset vs revert.

About Henryk Tews

What you can read next

Git course #7 – debugging and rescue: bisect, reflog, reset vs revert
Git course #4 – remote work: remote, fetch vs pull, force-with-lease
Git course #2 – commits and history: rebase -i, cherry-pick, bisect

© 2026 Created by

TOP
Zarządzaj zgodą
Aby zapewnić jak najlepsze wrażenia, korzystamy z technologii, takich jak pliki cookie, do przechowywania i/lub uzyskiwania dostępu do informacji o urządzeniu. Zgoda na te technologie pozwoli nam przetwarzać dane, takie jak zachowanie podczas przeglądania lub unikalne identyfikatory na tej stronie. Brak wyrażenia zgody lub wycofanie zgody może niekorzystnie wpłynąć na niektóre cechy i funkcje.
Funkcjonalne Always active
Przechowywanie lub dostęp do danych technicznych jest ściśle konieczny do uzasadnionego celu umożliwienia korzystania z konkretnej usługi wyraźnie żądanej przez subskrybenta lub użytkownika, lub wyłącznie w celu przeprowadzenia transmisji komunikatu przez sieć łączności elektronicznej.
Preferencje
Przechowywanie lub dostęp techniczny jest niezbędny do uzasadnionego celu przechowywania preferencji, o które nie prosi subskrybent lub użytkownik.
Statystyka
Przechowywanie techniczne lub dostęp, który jest używany wyłącznie do celów statystycznych. Przechowywanie techniczne lub dostęp, który jest używany wyłącznie do anonimowych celów statystycznych. Bez wezwania do sądu, dobrowolnego podporządkowania się dostawcy usług internetowych lub dodatkowych zapisów od strony trzeciej, informacje przechowywane lub pobierane wyłącznie w tym celu zwykle nie mogą być wykorzystywane do identyfikacji użytkownika.
Marketing
Przechowywanie lub dostęp techniczny jest wymagany do tworzenia profili użytkowników w celu wysyłania reklam lub śledzenia użytkownika na stronie internetowej lub na kilku stronach internetowych w podobnych celach marketingowych.
  • Manage options
  • Manage services
  • Manage {vendor_count} vendors
  • Read more about these purposes
Zobacz preferencje
  • {title}
  • {title}
  • {title}