Chapters ▾ 2nd Edition

7.5 Git Tools - Soek (Searching)

Soek (Searching)

Met byna enige grootte kodebasis, sal jy dikwels moet vind waar 'n funksie geroep of gedefinieer word, of die geskiedenis van 'n metode moet vertoon. Git bied 'n paar nuttige instrumente om vinnig en maklik deur die kode en vasleggings (commits) wat in sy databasis gestoor is, te soek. Ons sal deur 'n paar van hulle gaan.

Git Grep

Git kom met 'n opdrag genaamd grep wat jou toelaat om maklik deur enige vasgelegde boom (committed tree), die werkgids (working directory), of selfs die indeks te soek vir 'n string of gereelde uitdrukking (regular expression). Vir die voorbeelde wat volg, sal ons deur die bronkode vir Git self soek.

By verstek sal git grep deur die lêers in jou werkgids soek. As 'n eerste variasie kan jy óf die -n óf --line-number opsies gebruik om die reëlnommers te druk waar Git ooreenkomste gevind het:

$ 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:826:struct tm *gmtime_r(const time_t *timep, struct tm *result)
compat/mingw.h:206:struct tm *gmtime_r(const time_t *timep, struct tm *result);
date.c:482:             if (gmtime_r(&now, &now_tm))
date.c:545:             if (gmtime_r(&time, tm)) {
date.c:758:             /* gmtime_r() in match_digit() may have clobbered it */
git-compat-util.h:1138:struct tm *git_gmtime_r(const time_t *, struct tm *);
git-compat-util.h:1140:#define gmtime_r git_gmtime_r

Benewens die basiese soektog wat hierbo gewys word, ondersteun git grep 'n oormaat van ander interessante opsies.

Byvoorbeeld, in plaas daarvan om al die ooreenkomste te druk, kan jy git grep vra om die afvoer op te som deur slegs te wys watter lêers die soekstring bevat het en hoeveel ooreenkomste daar in elke lêer was met die -c of --count opsie:

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

As jy belangstel in die konteks van 'n soekstring, kan jy die insluitende metode of funksie vir elke ooreenstemmende string vertoon met óf die -p óf --show-function opsies:

$ git grep -p gmtime_r *.c
date.c=static int match_multi_number(timestamp_t num, char c, const char *date,
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)) {
date.c=int parse_date_basic(const char *date, timestamp_t *timestamp, int *offset)
date.c:         /* gmtime_r() in match_digit() may have clobbered it */

Soos jy kan sien, word die gmtime_r roetine geroep vanaf beide die match_multi_number en match_digit funksies in die date.c lêer (die derde ooreenkoms wat vertoon word, verteenwoordig bloot die string wat in 'n opmerking verskyn).

Jy kan ook na komplekse kombinasies van stringe soek met die --and vlag, wat verseker dat veelvuldige ooreenkomste in dieselfde reël teks moet voorkom. Kom ons soek byvoorbeeld na enige reëls wat 'n konstante definieer waarvan die naam enigeen van die substringe “LINK” of “BUF_MAX” bevat, spesifiek in 'n ouer weergawe van die Git-kodebasis wat deur die merker (tag) v1.8.0 verteenwoordig word (ons sal die --break en --heading opsies bygooi wat help om die afvoer in 'n meer leesbare formaat op te deel):

$ 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 */

Die git grep opdrag het 'n paar voordele bo normale soekopdragte soos grep en ack. Die eerste is dat dit regtig vinnig is, die tweede is dat jy deur enige boom in Git kan soek, nie net die werkgids nie. Soos ons in die bostaande voorbeeld gesien het, het ons gesoek na terme in 'n ouer weergawe van die Git-bronkode, nie die weergawe wat tans uitgetrek (checked out) was nie.

Git Log Soek (Git Log Searching)

Miskien soek jy nie waar 'n term bestaan nie, maar wanneer dit bestaan het of ingestel is. Die git log opdrag het 'n aantal kragtige instrumente om spesifieke vasleggings te vind deur die inhoud van hul boodskappe of selfs die inhoud van die diff wat hulle instel.

As ons byvoorbeeld wil uitvind wanneer die ZLIB_BUF_MAX konstante oorspronklik ingestel is, kan ons die -S opsie gebruik (in die omgangstaal verwys na as die Git “piksteel” of “pickaxe” opsie) om vir Git te sê om vir ons slegs daardie vasleggings te wys wat die aantal voorkomste van daardie string verander het.

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

As ons na die diff van daardie vasleggings kyk, kan ons sien dat in ef49a7a die konstante ingestel is en in e01503b is dit gewysig.

As jy meer spesifiek moet wees, kan jy 'n gereelde uitdrukking (regular expression) verskaf om na te soek met die -G opsie.

Nog 'n redelik gevorderde logsoektog wat kranksinnig nuttig is, is die reëlgeskiedenis-soektog. Voer eenvoudig git log uit met die -L opsie, en dit sal vir jou die geskiedenis van 'n funksie of reël kode in jou kodebasis wys.

Byvoorbeeld, as ons elke verandering wat aan die funksie git_deflate_bound in die zlib.c lêer gemaak is wil sien, kan ons git log -L :git_deflate_bound:zlib.c uitvoer. Dit sal probeer uitvind wat die grense van daardie funksie is en dan deur die geskiedenis kyk en vir ons elke verandering wys wat aan die funksie gemaak is as 'n reeks pleisters (patches) terug tot toe die funksie vir die eerste keer geskep is.

$ 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);
+}
+

As Git nie kan uitvind hoe om 'n funksie of metode in jou programmeertaal te pas nie, kan jy dit ook voorsien van 'n gereelde uitdrukking (of regex). Byvoorbeeld, dit sou dieselfde ding gedoen het as die voorbeeld hierbo: git log -L '/unsigned long git_deflate_bound/',/^}/:zlib.c. Jy kan dit ook 'n reeks reëls of 'n enkele reëlnommer gee en jy sal dieselfde soort afvoer kry.