Git
Chapters ▾ 2nd Edition

7.5 Utilitaires Git - Recherche

Recherche

Quelle que soit la taille de votre code, vous avez souvent besoin de chercher où une fonction est appelée ou définie, ou de retrouver l’historique d’une méthode. Git fournit quelques outils permettant rapidement de rechercher dans le code et les commits stockés dans votre base de données. Nous allons en détailler quelques uns.

Git grep

Git est livré avec une commande appelée grep qui permet de rechercher facilement une chaîne de caractères ou une expression régulière dans une arborescence validée ou dans le répertoire de travail. Pour tous les exemples qui suivent, nous allons utiliser le dépôt de Git lui-même.

Par défaut, git grep recherche dans le répertoire de travail. Vous pouvez passer l’option -n pour afficher les numéros des lignes des correspondances.

$ git grep -n gmtime_r
compat/gmtime.c:3:#undef gmtime_r
compat/gmtime.c:8:      return git_gmtime_r(timep, &result);
compat/gmtime.c:11:struct tm *git_gmtime_r(const time_t *timep, struct tm *result)
compat/gmtime.c:16:     ret = gmtime_r(timep, result);
compat/mingw.c:606:struct tm *gmtime_r(const time_t *timep, struct tm *result)
compat/mingw.h:162:struct tm *gmtime_r(const time_t *timep, struct tm *result);
date.c:429:             if (gmtime_r(&now, &now_tm))
date.c:492:             if (gmtime_r(&time, tm)) {
git-compat-util.h:721:struct tm *git_gmtime_r(const time_t *, struct tm *);
git-compat-util.h:723:#define gmtime_r git_gmtime_r

La commande grep peut être enrichie grâce à un certain nombre d’options intéressantes.

Par exemple, pour l’appel précédent, vous pouvez indiquer à Git de résumer le résultat en ne montrant que les fichiers et le nombre de correspondances au moyen de l’option --count :

$ git grep --count gmtime_r
compat/gmtime.c:4
compat/mingw.c:1
compat/mingw.h:1
date.c:2
git-compat-util.h:2

Si vous souhaitez voir dans quelle méthode ou fonction la correspondance a été trouvée, vous pouvez passer l’option -p :

$ git grep -p gmtime_r *.c
date.c=static int match_multi_number(unsigned long num, char c, const char *date, char *end, struct tm *tm)
date.c:         if (gmtime_r(&now, &now_tm))
date.c=static int match_digit(const char *date, struct tm *tm, int *offset, int *tm_gmt)
date.c:         if (gmtime_r(&time, tm)) {

Ici, on peut voir que gmtime_r est appelée dans les fonctions match_multi_number et match_digit du fichier date.c.

Vous pouvez aussi rechercher des combinaisons plus complexes de chaînes de caractères avec l’option --and qui force plusieurs correspondances sur la même ligne. Par exemple, recherchons toutes les lignes qui définissent une constante qui contient au choix « LINK » ou « BUF_MAX » dans la base de code de Git avant la version 1.8.0.

Ici, nous allons utiliser les options --break et --heading qui aident à découper le résultat dans un format plus digeste.

$ git grep --break --heading \
    -n -e '#define' --and \( -e LINK -e BUF_MAX \) v1.8.0
v1.8.0:builtin/index-pack.c
62:#define FLAG_LINK (1u<<20)

v1.8.0:cache.h
73:#define S_IFGITLINK  0160000
74:#define S_ISGITLINK(m)       (((m) & S_IFMT) == S_IFGITLINK)

v1.8.0:environment.c
54:#define OBJECT_CREATION_MODE OBJECT_CREATION_USES_HARDLINKS

v1.8.0:strbuf.c
326:#define STRBUF_MAXLINK (2*PATH_MAX)

v1.8.0:symlinks.c
53:#define FL_SYMLINK  (1 << 2)

v1.8.0:zlib.c
30:/* #define ZLIB_BUF_MAX ((uInt)-1) */
31:#define ZLIB_BUF_MAX ((uInt) 1024 * 1024 * 1024) /* 1GB */

La commande git grep a quelques avantages sur les commandes de recherche normales telles que grep et ack. Le premier est qu’elle est vraiment rapide, le second est qu’elle vous permet de rechercher dans n’importe quelle arborescence Git, pas seulement la copie de travail. Comme nous l’avons vu dans l’exemple ci-dessus, nous avons cherché des termes dans une version ancienne du code source de Git, pas dans la dernière version extraite.

Recherche dans le journal Git

Peut-être ne cherchez-vous pas un terme apparaît, mais plutôt quand il existait ou fut introduit. La commande git log comprend un certain nombre d’outils puissants pour trouver des commits spécifiques par le contenu de leurs messages ou le contenu des diffs qu’ils introduisent.

Si vous voulez trouver par exemple quand la constante ZLIB_BUF_MAX a été initialement introduite, nous pouvons indiquez à Git de ne montrer que les commits qui soit ajoutent soit retirent la chaîne avec l’option -S.

$ git log -SZLIB_BUF_MAX --oneline
e01503b zlib: allow feeding more than 4GB in one go
ef49a7a zlib: zlib can only process 4GB at a time

Si nous regardons la diff de ces commits, nous pouvons voir que dans ef49a7a, la constante a été introduite et qu’elle a été modifiée dans e01503b.

Si vous devez être plus spécifique, vous pouvez fournir une expression régulière à rechercher avec l’option -G.

Recherche des évolutions d’une ligne

Un autre outil avancé de recherche dans l’historique qui peut s’avérer très utile est la recherche de l’historique d’une ligne. C’est une addition assez récente et peu connue, mais elle peut être très efficace. On l’active avec l’option -L de git log et elle vous montre l’historique d’une fonction ou d’une ligne dans votre base de code.

Par exemple, si nous souhaitions voir toutes les modifications réalisées sur la fonction git_deflate_bound dans le fichier zlib.c, nous pourrions lancer git log -L :git_deflate_bound:zlib.c. Cette commande va essayer de déterminer les limites de cette fonction et de rechercher dans l’historique chaque modification réalisée sur la fonction comme une série de patchs jusqu’au moment de sa création.

$ git log -L :git_deflate_bound:zlib.c
commit ef49a7a0126d64359c974b4b3b71d7ad42ee3bca
Author: Junio C Hamano <gitster@pobox.com>
Date:   Fri Jun 10 11:52:15 2011 -0700

    zlib: zlib can only process 4GB at a time

diff --git a/zlib.c b/zlib.c
--- a/zlib.c
+++ b/zlib.c
@@ -85,5 +130,5 @@
-unsigned long git_deflate_bound(z_streamp strm, unsigned long size)
+unsigned long git_deflate_bound(git_zstream *strm, unsigned long size)
 {
-       return deflateBound(strm, size);
+       return deflateBound(&strm->z, size);
 }


commit 225a6f1068f71723a910e8565db4e252b3ca21fa
Author: Junio C Hamano <gitster@pobox.com>
Date:   Fri Jun 10 11:18:17 2011 -0700

    zlib: wrap deflateBound() too

diff --git a/zlib.c b/zlib.c
--- a/zlib.c
+++ b/zlib.c
@@ -81,0 +85,5 @@
+unsigned long git_deflate_bound(z_streamp strm, unsigned long size)
+{
+       return deflateBound(strm, size);
+}
+

Si Git ne peut pas déterminer comment trouver la fonction ou la méthode dans votre langage de programmation, vous pouvez aussi fournir une regex. Par exemple, cela aurait donné le même résultat avec git log -L '/unsigned long git_deflate_bound/',/^}/:zlib.c. Vous auriez pu aussi spécifier un intervalle de lignes ou un numéro de ligne et vous auriez obtenu le même type de résultat.