Aller au contenu
·26 min de lecture

Git au-delà des bases : des workflows qui font gagner des heures chaque semaine

Rebase interactif, cherry-pick, bisect, worktrees, sauvetage par reflog et les stratégies de branching qui marchent vraiment. Des commandes Git que j'utilise quotidiennement.

Partager:X / TwitterLinkedIn

La plupart des développeurs apprennent cinq commandes Git et s'arrêtent là. add, commit, push, pull, merge. Peut-être checkout et branch s'ils se sentent aventureux. Ça suffit pour la première année. Puis votre branche a 47 commits avec des messages comme « fix » et « wip » et « please work », vous faites accidentellement un reset sur quelque chose que vous n'auriez pas dû, et vous passez 40 minutes sur Stack Overflow à essayer de défaire un merge qui a mal tourné.

J'utilise Git depuis des années. Pas de manière occasionnelle — intensivement. Plusieurs branches, plusieurs dépôts, plusieurs collaborateurs, toute la journée, tous les jours. Ce qui suit, ce sont les commandes et les workflows que j'utilise réellement. Pas ceux qui ont belle allure dans un tutoriel. Ceux qui me font gagner du temps réel, chaque semaine.

Rebase interactif : nettoyez votre bazar avant que quiconque ne le voie#

Votre branche a douze commits. La moitié sont « fix typo ». Un dit « undo previous commit ». Un autre dit « actually fix it this time ». Vous êtes sur le point d'ouvrir une PR. Personne n'a besoin de voir cet historique.

Le rebase interactif est la façon dont vous réécrivez l'historique sur votre branche avant de la partager. Il vous permet de fusionner des commits ensemble, reformuler des messages, les réordonner ou les supprimer entièrement.

La commande de base#

bash
git rebase -i HEAD~5

Cela ouvre un éditeur montrant vos 5 derniers commits, du plus ancien au plus récent :

bash
pick a1b2c3d Add user authentication endpoint
pick d4e5f6g Fix typo in auth middleware
pick h7i8j9k Add rate limiting
pick l0m1n2o Fix rate limit bug
pick p3q4r5s Update auth tests

Chaque ligne commence par une commande. Changez pick en une de celles-ci :

  • squash (ou s) — Fusionner ce commit dans celui au-dessus, combiner les messages
  • fixup (ou f) — Comme squash, mais abandonner le message de ce commit
  • reword (ou r) — Garder le commit mais changer son message
  • drop (ou d) — Supprimer ce commit entièrement
  • edit (ou e) — Mettre en pause le rebase à ce commit pour le modifier

Une vraie session de nettoyage#

Voici ce que je fais réellement. Cet historique désordonné ci-dessus devient :

bash
pick a1b2c3d Add user authentication endpoint
fixup d4e5f6g Fix typo in auth middleware
pick h7i8j9k Add rate limiting
fixup l0m1n2o Fix rate limit bug
pick p3q4r5s Update auth tests

Enregistrez et fermez. Maintenant vous avez trois commits propres au lieu de cinq. La correction de typo est intégrée dans le commit d'auth. La correction du bug de rate limit est intégrée dans le commit de rate limit. Votre relecteur de PR voit une progression propre et logique.

Réordonner les commits#

Vous pouvez littéralement réarranger les lignes. Si le commit de test devrait venir avant le commit de rate limiting, déplacez simplement la ligne :

bash
pick a1b2c3d Add user authentication endpoint
pick p3q4r5s Update auth tests
pick h7i8j9k Add rate limiting

Git va rejouer vos commits dans ce nouvel ordre. S'il y a des conflits, il mettra en pause et vous laissera les résoudre.

Le raccourci autosquash#

Si vous savez qu'un commit est une correction pour un précédent, marquez-le au moment du commit :

bash
git commit --fixup=a1b2c3d

Cela crée un commit avec le message fixup! Add user authentication endpoint. Puis quand vous rebasez :

bash
git rebase -i --autosquash HEAD~5

Git réordonne automatiquement les commits fixup juste en dessous de leurs cibles et les marque comme fixup. Vous n'avez qu'à enregistrer et fermer. Pas d'édition manuelle.

J'utilise cela constamment. C'est la façon la plus rapide d'itérer sur une branche tout en gardant l'historique final propre.

La règle d'or#

Ne jamais rebaser des commits qui ont été poussés vers une branche partagée. Si d'autres personnes ont basé du travail sur ces commits, réécrire l'historique causera de vrais problèmes. Rebasez vos propres branches de fonctionnalités avant de les fusionner. Ne rebasez jamais main.

Si vous avez déjà poussé votre branche de fonctionnalité et que vous devez rebaser :

bash
git push --force-with-lease

Le flag --force-with-lease est plus sûr que --force. Il refuse de pousser si quelqu'un d'autre a poussé vers la même branche depuis votre dernier fetch. Il n'empêchera pas tous les problèmes, mais il attrape le plus courant.

Cherry-pick : transferts chirurgicaux de commits#

Le cherry-pick prend un commit spécifique d'une branche et l'applique à une autre. Pas un merge. Pas un rebase. Juste un commit, proprement appliqué.

Quand je l'utilise réellement#

Le scénario le plus courant : j'ai corrigé un bug sur ma branche de fonctionnalité, mais la correction doit aussi aller sur main ou une branche de release immédiatement. Je ne veux pas fusionner ma branche de fonctionnalité entière. Je veux juste cette correction.

bash
# Trouver le hash du commit de la correction
git log --oneline feature/user-auth
# a1b2c3d Fix null pointer in session validation
 
# Basculer sur main et cherry-pick
git checkout main
git cherry-pick a1b2c3d

C'est fait. La correction est sur main comme un nouveau commit avec les mêmes modifications.

Cherry-pick sans commit#

Parfois vous voulez appliquer les modifications mais pas encore les commiter. Peut-être voulez-vous combiner plusieurs cherry-picks en un seul commit, ou modifier légèrement les changements :

bash
git cherry-pick --no-commit a1b2c3d

Les modifications sont stagées mais pas commitées. Vous pouvez les modifier, ajouter d'autres changements, puis commiter quand vous êtes prêt.

Cherry-pick par plage#

Besoin de plusieurs commits consécutifs ? Utilisez la syntaxe de plage :

bash
git cherry-pick a1b2c3d..f6g7h8i

Cela cherry-pick tout après a1b2c3d jusqu'à et y compris f6g7h8i. Notez que a1b2c3d lui-même est exclu. Si vous voulez l'inclure :

bash
git cherry-pick a1b2c3d^..f6g7h8i

Gérer les conflits#

Les conflits de cherry-pick fonctionnent comme les conflits de merge. Quand un se produit :

bash
# Git vous dit qu'il y a un conflit
# Corrigez les fichiers en conflit, puis :
git add .
git cherry-pick --continue

Ou si vous changez d'avis :

bash
git cherry-pick --abort

Une chose à surveiller : les commits cherry-pickés créent de nouveaux hashs de commit. Si vous mergez plus tard la branche originale, Git est généralement assez intelligent pour gérer la duplication. Mais si vous cherry-pickez agressivement entre des branches qui finiront par être mergées, vous pourriez voir des conflits inattendus. Utilisez-le chirurgicalement, pas comme stratégie de merge.

Git bisect : recherche binaire pour les bugs#

Quelque chose est cassé. Vous savez que ça marchait il y a deux semaines. Il y a eu 200 commits depuis. Lequel a tout cassé ?

Vous pourriez vérifier chaque commit manuellement. Ou vous pourriez utiliser git bisect, qui utilise la recherche binaire pour trouver le commit exact qui a cassé les choses en log2(n) étapes. Pour 200 commits, ça fait environ 7-8 vérifications au lieu de 200.

La méthode manuelle#

bash
# Commencer le bisect
git bisect start
 
# Marquer le commit actuel comme mauvais (le bug existe ici)
git bisect bad
 
# Marquer un commit connu comme bon (le bug n'existait pas ici)
git bisect good v2.1.0

Git checkout un commit à mi-chemin entre bon et mauvais. Testez-le. Puis :

bash
# Si le bug existe à ce commit :
git bisect bad
 
# Si le bug n'existe pas à ce commit :
git bisect good

Git réduit la plage de moitié à chaque fois. Après 7-8 étapes, il vous dit :

bash
a1b2c3d4e5f6g7h is the first bad commit
commit a1b2c3d4e5f6g7h
Author: Some Developer <dev@example.com>
Date: Tue Feb 18 14:23:01 2026 +0300
 
    Refactor session handling to use async middleware

Maintenant vous savez exactement quel commit a introduit le bug. Quand vous avez terminé :

bash
git bisect reset

Cela vous ramène là où vous avez commencé.

La méthode automatisée (c'est là que réside la vraie puissance)#

Si vous avez un test qui peut détecter le bug, vous pouvez automatiser le tout :

bash
git bisect start
git bisect bad HEAD
git bisect good v2.1.0
git bisect run npm test -- --grep "session validation"

Git va automatiquement checkout des commits, lancer le test et les marquer comme bons ou mauvais en fonction du code de sortie. Zéro signifie bon, non-zéro signifie mauvais. Partez, revenez, et il vous dit le commit exact.

Vous pouvez utiliser n'importe quel script :

bash
git bisect run ./test-regression.sh

test-regression.sh est :

bash
#!/bin/bash
npm run build 2>/dev/null || exit 125  # 125 signifie "sauter ce commit"
npm test -- --grep "session" || exit 1  # 1 signifie "mauvais"
exit 0                                   # 0 signifie "bon"

Le code de sortie 125 est spécial — il dit à bisect de sauter ce commit (utile si un commit ne compile pas). C'est une de ces fonctionnalités qui semblent niches jusqu'à ce que vous en ayez besoin, et alors elle vous épargne un après-midi entier.

Une vraie session de bisect#

Voici à quoi ça ressemble en pratique :

bash
$ git bisect start
$ git bisect bad HEAD
$ git bisect good abc1234
Bisecting: 97 revisions left to test after this (roughly 7 steps)
[def5678...] Commit message here
 
$ npm test -- --grep "login flow"
# Les tests échouent
 
$ git bisect bad
Bisecting: 48 revisions left to test after this (roughly 6 steps)
[ghi9012...] Another commit message
 
$ npm test -- --grep "login flow"
# Les tests passent
 
$ git bisect good
Bisecting: 24 revisions left to test after this (roughly 5 steps)
...
 
# Après ~7 itérations :
abc1234def5678ghi is the first bad commit

Sept étapes pour trouver une aiguille dans une botte de foin de 200 commits.

Git worktrees : plusieurs branches, zéro stash#

C'est la fonctionnalité Git la plus sous-utilisée. Je suis convaincu que la plupart des développeurs ne savent pas qu'elle existe.

Le problème : vous êtes en plein dans une branche de fonctionnalité. Des fichiers sont modifiés partout. Puis quelqu'un dit « tu peux jeter un œil à ce bug de production rapidement ? » Vous avez trois options :

  1. Tout stasher, changer de branche, corriger, revenir, pop le stash. Espérer que rien ne tourne mal.
  2. Commiter votre travail à moitié fait avec un message « wip ». Moche mais fonctionnel.
  3. Cloner le dépôt à nouveau dans un répertoire différent.

Ou l'option 4 : les worktrees.

Ce qu'est un worktree#

Un worktree est un deuxième (ou troisième, ou quatrième) répertoire de travail lié au même dépôt. Chaque worktree a sa propre branche checkoutée, ses propres fichiers de travail, son propre index. Mais ils partagent les mêmes données .git, donc vous ne dupliquez pas le dépôt entier.

Ajouter un worktree#

bash
# Vous êtes sur feature/user-auth, en plein dans le travail
# Besoin de corriger un bug sur main :
 
git worktree add ../hotfix-session main

Cela crée un nouveau répertoire ../hotfix-session avec main checkoué. Votre répertoire actuel reste exactement tel quel. Rien de stashé, rien de commité, rien de perturbé.

bash
cd ../hotfix-session
# Corriger le bug
git add .
git commit -m "Fix null pointer in session validation"
git push origin main
cd ../my-project
# Continuez à travailler sur votre fonctionnalité comme si rien ne s'était passé

Créer une nouvelle branche dans un worktree#

bash
git worktree add ../hotfix-nav -b hotfix/nav-crash main

Cela crée le worktree ET crée une nouvelle branche hotfix/nav-crash basée sur main.

Gérer les worktrees#

bash
# Lister tous les worktrees
git worktree list
# /home/dev/my-project         abc1234 [feature/user-auth]
# /home/dev/hotfix-session     def5678 [main]
 
# Supprimer un worktree quand c'est fini
git worktree remove ../hotfix-session
 
# Si le répertoire a déjà été supprimé :
git worktree prune

Pourquoi c'est mieux que le stash#

Le stash convient pour les changements de contexte rapides. Mais les worktrees sont meilleurs pour tout ce qui prend plus de cinq minutes :

  • Votre IDE reste ouvert sur votre branche de fonctionnalité. Pas de réindexation, pas de perte de votre position de défilement.
  • Vous pouvez lancer des tests dans les deux répertoires simultanément.
  • Pas de risque de conflits de stash ou d'oubli de ce que vous avez stashé.
  • Vous pouvez avoir un serveur de développement en cours d'exécution dans un worktree et un build propre dans un autre.

En général, je garde deux ou trois worktrees actifs : ma branche de fonctionnalité principale, un worktree main pour les vérifications rapides, et parfois un worktree de review où je checkout la PR de quelqu'un d'autre.

Le seul piège#

Vous ne pouvez pas avoir la même branche checkoutée dans deux worktrees. C'est par conception — cela vous empêche de faire des modifications conflictuelles sur la même branche à deux endroits. Si vous essayez, Git refusera.

Reflog : le bouton « annuler » pour tout#

Vous avez fait un hard reset et perdu des commits. Vous avez supprimé une branche. Vous avez rebasé et tout est parti de travers. Vous pensez que votre travail est perdu.

Ce n'est pas le cas. Git ne supprime presque jamais réellement quoi que ce soit. Le reflog est votre filet de sécurité.

Ce qu'est le reflog#

Chaque fois que HEAD bouge — chaque commit, checkout, rebase, reset, merge — Git l'enregistre dans le reflog. C'est un journal de tous les endroits où votre HEAD a été, dans l'ordre.

bash
git reflog

Sortie :

bash
a1b2c3d (HEAD -> main) HEAD@{0}: reset: moving to HEAD~3
f4e5d6c HEAD@{1}: commit: Add payment processing
b7a8c9d HEAD@{2}: commit: Update user dashboard
e0f1g2h HEAD@{3}: commit: Fix auth token refresh
i3j4k5l HEAD@{4}: checkout: moving from feature/payments to main

Chaque entrée a un index (HEAD@{0}, HEAD@{1}, etc.) et une description de ce qui s'est passé.

Récupérer après un hard reset#

Vous avez accidentellement lancé git reset --hard HEAD~3 et perdu trois commits. Ils sont juste là dans le reflog :

bash
# Voir ce que vous avez perdu
git reflog
 
# Le commit avant le reset est HEAD@{1}
git reset --hard f4e5d6c

Les trois commits sont de retour. Crise évitée.

Récupérer une branche supprimée#

Vous avez supprimé une branche qui avait du travail non fusionné :

bash
git branch -D feature/experimental
# Oh non, ça contenait deux semaines de travail

Les commits existent toujours. Trouvez-les :

bash
git reflog | grep "feature/experimental"
# Ou cherchez simplement dans le reflog le dernier commit sur cette branche
 
# Trouvé. Recréez la branche à ce commit :
git branch feature/experimental a1b2c3d

La branche est de retour, avec tous ses commits.

Récupérer après un mauvais rebase#

Vous avez rebasé et tout a mal tourné. Des conflits partout, des mauvais commits, le chaos :

bash
# Le reflog montre où vous étiez avant le rebase
git reflog
# a1b2c3d HEAD@{0}: rebase (finish): ...
# ...
# f4e5d6c HEAD@{5}: rebase (start): checkout main
# b7a8c9d HEAD@{6}: commit: Your last good commit
 
# Revenir à avant le rebase
git reset --hard b7a8c9d

Vous êtes de retour exactement là où vous étiez avant le début du rebase. Comme s'il ne s'était jamais produit.

Le filet de sécurité de 30 jours#

Par défaut, Git garde les entrées du reflog pendant 30 jours (90 jours pour les commits atteignables). Après ça, elles peuvent être nettoyées par le garbage collector. Donc vous avez un mois pour réaliser que vous avez fait une erreur. En pratique, c'est plus que suffisant.

Vous pouvez vérifier l'expiration :

bash
git config gc.reflogExpire
# par défaut : 90.days.ago (pour les commits atteignables)
git config gc.reflogExpireUnreachable
# par défaut : 30.days.ago (pour les commits non atteignables)

Si vous êtes paranoïaque, augmentez-la :

bash
git config --global gc.reflogExpireUnreachable "180.days.ago"

Une règle personnelle#

Avant toute opération destructive — hard reset, force push, suppression de branche — je lance git log --oneline -10 d'abord. Je note mentalement le HEAD actuel. Ça prend deux secondes et m'a sauvé plus d'une fois d'une panique inutile.

Stasher correctement : ce n'est pas juste git stash#

La plupart des gens utilisent le stash comme ça :

bash
git stash
# faire quelque chose
git stash pop

Ça marche, mais c'est l'équivalent de tout jeter dans une boîte étiquetée « trucs ». Quand vous avez trois stashs, vous n'avez aucune idée de ce qui correspond à quoi.

Nommez vos stashs#

bash
git stash push -m "WIP: validation du formulaire d'auth utilisateur"

Maintenant quand vous listez les stashs :

bash
git stash list
# stash@{0}: On feature/auth: WIP: validation du formulaire d'auth utilisateur
# stash@{1}: On main: Tentative de correction rapide du bug de nav
# stash@{2}: On feature/payments: Expérimentation avec les webhooks Stripe

Vous pouvez voir exactement ce que contient chaque stash.

Inclure les fichiers non suivis#

Par défaut, git stash ne stashe que les fichiers suivis. Les nouveaux fichiers que vous n'avez pas encore ajoutés sont laissés derrière :

bash
# Stasher tout, y compris les nouveaux fichiers
git stash push --include-untracked -m "WIP: nouveaux composants d'auth"
 
# Ou même inclure les fichiers ignorés (rarement nécessaire)
git stash push --all -m "Snapshot complet de l'espace de travail"

J'utilise --include-untracked presque à chaque fois. Laisser les nouveaux fichiers derrière quand vous changez de branche cause de la confusion.

Stash partiel#

C'est celui que la plupart des gens ne connaissent pas. Vous pouvez stasher des fichiers spécifiques :

bash
# Stasher seulement des fichiers spécifiques
git stash push -m "Juste les changements d'auth" src/auth/ src/middleware.ts

Ou utilisez le mode patch pour stasher des hunks spécifiques à l'intérieur des fichiers :

bash
git stash push --patch -m "Partiel : seulement la logique de validation"

Git parcourra chaque modification de façon interactive et demandera si vous voulez la stasher. y pour oui, n pour non, s pour diviser le hunk en morceaux plus petits.

Apply vs pop#

bash
# Pop : appliquer et supprimer de la liste des stashs
git stash pop stash@{2}
 
# Apply : appliquer mais garder dans la liste des stashs
git stash apply stash@{2}

J'utilise apply quand je ne suis pas sûr que le stash s'appliquera proprement. S'il y a un conflit, le stash est préservé. Avec pop, s'il y a un conflit, le stash reste dans la liste de toute façon (beaucoup de gens ne le savent pas), mais je préfère l'intention explicite de apply.

Voir le contenu d'un stash#

bash
# Voir quels fichiers ont changé dans un stash
git stash show stash@{0}
 
# Voir le diff complet
git stash show -p stash@{0}

Créer une branche depuis un stash#

Si votre stash s'est transformé en quelque chose de plus conséquent :

bash
git stash branch feature/auth-validation stash@{0}

Cela crée une nouvelle branche depuis le commit où vous avez originellement stashé, applique le stash et le supprime. Propre.

Stratégies de branching : laquelle fonctionne vraiment#

Il existe trois stratégies de branching courantes. Chacune a un contexte où elle brille et des contextes où elle cause des problèmes.

Gitflow#

Le classique. main, develop, feature/*, release/*, hotfix/*. Créé par Vincent Driessen en 2010.

bash
# Branche de fonctionnalité
git checkout -b feature/user-auth develop
# ... travail ...
git checkout develop
git merge --no-ff feature/user-auth
 
# Branche de release
git checkout -b release/2.1.0 develop
# ... corrections finales ...
git checkout main
git merge --no-ff release/2.1.0
git tag -a v2.1.0 -m "Release 2.1.0"
git checkout develop
git merge --no-ff release/2.1.0
 
# Hotfix
git checkout -b hotfix/session-fix main
# ... correction ...
git checkout main
git merge --no-ff hotfix/session-fix
git checkout develop
git merge --no-ff hotfix/session-fix

Quand ça marche : Applications mobiles, logiciels desktop, tout ce qui a des releases versionnées nommées et plusieurs versions supportées simultanément. Si vous livrez la v2.1 et la v3.0 et devez patcher les deux, Gitflow gère ça.

Quand ça ne marche pas : Applications web avec déploiement continu. Si vous déployez en production 5 fois par jour, la cérémonie des branches de release et de develop est de la surcharge pure. La plupart des équipes web qui adoptent Gitflow se retrouvent avec une branche develop perpétuellement cassée et des branches de release que personne ne comprend.

GitHub Flow#

Simple. Vous avez main. Vous créez des branches de fonctionnalités. Vous ouvrez des PR. Vous mergez dans main. Vous déployez main.

bash
git checkout -b feature/user-auth main
# ... travail ...
git push origin feature/user-auth
# Ouvrir une PR, se faire relire, merger
# main est toujours déployable

Quand ça marche : Petites à moyennes équipes livrant des applications web. Déploiement continu. Si main est toujours déployé, c'est tout ce dont vous avez besoin. C'est ce que ce site utilise.

Quand ça ne marche pas : Quand vous devez maintenir plusieurs versions de release, ou quand vous avez un long cycle de QA avant le déploiement. GitHub Flow suppose que main va en production rapidement.

Développement basé sur le trunk#

Tout le monde commit sur main (le « trunk ») directement ou via des branches de très courte durée (moins d'un jour). Pas de branches de fonctionnalités de longue durée.

bash
# Branche de courte durée (mergée le jour même)
git checkout -b fix/auth-token main
# ... changement petit et ciblé ...
git push origin fix/auth-token
# PR relue et mergée en quelques heures, pas des jours

Quand ça marche : Équipes performantes avec une bonne CI/CD, des suites de tests complètes et des feature flags. Google, Meta et la plupart des grandes entreprises tech utilisent le développement basé sur le trunk. Ça force des changements petits et incrémentaux et élimine l'enfer des merges.

Quand ça ne marche pas : Équipes sans bonne couverture de tests ou CI. Si merger dans le trunk signifie déployer du code non testé, vous casserez la production constamment. Vous avez aussi besoin de feature flags pour tout ce qui prend plus d'un jour à construire :

bash
# Feature flag dans le code
if (featureFlags.isEnabled('new-checkout-flow')) {
  renderNewCheckout();
} else {
  renderLegacyCheckout();
}

Ma recommandation#

Pour la plupart des équipes de développement web : commencez avec GitHub Flow. C'est simple, ça marche, et ça ne nécessite pas d'outillage au-delà de ce que GitHub/GitLab fournit déjà.

Si votre équipe dépasse 15-20 ingénieurs et que vous déployez plusieurs fois par jour, regardez le développement basé sur le trunk avec des feature flags. L'investissement dans l'infrastructure de feature flags se rentabilise en réduisant les conflits de merge et en accélérant les itérations.

Si vous livrez du logiciel versionné (applications mobiles, outils CLI, bibliothèques) : Gitflow ou une version simplifiée. Vous avez réellement besoin de ces branches de release.

Ne choisissez pas une stratégie parce qu'un article de blog a dit que c'est la meilleure. Choisissez celle qui correspond à la façon dont vous livrez réellement.

Git hooks : automatisez ce que vous oubliez sans cesse#

Les hooks Git sont des scripts qui s'exécutent automatiquement à des moments spécifiques du workflow Git. Ils sont locaux à votre machine (pas poussés vers le remote), ce qui signifie que vous avez besoin d'un moyen de les partager avec votre équipe.

Les hooks qui comptent vraiment#

pre-commit — S'exécute avant chaque commit. Utilisez-le pour le linting et le formatage :

bash
#!/bin/bash
# .git/hooks/pre-commit
 
# Lancer ESLint uniquement sur les fichiers stagés
STAGED_FILES=$(git diff --cached --name-only --diff-filter=ACM | grep -E '\.(js|ts|tsx)$')
 
if [ -n "$STAGED_FILES" ]; then
  echo "Lancement d'ESLint sur les fichiers stagés..."
  npx eslint $STAGED_FILES --quiet
  if [ $? -ne 0 ]; then
    echo "ESLint a échoué. Corrigez les erreurs avant de commiter."
    exit 1
  fi
fi
 
# Lancer Prettier sur les fichiers stagés
if [ -n "$STAGED_FILES" ]; then
  echo "Lancement de Prettier..."
  npx prettier --check $STAGED_FILES
  if [ $? -ne 0 ]; then
    echo "La vérification Prettier a échoué. Lancez 'npx prettier --write' d'abord."
    exit 1
  fi
fi

commit-msg — Valide le format du message de commit. Parfait pour appliquer les conventional commits :

bash
#!/bin/bash
# .git/hooks/commit-msg
 
COMMIT_MSG=$(cat "$1")
PATTERN="^(feat|fix|docs|style|refactor|test|chore|perf|ci|build|revert)(\(.+\))?: .{1,72}"
 
if ! echo "$COMMIT_MSG" | grep -qE "$PATTERN"; then
  echo "Format de message de commit invalide."
  echo "Attendu : type(scope): description"
  echo "Exemple : feat(auth): add session refresh endpoint"
  echo ""
  echo "Types valides : feat, fix, docs, style, refactor, test, chore, perf, ci, build, revert"
  exit 1
fi

pre-push — S'exécute avant le push. Utilisez-le pour les tests :

bash
#!/bin/bash
# .git/hooks/pre-push
 
echo "Lancement des tests avant le push..."
npm test
if [ $? -ne 0 ]; then
  echo "Les tests ont échoué. Push annulé."
  exit 1
fi

Husky vs hooks natifs#

Les hooks natifs vivent dans .git/hooks/. Le problème : le répertoire .git n'est pas suivi par Git, donc vous ne pouvez pas partager les hooks via le dépôt. Tout le monde doit les configurer manuellement.

Husky résout ce problème. Il stocke les configurations de hooks dans le dépôt et configure .git/hooks automatiquement lors du npm install :

bash
npx husky init

Cela crée un répertoire .husky/. Ajoutez les hooks comme fichiers :

bash
# .husky/pre-commit
npx lint-staged

Combiné avec lint-staged, vous obtenez des vérifications pre-commit rapides et ciblées :

json
{
  "lint-staged": {
    "*.{js,ts,tsx}": ["eslint --fix", "prettier --write"],
    "*.css": ["prettier --write"],
    "*.json": ["prettier --write"]
  }
}

Cela lance ESLint et Prettier uniquement sur les fichiers que vous êtes en train de commiter. Pas sur le codebase entier. Rapide.

Quand sauter les hooks#

Parfois vous devez commiter sans que les hooks ne s'exécutent. Hotfix d'urgence, commits work-in-progress sur votre propre branche :

bash
git commit --no-verify -m "WIP: débogage du problème de production"

Utilisez ceci avec parcimonie. Si vous vous retrouvez à sauter les hooks régulièrement, vos hooks sont probablement trop lents ou trop stricts.

Alias qui font gagner du temps#

Mon .gitconfig a évolué au fil des années. Voici les alias qui ont survécu — ceux que j'utilise réellement au quotidien, pas ceux que j'ai ajoutés parce qu'ils avaient l'air malins.

Log élégant#

Le git log par défaut est verbeux. Ceci vous donne une vue propre, colorée et basée sur un graphe :

bash
git config --global alias.lg "log --oneline --graph --all --decorate"

Utilisation :

bash
git lg
# * a1b2c3d (HEAD -> main) Fix session validation
# | * d4e5f6g (feature/payments) Add Stripe integration
# | * h7i8j9k Update payment models
# |/
# * l0m1n2o Merge PR #42
# * p3q4r5s Add user dashboard

Je lance ça 20 fois par jour. C'est la façon la plus rapide de comprendre l'état de votre dépôt.

Annuler le dernier commit#

Garder les modifications, juste annuler le commit :

bash
git config --global alias.undo "reset HEAD~1 --mixed"

Utilisation :

bash
git undo
# Le commit a disparu, mais tous les changements sont toujours dans votre répertoire de travail

J'utilise ça quand je commite trop tôt, oublie un fichier, ou veux restructurer les modifications.

Tout dé-stager#

bash
git config --global alias.unstage "reset HEAD --"

Utilisation :

bash
git unstage src/auth/session.ts
# Le fichier est dé-stagé mais les modifications sont préservées

Lister tous les alias#

Parce que vous oublierez ce que vous avez configuré :

bash
git config --global alias.aliases "config --get-regexp ^alias\\."

Plus d'alias que j'utilise#

bash
# Montrer ce que vous êtes sur le point de commiter
git config --global alias.staged "diff --staged"
 
# Statut court
git config --global alias.st "status -sb"
 
# Amender sans changer le message
git config --global alias.amend "commit --amend --no-edit"
 
# Montrer le dernier commit
git config --global alias.last "log -1 HEAD --stat"
 
# Pull avec rebase au lieu de merge
git config --global alias.up "pull --rebase --autostash"
 
# Supprimer les branches qui ont été mergées dans main
git config --global alias.cleanup "!git branch --merged main | grep -v '^[ *]*main$' | xargs git branch -d"

L'alias up est particulièrement bon. pull --rebase garde votre historique linéaire au lieu de créer des commits de merge pour chaque pull. --autostash stashe et restaure automatiquement vos modifications si vous avez des fichiers modifiés. C'est ce que pull aurait dû être par défaut.

L'alias cleanup supprime les branches locales qui ont été mergées dans main. Avec le temps, vous accumulez des dizaines de branches obsolètes. Lancez ça une fois par semaine.

Les commandes que j'utilise au quotidien#

Ce ne sont ni des alias ni des fonctionnalités avancées. Ce sont juste des commandes que je lance constamment et que beaucoup de développeurs ne semblent pas connaître.

La commande de log ultime#

bash
git log --oneline --graph --all

Cela montre chaque branche, chaque merge, la topologie entière de votre dépôt dans une vue compacte. C'est la première chose que je lance quand je pull des changements. Ça répond à « que se passe-t-il dans ce dépôt en ce moment ? »

Diff des modifications stagées#

bash
git diff --staged

Cela montre ce qui est sur le point d'être commité. Pas ce qui a changé dans votre répertoire de travail — ce qui est réellement stagé. Je lance toujours ça avant de commiter. Toujours. Ça attrape les inclusions accidentelles, les instructions de débogage, les console.logs qui ne devraient pas être là.

bash
# Voir les modifications non stagées
git diff
 
# Voir les modifications stagées
git diff --staged
 
# Voir les deux
git diff HEAD

Montrer un commit spécifique#

bash
git show a1b2c3d

Montre le diff complet d'un seul commit. Utile pour revoir l'historique, comprendre ce qu'un commit a réellement changé.

bash
# Montrer juste les fichiers qui ont changé
git show --stat a1b2c3d
 
# Montrer un fichier spécifique à un commit spécifique
git show a1b2c3d:src/auth/session.ts

Ce dernier est incroyablement utile. Vous pouvez voir n'importe quel fichier à n'importe quel moment de l'historique sans checkout ce commit.

Blame avec plages de lignes#

bash
git blame -L 42,60 src/auth/session.ts

Montre qui a modifié les lignes 42-60 en dernier. Plus utile que de blamer le fichier entier, ce qui est généralement accablant.

bash
# Montrer aussi le message de commit, pas juste le hash
git blame -L 42,60 --show-name src/auth/session.ts
 
# Ignorer les modifications d'espaces blancs (très utile)
git blame -w -L 42,60 src/auth/session.ts
 
# Montrer le commit avant celui blamé (creuser plus profond)
git log --follow -p -- src/auth/session.ts

Le flag -w est important. Sans lui, blame attribuera les lignes à celui qui a reformaté le fichier en dernier, ce qui n'est rarement la personne que vous cherchez.

Trouver une chaîne dans tout l'historique#

bash
# Trouver quand une fonction a été ajoutée ou supprimée
git log -S "validateSession" --oneline
 
# Trouver quand un pattern regex est apparu
git log -G "session.*timeout" --oneline

-S (le « pickaxe ») trouve les commits où le nombre d'occurrences d'une chaîne a changé. -G trouve les commits où le diff correspond à une regex. Les deux sont puissants pour l'archéologie — comprendre quand quelque chose a été introduit ou supprimé.

Montrer ce qui a changé entre deux points#

bash
# Ce qui a changé entre deux branches
git diff main..feature/auth
 
# Ce qui a changé sur cette branche depuis qu'elle a divergé de main
git diff main...feature/auth
 
# Lister juste les fichiers modifiés
git diff main...feature/auth --name-only
 
# Vue stat (fichiers + insertions/suppressions)
git diff main...feature/auth --stat

Deux points vs trois points, ça compte. Deux points montrent la différence entre les extrémités des deux branches. Trois points montrent ce qui a changé du côté droit depuis qu'il a divergé du côté gauche. Trois points est généralement ce que vous voulez quand vous relisez une branche de fonctionnalité.

Nettoyer les fichiers non suivis#

bash
# Voir ce qui serait supprimé (dry run)
git clean -n
 
# Supprimer les fichiers non suivis
git clean -f
 
# Supprimer les fichiers et répertoires non suivis
git clean -fd
 
# Supprimer les fichiers non suivis et ignorés (option nucléaire)
git clean -fdx

Lancez toujours avec -n d'abord. git clean -fdx va supprimer vos node_modules, .env, les artefacts de build — tout ce qui n'est pas suivi par Git. Utile pour un redémarrage vraiment propre, mais destructif.

Restaurer un seul fichier depuis une autre branche#

bash
# Obtenir la version main d'un fichier sans changer de branche
git restore --source main -- src/config/database.ts

Ou depuis un commit spécifique :

bash
git restore --source a1b2c3d -- src/config/database.ts

C'est plus propre que l'ancienne syntaxe git checkout main -- path/to/file, et ça n'affecte pas HEAD.

Tout assembler : un vrai workflow#

Voici à quoi ressemble une journée typique avec ces outils :

bash
# Matin : vérifier ce qui se passe
git lg
git fetch --all
 
# Commencer une fonctionnalité
git checkout -b feature/session-refresh main
 
# Travailler, commiter de façon incrémentale
git add -p                        # Stager des hunks spécifiques, pas des fichiers entiers
git commit -m "Add token refresh endpoint"
git commit -m "Add refresh token rotation"
git commit -m "Fix: handle expired refresh tokens"
git commit -m "Add integration tests"
 
# Interrompu : besoin de corriger un bug de production
git worktree add ../hotfix main
cd ../hotfix
# ... corriger, commiter, pousser, PR mergée ...
cd ../my-project
git worktree remove ../hotfix
 
# Retour au travail sur la fonctionnalité
git commit -m "Fix edge case in token validation"
 
# Prêt pour la PR : nettoyer l'historique
git rebase -i main
# Squasher les commits de correction, reformuler pour la clarté
 
# Pousser et ouvrir la PR
git push -u origin feature/session-refresh
 
# Quelque chose a cassé en staging ? Trouver quel commit :
git bisect start
git bisect bad HEAD
git bisect good main
git bisect run npm test
 
# Oups, j'ai fait un hard-reset sur le mauvais truc
git reflog
git reset --hard HEAD@{2}

Chacune de ces commandes prend quelques secondes. Ensemble, elles font gagner des heures. Pas des heures hypothétiques — de vraies heures, chaque semaine, que je passerais autrement à démêler des problèmes Git, à chercher manuellement des bugs ou à perdre du travail lors de changements de contexte.

Git est un outil qui récompense la profondeur. Les bases vous font passer la journée. Mais les commandes de cet article sont ce qui sépare « j'utilise Git » de « Git me rend réellement plus rapide ». Apprenez-les de façon incrémentale. Choisissez une nouvelle technique cette semaine et utilisez-la jusqu'à ce qu'elle soit dans votre mémoire musculaire. Puis choisissez-en une autre.

Votre futur vous, en train de fixer un bug de production à 23 heures, vous remerciera de connaître git bisect.

Articles similaires