Chapters ▾ 2nd Edition

7.5 ابزارهای گیت (Git Tools) - جستجو (Searching)

جستجو (Searching)

در هر اندازه‌ای از کد، اغلب لازم است بدانید یک تابع کجا فراخوانی یا تعریف شده است، یا تاریخچه یک متد را مشاهده کنید. گیت چند ابزار مفید برای جستجوی سریع و آسان در کد و کامیت‌های ذخیره شده در پایگاه داده خود ارائه می‌دهد. در ادامه چند نمونه از آن‌ها را بررسی می‌کنیم.

گلوبال سرچ گیت (Git Grep)

گیت با دستوری به نام grep عرضه می‌شود که به شما امکان می‌دهد به سادگی در هر درخت کامیت شده، دایرکتوری کاری یا حتی ایندکس، به دنبال یک رشته یا عبارت منظم بگردید. در مثال‌های بعدی، کد منبع خود گیت را جستجو خواهیم کرد.

به طور پیش‌فرض، git grep در فایل‌های دایرکتوری کاری شما جستجو می‌کند. به عنوان اولین تغییر، می‌توانید از گزینه‌های -n یا --line-number استفاده کنید تا شماره خط‌هایی که گیت تطابق پیدا کرده را چاپ کند:

$ 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

علاوه بر جستجوی ساده بالا، git grep گزینه‌های جالب و متنوع دیگری نیز دارد.

برای مثال، به جای چاپ همه تطابق‌ها، می‌توانید از گزینه‌های -c یا --count استفاده کنید تا خروجی خلاصه شده‌ای ببینید که فقط فایل‌هایی را نشان می‌دهد که رشته جستجو را داشتند و تعداد تطابق‌ها در هر فایل چقدر بوده است:

$ 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

اگر به متن پیرامونی رشته جستجو علاقه دارید، می‌توانید با یکی از گزینه‌های -p یا --show-function تابع یا متدی که هر رشته تطبیق‌یافته در آن قرار دارد را نمایش دهید:

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

همانطور که می‌بینید، تابع gmtime_r هم در توابع match_multi_number و match_digit در فایل date.c فراخوانی شده است (مورد سوم که نمایش داده شده فقط رشته‌ای است که در یک کامنت آمده).

همچنین می‌توانید با استفاده از پرچم --and به دنبال ترکیب‌های پیچیده‌ای از رشته‌ها بگردید، به گونه‌ای که چندین تطابق باید در یک خط متن وجود داشته باشند. برای مثال، بیایید دنبال خطوطی باشیم که ثابتی تعریف می‌کنند که نام آن شامل هر یک از زیررشته‌های “LINK” یا “BUF_MAX” باشد، و این جستجو را در نسخه قدیمی‌تر کد منبع گیت که به تگ v1.8.0 اشاره دارد انجام دهیم (همچنین گزینه‌های --break و --heading را اضافه می‌کنیم تا خروجی خواناتر شود):

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

دستور git grep چند مزیت نسبت به دستورات جستجوی معمولی مانند grep و ack دارد. اول اینکه بسیار سریع است، دوم اینکه می‌توانید در هر درخت گیت جستجو کنید، نه فقط دایرکتوری کاری. همانطور که در مثال بالا دیدیم، ما در نسخه قدیمی‌تر کد منبع گیت جستجو کردیم، نه نسخه‌ای که در حال حاضر چک‌اوت شده بود.

جستجوی تاریخچه گیت (Git Log Searching)

شاید شما به دنبال محل یک عبارت نیستید، بلکه می‌خواهید بدانید چه زمانی آن وجود داشت یا معرفی شده است. دستور git log ابزارهای قدرتمندی برای یافتن کامیت‌های خاص بر اساس محتوای پیام‌ها یا حتی محتوای تغییراتی که ایجاد کرده‌اند، دارد.

برای مثال، اگر بخواهیم بفهمیم ثابت ZLIB_BUF_MAX چه زمانی معرفی شده است، می‌توانیم از گزینه -S (که به شوخی به آن گزینه "تبر گیت" گفته می‌شود) استفاده کنیم تا گیت فقط کامیت‌هایی را نشان دهد که تعداد وقوع آن رشته را تغییر داده‌اند.

$ 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

اگر به دیف تغییرات آن کامیت‌ها نگاه کنیم، می‌بینیم که در کامیت ef49a7a این ثابت معرفی شده و در کامیت e01503b تغییر کرده است.

اگر نیاز به جستجوی دقیق‌تری دارید، می‌توانید با گزینه -G یک عبارت منظم برای جستجو ارائه دهید.

یکی دیگر از جستجوهای پیشرفته ولی بسیار مفید، جستجوی تاریخچه یک خط است. کافی است دستور git log را با گزینه -L اجرا کنید تا تاریخچه یک تابع یا خط کد در کدبیس شما نشان داده شود.

برای مثال، اگر بخواهیم هر تغییری که روی تابع git_deflate_bound در فایل zlib.c اعمال شده را ببینیم، می‌توانیم دستور git log -L :git_deflate_bound:zlib.c را اجرا کنیم. گیت سعی می‌کند مرزهای آن تابع را تشخیص دهد و سپس تاریخچه آن را به شکل مجموعه‌ای از پچ‌ها از زمان ایجاد تابع نمایش دهد.

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

اگر گیت نتواند تابع یا متد را در زبان برنامه‌نویسی شما تشخیص دهد، می‌توانید یک عبارت منظم (regex) به آن بدهید. برای مثال، این دستور همان کاری را انجام می‌دهد که مثال بالا: git log -L '/unsigned long git_deflate_bound/',/^}/:zlib.c همچنین می‌توانید بازه‌ای از خطوط یا شماره خط خاصی بدهید و خروجی مشابه دریافت کنید.

scroll-to-top