| GIT-BISECT(1) | Git Manual | GIT-BISECT(1) |
نام (NAME)
git-bisect - استفاده از جستجوی دودویی برای یافتن کامیتی که یک باگ را ایجاد کرده است
خلاصه دستور (SYNOPSIS)
git bisect start [--term-(bad|new)=<term-new> --term-(good|old)=<term-old>]
[--no-checkout] [--first-parent] [<bad> [<good>...]] [--] [<pathspec>...]
git bisect (bad|new|<term-new>) [<rev>]
git bisect (good|old|<term-old>) [<rev>...]
git bisect terms [--term-(good|old) | --term-(bad|new)]
git bisect skip [(<rev>|<range>)...]
git bisect next
git bisect reset [<commit>]
git bisect (visualize|view)
git bisect replay <logfile>
git bisect log
git bisect run <cmd> [<arg>...]
git bisect help
توضیحات (DESCRIPTION)
این دستور از الگوریتم جستجوی دودویی برای یافتن اینکه کدام کامیت در تاریخچه پروژه شما یک باگ را ایجاد کرده است، استفاده میکند. روش استفاده از آن به این صورت است که ابتدا یک کامیت "خراب" (bad) که مشخص است حاوی باگ است، و یک کامیت "سالم" (good) که پیش از ایجاد باگ بوده است را به آن معرفی میکنید. سپس git bisect کامیتی را بین این دو نقطه پایانی انتخاب کرده و از شما میپرسد که آیا کامیت انتخابشده "سالم" (good) است یا "خراب" (bad). این دستور دامنه را محدودتر و محدودتر میکند تا زمانی که دقیقاً همان کامیتی را که تغییر را ایجاد کرده پیدا کند.
در واقع، git bisect میتواند برای یافتن کامیتی استفاده شود که هر ویژگی پروژه شما را تغییر داده است؛ به عنوان مثال، کامیتی که یک باگ را رفع کرده، یا کامیتی که باعث بهبود کارایی یک بنچمارک شده است. برای پشتیبانی از این کاربرد عمومیتر، میتوان از اصطلاحات "قدیمی" (old) و "جدید" (new) به جای "سالم" (good) و "خراب" (bad) استفاده کرد، یا میتوانید اصطلاحات دلخواه خود را برگزینید. برای اطلاعات بیشتر بخش «اصطلاحات جایگزین» را در زیر ببینید.
دستورات پایه bisect: start، bad، good
به عنوان مثال، فرض کنید در تلاش هستید تا کامیتی را پیدا کنید که ویژگی خاصی را که در نسخه v2.6.13-rc2 پروژه به درستی کار میکرد، خراب کرده است. شما یک نشست bisect را به صورت زیر آغاز میکنید:
$ git bisect start $ git bisect bad # نسخه فعلی خراب است $ git bisect good v2.6.13-rc2 # مشخص است که نسخه v2.6.13-rc2 سالم است
پس از مشخص کردن حداقل یک کامیت خراب و یک کامیت سالم، git bisect کامیتی را در میانه آن بازه از تاریخچه انتخاب میکند، آن را چکاوت مینماید و خروجی مشابه زیر را نمایش میدهد:
Bisecting: 675 revisions left to test after this (roughly 10 steps)
اکنون باید نسخه چکاوتشده را کامپایل کرده و آن را آزمایش کنید. اگر آن نسخه به درستی کار کرد، دستور زیر را وارد کنید:
$ git bisect good
اگر آن نسخه خراب بود، دستور زیر را وارد کنید:
$ git bisect bad
سپس git bisect با پیامی مشابه زیر پاسخ خواهد داد:
Bisecting: 337 revisions left to test after this (roughly 9 steps)
فرآیند را تکرار کنید: درخت را کامپایل کرده، آن را آزمایش نمایید، و بسته به اینکه نسخه سالم است یا خراب، دستور git bisect good یا git bisect bad را اجرا کنید تا کامیت بعدی که نیاز به آزمایش دارد مشخص شود.
در نهایت هیچ ویرایش دیگری برای بررسی باقی نخواهد ماند، و دستور توضیحی درباره اولین کامیت خراب چاپ خواهد کرد. ارجاع refs/bisect/bad روی آن کامیت باقی خواهد ماند.
بازنشانی bisect (دستور Bisect reset)
پس از یک نشست bisect، برای پاکسازی وضعیت جستجوی دودویی و بازگشت به HEAD اصلی، دستور زیر را صادر کنید:
git bisect reset
به طور پیشفرض، این دستور درخت شما را به کامیتی که قبل از git bisect start چکاوت شده بود بازمیگرداند. (یک دستور جدید git bisect start نیز این کار را انجام میدهد، زیرا وضعیت قدیمی bisect را پاکسازی میکند).
با یک آرگومان اختیاری، میتوانید در عوض به کامیت متفاوتی بازگردید:
git bisect reset <commit>
به عنوان مثال، git bisect reset bisect/bad اولین ویرایش خراب را چکاوت خواهد کرد، در حالی که git bisect reset HEAD شما را روی کامیت فعلی جستجوی دودویی باقی میگذارد و از هرگونه جابجایی بین کامیتها جلوگیری میکند.
اصطلاحات جایگزین (Alternate terms)
گاهی اوقات شما به دنبال کامیتی که خرابی ایجاد کرده نیستید، بلکه به دنبال کامیتی هستید که باعث تغییری بین یک وضعیت "قدیمی" (old) و وضعیت "جدید" (new) دیگر شده است. برای مثال، ممکن است به دنبال کامیتی باشید که یک اصلاح خاص را اضافه کرده است. یا ممکن است به دنبال اولین کامیتی باشید که در آن نام فایلهای کد منبع در نهایت با استاندارد نامگذاری شرکت شما مطابقت پیدا کرده است. یا هر مورد دیگر.
در چنین مواردی استفاده از اصطلاحات "سالم" (good) و "خراب" (bad) برای اشاره به «وضعیت قبل از تغییر» و «وضعیت بعد از تغییر» میتواند بسیار گیجکننده باشد. بنابراین در عوض، میتوانید به ترتیب از اصطلاحات "قدیمی" (old) و "جدید" (new) به جای "سالم" و "خراب" استفاده کنید. (اما توجه داشته باشید که نمیتوانید در یک نشست واحد "good" و "bad" را با "old" و "new" ترکیب کنید).
در این کاربرد کلیتر، شما به git bisect یک کامیت "جدید" که دارای یک ویژگی خاص است و یک کامیت "قدیمی" که آن ویژگی را ندارد ارائه میدهید. هر بار که git bisect یک کامیت را چکاوت میکند، شما بررسی میکنید که آیا آن کامیت دارای آن ویژگی هست یا خیر. اگر بود، کامیت را به عنوان "جدید" (new) علامتگذاری کنید؛ در غیر این صورت، آن را به عنوان "قدیمی" (old) علامت بزنید. پس از اتمام جستجوی دودویی، git bisect گزارش خواهد داد که کدام کامیت آن ویژگی را معرفی کرده است.
برای استفاده از "old" و "new" به جای "good" و "bad"، باید دستور git bisect start را بدون کامیت به عنوان آرگومان اجرا کنید و سپس دستورات زیر را برای افزودن کامیتها صادر نمایید:
git bisect old [<rev>]
تا مشخص شود که یک کامیت قبل از تغییر مورد نظر بوده است، یا
git bisect new [<rev>...]
تا مشخص شود که بعد از آن بوده است.
برای یادآوری اصطلاحات مورد استفاده فعلی، دستور زیر را به کار ببرید:
git bisect terms
میتوانید تنها اصطلاح قدیمی را با git bisect terms --term-old یا git bisect terms --term-good دریافت کنید؛ همچنین git bisect terms --term-new و git bisect terms --term-bad میتوانند برای دانستن نحوه نامگذاری کامیتهای تازهتر از تغییر مورد نظر استفاده شوند.
اگر مایلید به جای "bad"/"good" یا "new"/"old" از اصطلاحات دلخواه خود استفاده کنید، میتوانید با آغاز جستجوی دودویی با دستور زیر هر نامی را که میپسندید انتخاب کنید (به جز زیردستورهای موجود bisect مانند reset، start و غیره):
git bisect start --term-old <term-old> --term-new <term-new>
به عنوان مثال، اگر به دنبال کامیتی هستید که افت کارایی (performance regression) ایجاد کرده است، میتوانید از دستور زیر استفاده کنید:
$ git bisect start --term-old fast --term-new slow
یا اگر به دنبال کامیتی هستید که یک باگ را رفع کرده است، میتوانید از دستور زیر استفاده کنید:
$ git bisect start --term-new fixed --term-old broken
سپس، به جای git bisect good و git bisect bad از git bisect <term-old> و git bisect <term-new> برای علامتگذاری کامیتها استفاده نمایید.
مصورسازی/مشاهده bisect (دستور Bisect visualize/view)
برای مشاهده مظنونین باقیمانده فعلی در gitk، دستور زیر را در طول فرآیند جستجوی دودویی صادر کنید (زیردستور view میتواند به عنوان جایگزینی برای visualize استفاده شود):
$ git bisect visualize
گیت یک محیط گرافیکی را از طریق متغیرهای محیطی مختلف تشخیص میدهد:
DISPLAY
SESSIONNAME
MSYSTEM
SECURITYSESSIONID
اگر هیچیک از این متغیرهای محیطی تنظیم نشده باشند، در عوض از git log استفاده میشود. همچنین میتوانید گزینههای خط فرمان مانند -p و --stat را ارسال کنید.
$ git bisect visualize --stat
لاگ و بازپخش bisect (دستورات Bisect log و bisect replay)
پس از علامتگذاری ویرایشها به عنوان سالم یا خراب، دستور زیر را صادر کنید تا نشان دهد تا کنون چه کارهایی انجام شده است:
$ git bisect log
اگر متوجه شدید که در تعیین وضعیت یک ویرایش اشتباه کردهاید، میتوانید خروجی این دستور را در یک فایل ذخیره کنید، آن را برای حذف مدخلهای نادرست ویرایش نمایید، و سپس دستورات زیر را برای بازگشت به وضعیت اصلاحشده صادر کنید:
$ git bisect reset $ git bisect replay that-file
اجتناب از تست یک کامیت
اگر در میانه یک نشست bisect میدانید که ویرایش پیشنهادی مورد مناسبی برای آزمایش نیست (برای مثال در بیلد با شکست مواجه میشود و میدانید که این خطا ارتباطی با باگی که دنبال میکنید ندارد)، میتوانید به صورت دستی یک کامیت نزدیک را انتخاب کرده و در عوض آن را آزمایش کنید.
برای مثال:
$ git bisect good/bad # دور قبلی سالم (good) یا خراب (bad) بود.
Bisecting: 337 revisions left to test after this (roughly 9 steps)
$ git bisect visualize # اوه، این مورد جالب نیست.
$ git reset --hard HEAD~3 # امتحان ۳ ویرایش قبل از آنچه
# پیشنهاد شد
سپس ویرایش انتخابشده را کامپایل و آزمایش کنید و پس از آن، ویرایش را به شیوه معمول به عنوان سالم یا خراب علامتگذاری نمایید.
نادیده گرفتن کامیت در bisect (دستور Bisect skip)
به جای اینکه خودتان یک کامیت نزدیک را انتخاب کنید، میتوانید با صدور این دستور از گیت بخواهید که این کار را برای شما انجام دهد:
$ git bisect skip # نسخه فعلی قابل آزمایش نیست
با این حال، اگر کامیتی مجاور کامیتی که به دنبال آن هستید را نادیده بگیرید (skip کنید)، گیت قادر نخواهد بود به طور دقیق تشخیص دهد کدامیک از آن کامیتها اولین کامیت خراب بوده است.
همچنین میتوانید به جای یک کامیت، با استفاده از نماد بازه (range)، بازهای از کامیتها را نادیده بگیرید. به عنوان مثال:
$ git bisect skip v2.5..v2.6
این دستور به فرآیند bisect میگوید که هیچ کامیتی پس از v2.5، تا و شامل v2.6 نباید آزمایش شود.
توجه داشته باشید اگر میخواهید اولین کامیت این بازه را نیز نادیده بگیرید، باید دستور زیر را صادر کنید:
$ git bisect skip v2.5 v2.5..v2.6
این به فرآیند bisect میگوید که کامیتهای بین v2.5 و v2.6 (شامل هر دو) باید نادیده گرفته شوند.
کامیت بعدی در bisect (دستور Bisect next)
به طور معمول، پس از علامتگذاری یک ویرایش به عنوان سالم یا خراب، گیت به طور خودکار ویرایش بعدی را برای آزمایش محاسبه و چکاوت میکند. با این حال، اگر نیاز دارید که مرحله بعدی جستجوی دودویی را به صورت صریح درخواست کنید، میتوانید از دستور زیر استفاده نمایید:
$ git bisect next
ممکن است از این دستور برای از سرگیری فرآیند جستجوی دودویی پس از قطع کردن آن با چکاوت یک ویرایش دیگر استفاده کنید.
کاهش دامنه جستجوی دودویی با دادن پارامترهای بیشتر به bisect start
اگر بدانید کدام بخش از درخت درگیر مشکلی است که آن را ردیابی میکنید، میتوانید با مشخص کردن پارامترهای pathspec هنگام صدور دستور bisect start، تعداد مراحل آزمایش را حتی بیشتر کاهش دهید:
$ git bisect start -- arch/i386 include/asm-i386
اگر از قبل بیش از یک کامیت سالم را میشناسید، میتوانید با مشخص کردن تمام کامیتهای سالم بلافاصله پس از کامیت خراب در هنگام اجرای دستور bisect start، فضای bisect را محدودتر کنید:
$ git bisect start v2.6.20-rc6 v2.6.20-rc4 v2.6.20-rc1 --
# نسخه v2.6.20-rc6 خراب است
# نسخههای v2.6.20-rc4 و v2.6.20-rc1 سالم هستند
اجرای خودکار bisect (دستور Bisect run)
اگر اسکریپتی دارید که میتواند تشخیص دهد کد منبع فعلی سالم است یا خراب، میتوانید با صدور دستور زیر جستجوی دودویی را به صورت خودکار انجام دهید:
git bisect run <cmd> [<arg>...]
توجه داشته باشید که <cmd> همراه با <arg> در صورتی که کد منبع فعلی سالم/قدیمی (good/old) باشد باید با کد خروج 0 خارج شود، و اگر کد منبع فعلی خراب/جدید (bad/new) باشد باید با کدی بین 1 تا 127 (شامل هر دو)، به جز 125، خارج شود.
هر کد خروج دیگری فرآیند bisect را متوقف و لغو خواهد کرد. باید توجه داشت برنامهای که از طریق exit(-1) پایان مییابد، مقدار 255 = $? را بر جای میگذارد (صفحه راهنمای exit(3) را ببینید)، زیرا مقدار با & 0377 بریده میشود.
کد خروج ویژه 125 باید زمانی استفاده شود که کد منبع فعلی قابل آزمایش نباشد. اگر اسکریپت با این کد خارج شود، ویرایش فعلی نادیده گرفته خواهد شد (بخش git bisect skip را در بالا ببینید). مقدار 125 به عنوان بالاترین مقدار منطقی برای این منظور انتخاب شد، زیرا کدهای 126 و 127 توسط پوستههای POSIX برای اعلام وضعیت خطای خاص استفاده میشوند (127 برای پیدا نشدن دستور، 126 برای پیدا شدن دستور اما عدم دسترسی اجرایی — تا جایی که به bisect run مربوط میشود، این جزئیات اهمیتی ندارند، زیرا آنها خطاهای معمول در اسکریپت هستند).
ممکن است اغلب متوجه شوید در طول یک نشست bisect میخواهید تغییرات موقتی (مانند s/#define DEBUG 0/#define DEBUG 1/ در یک فایل هدر، یا «ویرایشی که فاقد این کامیت است برای دور زدن مشکل دیگری که این bisect به آن علاقهای ندارد به این وصله نیاز دارد») روی ویرایش تحت آزمایش اعمال کنید.
برای مقابله با چنین وضعیتی، پس از اینکه git bisect داخلی ویرایش بعدی را برای آزمایش پیدا کرد، اسکریپت میتواند وصله را قبل از کامپایل اعمال کند، آزمایش واقعی را اجرا نماید و سپس تصمیم بگیرد که آیا ویرایش (احتمالاً همراه با وصله لازم) آزمایش را پشت سر گذاشته است یا خیر و سپس درخت را به وضعیت اولیه بازگرداند. در نهایت، اسکریپت باید با وضعیت آزمایش واقعی خارج شود تا به حلقه دستور git bisect run اجازه دهد نتیجه نهایی نشست bisect را تعیین کند.
گزینهها (OPTIONS)
--no-checkout
این گزینه ممکن است زمانی مفید باشد که آزمایشی که در هر مرحله انجام میدهید نیازی به یک درخت چکاوتشده نداشته باشد.
اگر مخزن از نوع bare باشد، --no-checkout به صورت پیشفرض در نظر گرفته میشود.
--first-parent
در تشخیص اشکالاتی که از طریق ادغام یک شاخه ایجاد شدهاند، کامیت ادغام به عنوان منشأ ایجاد باگ شناسایی میشود و اجداد آن نادیده گرفته خواهند شد.
این گزینه به ویژه برای جلوگیری از نتایج مثبت کاذب زمانی که یک شاخه ادغامشده شامل کامیتهای خراب یا غیرقابل بیلد بود اما خود ادغام مشکلی نداشت، بسیار مفید است.
مثالها (EXAMPLES)
$ git bisect start HEAD v1.2 -- # نسخه HEAD خراب و v1.2 سالم است $ git bisect run make # دستور make برنامه را بیلد میکند $ git bisect reset # خروج از نشست bisect
$ git bisect start HEAD origin -- # نسخه HEAD خراب و origin سالم است $ git bisect run make test # دستور make test بیلد و تست میکند $ git bisect reset # خروج از نشست bisect
$ cat ~/test.sh #!/bin/sh make || exit 125 # این بیلدهای خراب را نادیده میگیرد ~/check_test_case.sh # آیا تست پاس میشود؟ $ git bisect start HEAD HEAD~10 -- # مقصر در میان ۱۰ کامیت آخر است $ git bisect run ~/test.sh $ git bisect reset # خروج از نشست bisect
در اینجا ما از یک اسکریپت سفارشی test.sh استفاده میکنیم. در این اسکریپت، اگر make با شکست مواجه شود، از کامیت فعلی صرفنظر میکنیم. check_test_case.sh در صورت موفقیت مورد آزمایشی باید با exit 0 و در غیر این صورت با exit 1 خارج شود.
امنتر است که هر دو فایل test.sh و check_test_case.sh در خارج از مخزن قرار داشته باشند تا از تداخل بین فرآیندهای bisect، make و تست با اسکریپتها جلوگیری شود.
$ cat ~/test.sh
#!/bin/sh
# تغییر درخت کاری با ادغام شاخه hot-fix
# و سپس تلاش برای ساخت (build)
if git merge --no-commit --no-ff hot-fix &&
make
then
# اجرای تست اختصاصی پروژه و گزارش وضعیت آن
~/check_test_case.sh
status=$?
else
# به فراخواننده اطلاع دهید این نسخه غیرقابل آزمایش است
status=125
fi
# لغو تغییر اعمالشده تا امکان انتقال تمیز به کامیت بعدی فراهم شود
git reset --hard
# بازگرداندن کنترل
exit $status
این اسکریپت اصلاحات یک شاخه hot-fix را قبل از اجرای هر آزمون اعمال میکند، به عنوان مثال در صورتی که محیط ساخت یا آزمون شما تغییر کرده باشد به طوری که ویرایشهای قدیمیتر به اصلاحی نیاز داشته باشند که ویرایشهای جدیدتر از قبل آن را دارند. (اطمینان حاصل کنید شاخه hot-fix بر اساس کامیتی ساخته شده باشد که در تمام ویرایشهای مورد بررسی در جستجوی دودویی وجود دارد، تا ادغام موارد اضافی زیادی را وارد نکند، یا از git cherry-pick به جای git merge استفاده کنید).
$ git bisect start HEAD HEAD~10 -- # مقصر در میان ۱۰ کامیت آخر است $ git bisect run sh -c "make || exit 125; ~/check_test_case.sh" $ git bisect reset # خروج از نشست bisect
این نشان میدهد که اگر آزمون را در یک خط بنویسید، میتوانید بدون اسکریپت اجرا کار را پیش ببرید.
$ git bisect start HEAD <known-good-commit> [ <boundary-commit> ... ] --no-checkout
$ git bisect run sh -c '
GOOD=$(git for-each-ref "--format=%(objectname)" refs/bisect/good-*) &&
git rev-list --objects BISECT_HEAD --not $GOOD >tmp.$$ &&
git pack-objects --stdout >/dev/null <tmp.$$
rc=$?
rm -f tmp.$$
test $rc = 0'
$ git bisect reset # خروج از نشست bisect
در این حالت، هنگامی که git bisect run پایان مییابد، bisect/bad به کامیتی اشاره خواهد کرد که حداقل یک والد دارد که گراف قابل دسترسی آن در مفهوم مورد نیاز git pack-objects کاملاً قابل پیمایش است.
$ git bisect start $ git bisect new HEAD # کامیت فعلی به عنوان جدید (new) علامت زده میشود $ git bisect old HEAD~10 # دهمین کامیت از اکنون به عنوان قدیمی (old) علامت زده میشود
یا:
$ git bisect start --term-old broken --term-new fixed $ git bisect fixed $ git bisect broken HEAD~10
دریافت راهنما
برای دریافت توضیحات کوتاه درباره نحوه استفاده، از git bisect و برای توضیحات کاملتر از git bisect help یا git bisect -h استفاده کنید.
همچنین ببینید (SEE ALSO)
Fighting regressions with git bisect[1], git-blame(1).
گیت (GIT)
بخشی از مجموعه git(1)
نکات (NOTES)
- 1.
- مبارزه با پسرفتها با git bisect (Fighting regressions with git bisect)
| 2026-06-29 | Git 2.55.0 |