Git Toolbox

// Git Toolbox

Générateur de hooks Git

Les hooks sont des scripts que Git lance avant un commit ou un push. Choisis les vérifications, récupère les scripts et la façon de les installer.

pre-commit

Avant chaque commit : vérifie les fichiers indexés.

commit-msg

Vérifie le message de commit.

prepare-commit-msg

Prépare le message avant l'ouverture de l'éditeur.

pre-push

Avant chaque push : dernière chance avant le serveur.

Installer

Dans .git/hooks : jamais commité, seulement sur ta machine.

Copie, colle dans un terminal à la racine de ton dépôt, c'est fini :

Terminal (bash, zsh, Git Bash)
cat > .git/hooks/pre-commit <<'GITPUSHF_EOF'
#!/bin/sh
# pre-commit — generated by gitpushf.uk
# Skip once: --no-verify (git commit --no-verify, git push --no-verify)
# --- No commits directly on main
branch=$(git symbolic-ref --short HEAD 2>/dev/null)
case "$branch" in
main|master)
echo "✖ Direct commit on $branch. Create a branch first: git switch -c my-branch"
exit 1 ;;
esac
# --- No forgotten conflict markers
if git diff --cached -U0 | grep -qE '^\+(<<<<<<< |=======$|>>>>>>> )'; then
echo "✖ Conflict markers in your staged changes (<<<<<<< / ======= / >>>>>>>)."
exit 1
fi
# --- No secrets or .env files
if git diff --cached --name-only --diff-filter=A | grep -E '(^|/)\.env(\.[^/]*)?$' | grep -vqE '\.(example|sample|template)$'; then
echo "✖ A .env file is staged. Remove it: git restore --staged <file>, then add it to .gitignore."
exit 1
fi
if git diff --cached -U0 | grep -qE '^\+.*(-----BEGIN [A-Z ]*PRIVATE KEY-----|AKIA[0-9A-Z]{16}|sk_live_[0-9A-Za-z]{10,}|gh[pousr]_[0-9A-Za-z]{36}|github_pat_[0-9A-Za-z_]{20,}|glpat-[0-9A-Za-z_-]{20}|xox[abprs]-[0-9A-Za-z-]{10,}|sk-ant-[0-9A-Za-z_-]{20,})'; then
echo "✖ Something that looks like a secret is staged. Check: git diff --cached"
exit 1
fi
# --- No files over 5 MB
limit=5242880
git diff --cached --name-only --diff-filter=AM | while IFS= read -r file; do
size=$(git cat-file -s ":$file" 2>/dev/null || echo 0)
if [ "$size" -gt "$limit" ]; then
echo "✖ $file is $((size / 1048576)) MB (limit 5 MB). Use Git LFS: git lfs track \"$file\""
exit 1
fi
done || exit 1
GITPUSHF_EOF
cat > .git/hooks/commit-msg <<'GITPUSHF_EOF'
#!/bin/sh
# commit-msg — generated by gitpushf.uk
# Skip once: --no-verify (git commit --no-verify, git push --no-verify)
# $1 = file that holds the commit message
first=$(head -n 1 "$1")
# --- Conventional Commits
case "$first" in
Merge*|Revert*|fixup!*|squash!*|amend!*) ;;
*)
# An optional "[JIRA-123] " prefix is allowed (added by the ticket hook).
if ! printf '%s\n' "$first" | grep -qE '^(\[[A-Z][A-Z0-9]+-[0-9]+\] )?(feat|fix|docs|style|refactor|perf|test|build|ci|chore|revert)(\([a-z0-9._/-]+\))?!?: .+'; then
echo "✖ Commit message must follow Conventional Commits: type(scope): description"
echo " e.g. feat(auth): add Discord login"
exit 1
fi ;;
esac
GITPUSHF_EOF
cat > .git/hooks/pre-push <<'GITPUSHF_EOF'
#!/bin/sh
# pre-push — generated by gitpushf.uk
# Skip once: --no-verify (git commit --no-verify, git push --no-verify)
# Git sends one line per pushed ref on stdin: <local ref> <local sha> <remote ref> <remote sha>
refs=$(cat)
# --- No direct push to main
printf '%s\n' "$refs" | while read -r local_ref local_sha remote_ref remote_sha; do
case "$remote_ref" in
refs/heads/main|refs/heads/master)
echo "✖ Direct push to ${remote_ref#refs/heads/} is blocked. Push a branch and open a pull request."
exit 1 ;;
esac
done || exit 1
# --- No WIP / fixup! commits pushed
zero=0000000000000000000000000000000000000000
printf '%s\n' "$refs" | while read -r local_ref local_sha remote_ref remote_sha; do
[ -z "$local_sha" ] && continue
[ "$local_sha" = "$zero" ] && continue
if [ "$remote_sha" = "$zero" ]; then
subjects=$(git log --format=%s "$local_sha" --not --remotes)
else
subjects=$(git log --format=%s "$remote_sha..$local_sha")
fi
if printf '%s\n' "$subjects" | grep -qiE '^(wip|fixup!|squash!)'; then
echo "✖ WIP or fixup! commits in $local_ref. Clean up: git rebase -i --autosquash"
exit 1
fi
done || exit 1
GITPUSHF_EOF
chmod +x .git/hooks/pre-commit .git/hooks/commit-msg .git/hooks/pre-push

Cette commande crée tous les fichiers de hooks d'un coup. Pour changer une vérification, reviens ici et recolle-la.

Tu préfères créer les fichiers toi-même ? Les voir un par un
Sans risque
# Save each script as .git/hooks/<hook name>, then:
$ chmod +x .git/hooks/pre-commit .git/hooks/commit-msg .git/hooks/pre-push
.git/hooks/pre-commit
#!/bin/sh
# pre-commit — generated by gitpushf.uk
# Skip once: --no-verify (git commit --no-verify, git push --no-verify)
# --- No commits directly on main
branch=$(git symbolic-ref --short HEAD 2>/dev/null)
case "$branch" in
main|master)
echo "✖ Direct commit on $branch. Create a branch first: git switch -c my-branch"
exit 1 ;;
esac
# --- No forgotten conflict markers
if git diff --cached -U0 | grep -qE '^\+(<<<<<<< |=======$|>>>>>>> )'; then
echo "✖ Conflict markers in your staged changes (<<<<<<< / ======= / >>>>>>>)."
exit 1
fi
# --- No secrets or .env files
if git diff --cached --name-only --diff-filter=A | grep -E '(^|/)\.env(\.[^/]*)?$' | grep -vqE '\.(example|sample|template)$'; then
echo "✖ A .env file is staged. Remove it: git restore --staged <file>, then add it to .gitignore."
exit 1
fi
if git diff --cached -U0 | grep -qE '^\+.*(-----BEGIN [A-Z ]*PRIVATE KEY-----|AKIA[0-9A-Z]{16}|sk_live_[0-9A-Za-z]{10,}|gh[pousr]_[0-9A-Za-z]{36}|github_pat_[0-9A-Za-z_]{20,}|glpat-[0-9A-Za-z_-]{20}|xox[abprs]-[0-9A-Za-z-]{10,}|sk-ant-[0-9A-Za-z_-]{20,})'; then
echo "✖ Something that looks like a secret is staged. Check: git diff --cached"
exit 1
fi
# --- No files over 5 MB
limit=5242880
git diff --cached --name-only --diff-filter=AM | while IFS= read -r file; do
size=$(git cat-file -s ":$file" 2>/dev/null || echo 0)
if [ "$size" -gt "$limit" ]; then
echo "✖ $file is $((size / 1048576)) MB (limit 5 MB). Use Git LFS: git lfs track \"$file\""
exit 1
fi
done || exit 1
.git/hooks/commit-msg
#!/bin/sh
# commit-msg — generated by gitpushf.uk
# Skip once: --no-verify (git commit --no-verify, git push --no-verify)
# $1 = file that holds the commit message
first=$(head -n 1 "$1")
# --- Conventional Commits
case "$first" in
Merge*|Revert*|fixup!*|squash!*|amend!*) ;;
*)
# An optional "[JIRA-123] " prefix is allowed (added by the ticket hook).
if ! printf '%s\n' "$first" | grep -qE '^(\[[A-Z][A-Z0-9]+-[0-9]+\] )?(feat|fix|docs|style|refactor|perf|test|build|ci|chore|revert)(\([a-z0-9._/-]+\))?!?: .+'; then
echo "✖ Commit message must follow Conventional Commits: type(scope): description"
echo " e.g. feat(auth): add Discord login"
exit 1
fi ;;
esac
.git/hooks/pre-push
#!/bin/sh
# pre-push — generated by gitpushf.uk
# Skip once: --no-verify (git commit --no-verify, git push --no-verify)
# Git sends one line per pushed ref on stdin: <local ref> <local sha> <remote ref> <remote sha>
refs=$(cat)
# --- No direct push to main
printf '%s\n' "$refs" | while read -r local_ref local_sha remote_ref remote_sha; do
case "$remote_ref" in
refs/heads/main|refs/heads/master)
echo "✖ Direct push to ${remote_ref#refs/heads/} is blocked. Push a branch and open a pull request."
exit 1 ;;
esac
done || exit 1
# --- No WIP / fixup! commits pushed
zero=0000000000000000000000000000000000000000
printf '%s\n' "$refs" | while read -r local_ref local_sha remote_ref remote_sha; do
[ -z "$local_sha" ] && continue
[ "$local_sha" = "$zero" ] && continue
if [ "$remote_sha" = "$zero" ]; then
subjects=$(git log --format=%s "$local_sha" --not --remotes)
else
subjects=$(git log --format=%s "$remote_sha..$local_sha")
fi
if printf '%s\n' "$subjects" | grep -qiE '^(wip|fixup!|squash!)'; then
echo "✖ WIP or fixup! commits in $local_ref. Clean up: git rebase -i --autosquash"
exit 1
fi
done || exit 1

Besoin de passer une vérification une fois ? git commit --no-verify ou git push --no-verify.

Marche aussi sous Windows : Git for Windows lance ces scripts avec son propre shell.