GIT-BISECT(1) Git Manual GIT-BISECT(1)

git-bisect - استفاده از جستجوی دودویی برای یافتن کامیتی که یک باگ را ایجاد کرده است

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

این دستور از الگوریتم جستجوی دودویی برای یافتن اینکه کدام کامیت در تاریخچه پروژه شما یک باگ را ایجاد کرده است، استفاده می‌کند. روش استفاده از آن به این صورت است که ابتدا یک کامیت "خراب" (bad) که مشخص است حاوی باگ است، و یک کامیت "سالم" (good) که پیش از ایجاد باگ بوده است را به آن معرفی می‌کنید. سپس git bisect کامیتی را بین این دو نقطه پایانی انتخاب کرده و از شما می‌پرسد که آیا کامیت انتخاب‌شده "سالم" (good) است یا "خراب" (bad). این دستور دامنه را محدودتر و محدودتر می‌کند تا زمانی که دقیقاً همان کامیتی را که تغییر را ایجاد کرده پیدا کند.

در واقع، git bisect می‌تواند برای یافتن کامیتی استفاده شود که هر ویژگی پروژه شما را تغییر داده است؛ به عنوان مثال، کامیتی که یک باگ را رفع کرده، یا کامیتی که باعث بهبود کارایی یک بنچمارک شده است. برای پشتیبانی از این کاربرد عمومی‌تر، می‌توان از اصطلاحات "قدیمی" (old) و "جدید" (new) به جای "سالم" (good) و "خراب" (bad) استفاده کرد، یا می‌توانید اصطلاحات دلخواه خود را برگزینید. برای اطلاعات بیشتر بخش «اصطلاحات جایگزین» را در زیر ببینید.

به عنوان مثال، فرض کنید در تلاش هستید تا کامیتی را پیدا کنید که ویژگی خاصی را که در نسخه 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، برای پاک‌سازی وضعیت جستجوی دودویی و بازگشت به HEAD اصلی، دستور زیر را صادر کنید:

git bisect reset

به طور پیش‌فرض، این دستور درخت شما را به کامیتی که قبل از git bisect start چک‌اوت شده بود بازمی‌گرداند. (یک دستور جدید git bisect start نیز این کار را انجام می‌دهد، زیرا وضعیت قدیمی bisect را پاک‌سازی می‌کند).

با یک آرگومان اختیاری، می‌توانید در عوض به کامیت متفاوتی بازگردید:

git bisect reset <commit>

به عنوان مثال، git bisect reset bisect/bad اولین ویرایش خراب را چک‌اوت خواهد کرد، در حالی که git bisect reset HEAD شما را روی کامیت فعلی جستجوی دودویی باقی می‌گذارد و از هرگونه جابجایی بین کامیت‌ها جلوگیری می‌کند.

گاهی اوقات شما به دنبال کامیتی که خرابی ایجاد کرده نیستید، بلکه به دنبال کامیتی هستید که باعث تغییری بین یک وضعیت "قدیمی" (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> برای علامت‌گذاری کامیت‌ها استفاده نمایید.

برای مشاهده مظنونین باقی‌مانده فعلی در gitk، دستور زیر را در طول فرآیند جستجوی دودویی صادر کنید (زیردستور view می‌تواند به عنوان جایگزینی برای visualize استفاده شود):

$ git bisect visualize

گیت یک محیط گرافیکی را از طریق متغیرهای محیطی مختلف تشخیص می‌دهد:

DISPLAY

که در محیط‌های X Window System در سیستم‌های یونیکس تنظیم می‌شود.

SESSIONNAME

که تحت Cygwin در نشست‌های تعاملی دسکتاپ تنظیم می‌شود.

MSYSTEM

که تحت Msys2 و Git for Windows تنظیم می‌شود.

SECURITYSESSIONID

که ممکن است در macOS در نشست‌های تعاملی دسکتاپ تنظیم شود.

اگر هیچ‌یک از این متغیرهای محیطی تنظیم نشده باشند، در عوض از git log استفاده می‌شود. همچنین می‌توانید گزینه‌های خط فرمان مانند -p و --stat را ارسال کنید.

$ git bisect visualize --stat

پس از علامت‌گذاری ویرایش‌ها به عنوان سالم یا خراب، دستور زیر را صادر کنید تا نشان دهد تا کنون چه کارهایی انجام شده است:

$ 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               # امتحان ۳ ویرایش قبل از آنچه
                                        # پیشنهاد شد

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

به جای اینکه خودتان یک کامیت نزدیک را انتخاب کنید، می‌توانید با صدور این دستور از گیت بخواهید که این کار را برای شما انجام دهد:

$ 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 (شامل هر دو) باید نادیده گرفته شوند.

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

$ git bisect next

ممکن است از این دستور برای از سرگیری فرآیند جستجوی دودویی پس از قطع کردن آن با چک‌اوت یک ویرایش دیگر استفاده کنید.

اگر بدانید کدام بخش از درخت درگیر مشکلی است که آن را ردیابی می‌کنید، می‌توانید با مشخص کردن پارامترهای 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 سالم هستند

اگر اسکریپتی دارید که می‌تواند تشخیص دهد کد منبع فعلی سالم است یا خراب، می‌توانید با صدور دستور زیر جستجوی دودویی را به صورت خودکار انجام دهید:

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 را تعیین کند.

--no-checkout

در هر تکرار از فرآیند جستجوی دودویی، درخت کاری جدید را چک‌اوت نکنید. در عوض فقط ارجاعی با نام BISECT_HEAD را به‌روزرسانی کنید تا به کامیتی که باید آزمایش شود اشاره نماید.

این گزینه ممکن است زمانی مفید باشد که آزمایشی که در هر مرحله انجام می‌دهید نیازی به یک درخت چک‌اوت‌شده نداشته باشد.

اگر مخزن از نوع bare باشد، --no-checkout به صورت پیش‌فرض در نظر گرفته می‌شود.

--first-parent

هنگام مواجهه با یک کامیت ادغام (merge commit)، تنها اولین کامیت والد را دنبال کنید.

در تشخیص اشکالاتی که از طریق ادغام یک شاخه ایجاد شده‌اند، کامیت ادغام به عنوان منشأ ایجاد باگ شناسایی می‌شود و اجداد آن نادیده گرفته خواهند شد.

این گزینه به ویژه برای جلوگیری از نتایج مثبت کاذب زمانی که یک شاخه ادغام‌شده شامل کامیت‌های خراب یا غیرقابل بیلد بود اما خود ادغام مشکلی نداشت، بسیار مفید است.

•جستجوی دودویی خودکار برای یک بیلد خراب بین v1.2 و HEAD:
$ git bisect start HEAD v1.2 --      # نسخه HEAD خراب و v1.2 سالم است
$ git bisect run make                # دستور make برنامه را بیلد می‌کند
$ git bisect reset                   # خروج از نشست bisect
•جستجوی دودویی خودکار برای شکست تست بین origin و HEAD:
$ git bisect start HEAD origin --    # نسخه HEAD خراب و origin سالم است
$ git bisect run make test           # دستور make test بیلد و تست می‌کند
$ git bisect reset                   # خروج از نشست bisect
•جستجوی دودویی خودکار برای یک مورد آزمایشی (test case) خراب:
$ 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 و تست با اسکریپت‌ها جلوگیری شود.

•جستجوی دودویی خودکار با اصلاحات موقت (hot-fix):
$ 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 کاملاً قابل پیمایش است.

•جستجو برای یک اصلاح (fix) به جای افت کارایی در کد
$ 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 استفاده کنید.

Fighting regressions with git bisect[1], git-blame(1).

بخشی از مجموعه git(1)

1.
مبارزه با پس‌رفت‌ها با git bisect (Fighting regressions with git bisect)
file:///usr/share/doc/git-doc/git-bisect-lk2009.html
2026-06-29 Git 2.55.0