Aller au contenu
Développement medium

Rechercher dans Git : grep, log -S, log -L

12 min de lecture

git grep cherche du texte dans votre code actuel, git log -S trouve le commit qui a introduit ou supprimé une chaîne, et git log -L retrace l'historique d'une fonction. Ces trois outils couvrent tous les besoins de recherche dans un dépôt Git, bien plus efficacement que grep classique.

Prérequis : Consulter l'historique et Sélection de révisions.

  • Utiliser git grep pour chercher du texte dans tous les fichiers suivis
  • Rechercher avec log -S les commits qui ont introduit ou supprimé une chaîne
  • Localiser des changements dans une fonction avec log -L
  • Combiner ces outils pour un workflow de débogage par l'historique

git grep est plus rapide que grep -r car il ne parcourt que les fichiers suivis par Git (il ignore node_modules/, .git/, les artefacts de build...).

Sans argument supplémentaire, git grep cherche dans l'index et le répertoire de travail, c'est-à-dire dans les fichiers tels qu'ils existent maintenant. Chaque résultat est préfixé du chemin relatif à la racine du dépôt, quel que soit le sous-répertoire depuis lequel vous lancez la commande : c'est ce qui rend la sortie directement réutilisable dans un éditeur ou un script.

Fenêtre de terminal
# Chercher une chaîne dans tout le repo
git grep "TODO"
# Résultat :
# src/app.py:42: # TODO: gérer les erreurs
# src/utils.py:18: # TODO: optimiser cette boucle

Ces options se combinent librement, et trois d'entre elles changent la nature du résultat plutôt que sa présentation. -l ne renvoie que des chemins, ce qui en fait l'option à utiliser quand vous enchaînez sur xargs. -c renvoie un compteur par fichier, utile pour mesurer l'ampleur d'une dette avant de la traiter. -p remonte la ligne de déclaration englobante, ce qui vous évite d'ouvrir le fichier pour savoir dans quelle fonction se trouve le résultat. Les autres options affinent la correspondance sans changer le format.

OptionEffetExemple
-nAffiche les numéros de lignegit grep -n "TODO"
-cCompte les occurrences par fichiergit grep -c "TODO"
-lListe uniquement les fichiersgit grep -l "TODO"
-iInsensible à la cassegit grep -i "error"
-wMot entier uniquementgit grep -w "log"
-pAffiche la fonction englobantegit grep -p "calculate"
--headingRegroupe par fichiergit grep --heading -n "TODO"
-eSpécifie un motif (pour les regex)git grep -e "err[ou]r"

Le point à retenir tient en une phrase : les opérateurs booléens de git grep s'appliquent à la ligne, pas au fichier. --and ne sélectionne donc que les lignes où les deux motifs coexistent, ce qui n'est presque jamais ce qu'on cherche quand on veut « les fichiers qui parlent des deux sujets ». Pour ce besoin, il faut --all-match combiné à --or : il conserve les fichiers dont chaque motif est satisfait par au moins une ligne, éventuellement différente.

Fenêtre de terminal
# Lignes contenant "calculate" ET "price" sur la MÊME ligne
git grep -e "calculate" --and -e "price"
# Fichiers contenant "calculate" ET "price", même sur des lignes distinctes
git grep -l --all-match -e "calculate" --or -e "price"
# Lignes contenant "error" OU "warning"
git grep -e "error" --or -e "warning"

Vérifiez la différence sur un fichier où les deux mots sont sur des lignes séparées : la première commande ne renvoie rien, la deuxième renvoie le fichier.

Chercher dans un commit ou une branche spécifique

Section intitulée « Chercher dans un commit ou une branche spécifique »

Ajouter une révision en fin de commande fait basculer git grep du répertoire de travail vers l'arbre de ce commit. Vous interrogez alors le code tel qu'il était, sans avoir à changer de branche ni à créer de copie de travail : rien n'est écrit sur le disque. C'est la façon la plus rapide de répondre à « cette chaîne existait-elle en v1.0 ? », et le seul piège est d'oublier que les fichiers non suivis à cette révision sont, par définition, absents du résultat.

Fenêtre de terminal
# Chercher dans le commit v1.0
git grep "TODO" v1.0
# Chercher dans une autre branche
git grep "calculate_price" feature/pricing
# Chercher dans HEAD~5
git grep "deprecated" HEAD~5

Le « pickaxe » trouve les commits qui ont ajouté ou supprimé une chaîne spécifique. Contrairement à grep qui cherche dans l'état actuel, -S explore tout l'historique :

Fenêtre de terminal
# Qui a introduit la fonction calculate_price ?
git log -S "calculate_price" --oneline
# a1b2c3d Ajout du module de tarification
# e4f5a6b Suppression de l'ancien calcul
# Avec le diff complet
git log -S "calculate_price" -p

Trois variantes couvrent l'essentiel des usages. -G remplace la recherche littérale par une expression régulière évaluée sur le diff. Le filtre -- <chemin> restreint le parcours de l'historique et fait chuter le temps d'exécution sur un gros dépôt, ce qui compte puisque le pickaxe reconstruit un diff pour chaque commit examiné. --stat ajoute la liste des fichiers touchés, pratique quand la même chaîne a migré d'un module à l'autre.

Fenêtre de terminal
# Avec regex (-G au lieu de -S)
git log -G "calc.*price" --oneline
# Limité à certains fichiers
git log -S "API_KEY" -- src/config/
# Avec les noms de fichiers affectés
git log -S "deprecated_function" --stat

-L retrace l'historique d'un bloc de lignes ou d'une fonction à travers tous les commits :

Cette forme suit un bloc de lignes dans le temps, en tenant compte des décalages provoqués par les commits antérieurs. Les numéros que vous indiquez sont ceux de la révision de départ, HEAD par défaut : inutile de calculer où se trouvaient ces lignes il y a six mois, Git remonte la piste tout seul.

Fenêtre de terminal
# Historique des lignes 10 à 25 de app.py
git log -L 10,25:src/app.py
Fenêtre de terminal
# Historique de la fonction calculate_price dans app.py
git log -L :calculate_price:src/app.py

Git repère les bornes de la fonction avec un motif de hunk header. Sans configuration, ce motif est générique : toute ligne qui commence en colonne 0 par une lettre, un souligné ou un dollar est considérée comme un début de bloc, ce qui suffit pour Python, Go ou C. Pour les langages où cette heuristique échoue, déclarez le pilote adapté dans .gitattributes, par exemple *.py diff=python. Chaque commit est ensuite affiché avec le diff correspondant, du plus récent au plus ancien.

Deux détails de cette sortie méritent votre attention. L'en-tête @@ -10,5 +10,7 @@ indique que le bloc suivi occupait 5 lignes avant le commit et 7 après : c'est ainsi que vous repérez d'un coup d'œil un commit qui a fait grossir une fonction. Et contrairement à un git log -p classique, le diff est restreint au bloc suivi, même si le commit modifiait dix autres endroits du fichier.

commit a1b2c3d
Author: Alice <alice@example.com>
Date: Mon Mar 15 14:30:00 2026
fix: corriger la remise pour les gros volumes
diff --git a/src/app.py b/src/app.py
--- a/src/app.py
+++ b/src/app.py
@@ -10,5 +10,7 @@
def calculate_price(quantity, unit_price):
total = quantity * unit_price
+ if quantity > 100:
+ total *= 0.9
return total

Ce tableau se lit par la colonne Besoin, formulée comme la question que vous vous posez réellement. La ligne de partage est simple : git grep interroge un état du dépôt, les trois formes de git log interrogent des changements, et git blame répond à une question de responsabilité sur une ligne précise. Se tromper de famille est la cause la plus courante d'une recherche qui ne donne rien, typiquement chercher avec git grep une chaîne supprimée il y a deux ans.

BesoinCommandeExemple
Texte dans le code actuelgit grepgit grep "TODO"
Texte dans une version passéegit grep ... refgit grep "TODO" v1.0
Commit ayant introduit une chaînegit log -Sgit log -S "calc"
Commit ayant touché une regexgit log -Ggit log -G "calc.*"
Historique d'une fonctiongit log -Lgit log -L :func:file
Commit contenant un mot dans le messagegit log --grepgit log --grep="fix"
Auteur d'une lignegit blamegit blame file.py

L'enchaînement ci-dessous va du plus large au plus précis, et chaque commande consomme le résultat de la précédente. Vous partez d'un nom de symbole, vous obtenez des chemins, puis des commits, puis un diff ligne à ligne, puis un auteur à qui poser la question. Suivre cet ordre évite le réflexe coûteux qui consiste à lancer git blame en premier : blame ne montre que le dernier commit ayant touché chaque ligne, ce qui masque complètement l'historique d'une ligne plusieurs fois réécrite.

Fenêtre de terminal
# 1. Trouver où la fonction est utilisée
git grep -n "calculate_price"
# 2. Quand a-t-elle été modifiée ?
git log -S "calculate_price" --oneline
# 3. Voir l'évolution complète de la fonction
git log -L :calculate_price:src/app.py
# 4. Qui a écrit cette ligne spécifique ?
git blame -L 42,50 src/app.py

Les quatre situations ci-dessous couvrent la quasi-totalité des recherches qui échouent. Deux d'entre elles ne sont pas des pannes mais des malentendus sur le périmètre : git grep ignore ce que Git ne suit pas, et le pickaxe parcourt tout l'historique tant que vous ne le contraignez pas. Dans les deux cas, le correctif consiste à préciser la portée, pas à changer d'outil.

SymptômeCause probableSolution
git grep ne trouve rienFichier non suivi ou ignoréVérifiez avec git ls-files
-L :func: ne détecte pas la fonctionLangage non reconnuAjoutez un pattern dans .gitattributes
-S retourne trop de résultatsChaîne trop courte/génériquePrécisez avec -- chemin/
Recherche lente sur gros repoHistorique volumineuxLimitez avec --since ou -- chemin/
  • git grep : rapide, cherche dans le code actuel (ou une révision donnée)
  • git log -S (pickaxe) : trouve le commit qui a introduit/supprimé une chaîne
  • git log -G : comme -S mais avec des regex et sur le diff
  • git log -L : retrace l'historique complet d'une fonction
  • Combinez ces outils pour un débogage efficace : grep-S-Lblame

Ce site vous est utile ?

Sachez que moins de 1% des lecteurs soutiennent ce site.

Je maintiens +700 guides gratuits, sans pub ni tracking. Un soutien, même symbolique, m'aide à couvrir l'hébergement et à garder ces ressources gratuites. Merci pour votre appui.

Le formulaire ne s'affiche pas ? Ouvrir Ko-fi dans un onglet.

Abonnez-vous et suivez mon actualité DevSecOps sur LinkedIn