git cherry-pick & git bisect — Chirurgie de précision
Objectifs de la section
- Utiliser
git cherry-pickpour appliquer des commits spécifiques à une autre branche - Utiliser
git bisectpour trouver le commit qui a introduit un bug - Connaître les limitations et cas d'usage de ces commandes
git cherry-pick — Appliquer des commits spécifiques
git cherry-pick prend un commit d'une branche et l'applique à une autre, créant un nouveau commit avec les mêmes changements (hash différent).
Utilisation de base
# Cherry-pick d'un seul commit
git cherry-pick abc1234
# Cherry-pick de plusieurs commits
git cherry-pick abc1234 def5678 ghi9012
# Cherry-pick d'une plage de commits (exclusif du premier)
git cherry-pick abc1234..def5678
# Cherry-pick sans créer de commit (staging uniquement)
git cherry-pick --no-commit abc1234
# Cherry-pick en éditant le message de commit
git cherry-pick -e abc1234
Gérer les conflits de cherry-pick
# Si un conflit se produit :
# 1. Corriger le conflit
git status # Affiche les fichiers en conflit
# éditer les fichiers...
git add fichier-corrige.py
# 2. Continuer
git cherry-pick --continue
# OU : Abandonner
git cherry-pick --abort
# OU : Ignorer ce commit
git cherry-pick --skip
Quand utiliser cherry-pick
| Scénario | Utiliser cherry-pick ? | Alternative |
|---|---|---|
| Correction critique nécessaire sur la branche release | ✅ Oui | - |
| Commit accidentellement sur la mauvaise branche | ✅ Oui | - |
| Réutiliser une fonction utilitaire d'une autre branche | ✅ Oui | - |
| Intégrer toute une fonctionnalité | ❌ Non | Merge ou rebase |
| Synchronisation régulière des branches | ❌ Non | Merge ou rebase |
Cherry-pick crée une copie du commit (nouveau hash). Si vous fusionnez ensuite la branche originale, Git verra ces changements en double. Utilisez cherry-pick avec parcimonie et pour des cas spécifiques.
Exemples pratiques
# Scénario 1 : Correction critique nécessaire sur la branche release
git switch release/v1.0
git cherry-pick hash-du-commit-hotfix
git push origin release/v1.0
# Scénario 2 : Commit sur la mauvaise branche
git log --oneline # Trouver le hash du commit à déplacer
git switch bonne-branche
git cherry-pick abc1234 # Appliquer sur la bonne branche
git switch mauvaise-branche
git reset HEAD~1 # Supprimer de la mauvaise branche
git bisect — Recherche binaire de bugs
git bisect effectue une recherche binaire dans votre historique de commits pour trouver le commit exact qui a introduit un bug.
Bisect manuel
# 1. Démarrer bisect
git bisect start
# 2. Marquer le commit actuel comme mauvais (bug présent)
git bisect bad
# 3. Marquer un commit connu comme bon (pas de bug)
git bisect good v1.0.0
# ou par hash :
git bisect good abc1234
# Git va checkout le commit du milieu
# Tester votre application...
# 4. Marquer chaque commit testé
git bisect good # Pas de bug sur ce commit
git bisect bad # Bug présent sur ce commit
# 5. Git trouve et affiche le commit coupable :
# abc1234 est le premier mauvais commit
# 6. Quitter bisect
git bisect reset # Retourne au HEAD original
Bisect automatisé
Si vous avez un test qui peut détecter le bug, vous pouvez automatiser complètement bisect.
Créez un script de test test_bug.sh :
#!/bin/bash
# Retourne 0 (succès) si pas de bug, 1 si bug présent
python -c "
from app import obtenir_statistiques
from app import TACHES
TACHES.clear()
try:
stats = obtenir_statistiques()
if stats['total'] == 0:
exit(0)
else:
exit(1)
except ZeroDivisionError:
exit(1)
"
chmod +x test_bug.sh
# Laisser Git faire le bisect automatiquement !
git bisect start
git bisect bad HEAD
git bisect good v1.0.0
git bisect run ./test_bug.sh
# Git exécute le script sur chaque commit et trouve le coupable automatiquement
# À la fin :
git bisect reset
Log et replay de bisect
# Sauvegarder une session bisect pour plus tard
git bisect log > session-bisect.log
# Rejouer une session sauvegardée
git bisect replay session-bisect.log
git reflog — Le filet de sécurité
git reflog enregistre chaque mouvement de HEAD dans votre dépôt — c'est votre filet de sécurité ultime :
# Voir le reflog
git reflog
# Sortie :
# d5a1b4c HEAD@{0}: commit: feat: ajout statistiques
# c2e8f3a HEAD@{1}: checkout: moving from feature to main
# b7c9d1e HEAD@{2}: reset: moving to HEAD~1
# a3f4b2c HEAD@{3}: commit: feat: ajout recherche
Récupérer des commits « perdus »
# Vous avez accidentellement lancé git reset --hard et perdu des commits
git reset --hard HEAD~5 # Oups !
# Trouver les commits perdus dans le reflog
git reflog
# HEAD@{2} était avant le reset
# Récupérer
git reset --hard HEAD@{2}
# Ou créer une nouvelle branche depuis l'état perdu
git switch -c branche-recuperee HEAD@{2}
Le reflog n'est pas poussé vers GitHub. C'est un filet de sécurité local uniquement. Les entrées de reflog sont conservées 90 jours par défaut.
Résumé
| Commande | Description |
|---|---|
git cherry-pick <hash> | Appliquer un commit spécifique |
git cherry-pick --continue | Continuer après un conflit |
git cherry-pick --abort | Annuler le cherry-pick |
git bisect start | Démarrer la recherche binaire |
git bisect good/bad | Marquer un commit comme bon/mauvais |
git bisect run <script> | Bisect automatisé |
git bisect reset | Terminer la session bisect |
git reflog | Voir tous les mouvements de HEAD |