?
This document uses PHP Chinese website manual Release
git-bisect - 使用二進(jìn)制搜索來(lái)查找引入錯(cuò)誤的提交
git bisect <subcommand> <options>
該命令根據(jù)子命令采用各種子命令和不同的選項(xiàng):
git bisect start [--term-{old,good}=<term> --term-{new,bad}=<term>] [--no-checkout] [<bad> [<good>...]] [--] [<paths>...]git bisect (bad|new|<term-new>) [<rev>]git bisect (good|old|<term-old>) [<rev>...]git bisect terms [--term-good | --term-bad]git bisect skip [(<rev>|<range>)...]git bisect reset [<commit>]git bisect visualize git bisect replay <logfile>git bisect log git bisect run <cmd>...git bisect help
該命令使用二進(jìn)制搜索算法來(lái)查找項(xiàng)目歷史記錄中的哪個(gè)提交引入了錯(cuò)誤。通過(guò)首先告訴它一個(gè)已知包含該錯(cuò)誤的“錯(cuò)誤”提交以及一個(gè)在引入該錯(cuò)誤之前已知的“良好”提交來(lái)使用它。然后git bisect
在這兩個(gè)端點(diǎn)之間選擇一個(gè)提交,并詢問(wèn)所選提交是“好”還是“壞”。它繼續(xù)縮小范圍,直到找到引入更改的確切提交。
事實(shí)上,git bisect
可以用來(lái)發(fā)現(xiàn)改變提交的任何項(xiàng)目的財(cái)產(chǎn); 例如,修正錯(cuò)誤的提交或?qū)е禄鶞?zhǔn)性能提高的提交。為了支持這種更一般的用法,可以使用術(shù)語(yǔ)“舊”和“新”來(lái)代替“好”和“壞”,或者可以選擇自己的術(shù)語(yǔ)。有關(guān)更多信息,請(qǐng)參見(jiàn)下面的“替代條款”部分。
作為一個(gè)例子,假設(shè)您正在嘗試查找違反已知可在v2.6.13-rc2
您的項(xiàng)目版本中工作的功能的提交。你開(kāi)始平分會(huì)議如下:
$ git bisect start $ git bisect bad # Current version is bad $ git bisect good v2.6.13-rc2 # v2.6.13-rc2 is known to be good
一旦你指定了至少一個(gè)壞的和一個(gè)好的提交,git bisect
在該歷史范圍的中間選擇一個(gè)提交,檢查出來(lái),并輸出類(lèi)似于以下內(nèi)容的提交:
Bisecting: 675 revisions left to test after this (roughly 10 steps)
您現(xiàn)在應(yīng)該編譯檢出版本并對(duì)其進(jìn)行測(cè)試。如果該版本正常工作,請(qǐng)鍵入
$ git bisect good
如果該版本已損壞,請(qǐng)鍵入
$ git bisect bad
然后git bisect
會(huì)用類(lèi)似的回應(yīng)
Bisecting: 337 revisions left to test after this (roughly 9 steps)
繼續(xù)重復(fù)這個(gè)過(guò)程:編譯樹(shù),測(cè)試它,并根據(jù)它是好還是壞運(yùn)行git bisect good
或git bisect bad
詢問(wèn)下一個(gè)需要測(cè)試的提交。
最終將不會(huì)有更多的修訂留下來(lái)檢查,并且該命令將打印出第一個(gè)錯(cuò)誤提交的描述。該引用refs/bisect/bad
將指向該提交。
在平分會(huì)話之后,要清理平分狀態(tài)并返回到原始 HEAD,請(qǐng)發(fā)出以下命令:
$ git bisect reset
默認(rèn)情況下,這會(huì)將您的樹(shù)返回到之前簽出的提交git bisect start
。(一個(gè)新的git bisect start
也會(huì)這樣做,因?yàn)樗謇砹伺f的二分法狀態(tài)。)
使用可選參數(shù),您可以返回到其他提交:
$ git bisect reset <commit>
例如,git bisect reset bisect/bad
將檢查第一個(gè)錯(cuò)誤的修訂,同時(shí)git bisect reset HEAD
會(huì)讓您處于當(dāng)前的平分提交并避免切換提交。
有時(shí)候你并不是在尋找導(dǎo)致破壞的提交,而是尋找導(dǎo)致其他“舊”狀態(tài)和“新”狀態(tài)之間發(fā)生變化的提交。例如,您可能正在尋找引入特定修補(bǔ)程序的提交?;蛘吣赡苷趯ふ业谝淮翁峤?,其中源代碼文件名最終全部轉(zhuǎn)換為貴公司的命名標(biāo)準(zhǔn)。管他呢。
在這種情況下,使用“好”和“壞”這兩個(gè)術(shù)語(yǔ)來(lái)指代“改變前的狀態(tài)”和“改變后的狀態(tài)”可能會(huì)非常混亂。相反,您可以分別使用術(shù)語(yǔ)“舊”和“新”來(lái)代替“好”和“壞”。(但請(qǐng)注意,您不能在單個(gè)會(huì)話中將“好”和“壞”與“舊”和“新”混合在一起。)
在這個(gè)更通用的用法中,你提供git bisect
了一個(gè)“新”提交,它有一些屬性和一個(gè)沒(méi)有該屬性的“舊”提交。每次git bisect
檢出提交時(shí),都會(huì)測(cè)試該提交是否具有該屬性。如果是,則將提交標(biāo)記為“新”; 否則,將其標(biāo)記為“舊”。當(dāng)平分完成后,git bisect
將報(bào)告哪個(gè)提交引入了屬性。
要使用“old”和“new”而不是“good”和 bad,你必須運(yùn)行git bisect start
沒(méi)有提交作為參數(shù),然后運(yùn)行以下命令來(lái)添加提交:
git bisect old [<rev>]
表明某個(gè)提交是在尋求更改之前進(jìn)行的,或者
git bisect new [<rev>...]
以表明它是在之后。
要獲得當(dāng)前使用條款的提醒,請(qǐng)使用
git bisect terms
你可以用git bisect term --term-old
or git bisect term --term-good
來(lái)獲得舊的(分別是新的)術(shù)語(yǔ)。
如果你想用你自己的條件,而不是“壞” /“好”或“新” /“老”,你可以選擇你喜歡的任何名稱(除現(xiàn)有對(duì)開(kāi)子一樣reset
,start
通過(guò)使用開(kāi)始平分,...)
git bisect start --term-old <term-old> --term-new <term-new>
例如,如果您正在尋找引入性能回歸的提交,則可以使用
git bisect start --term-old fast --term-new slow
或者,如果您正在尋找修復(fù)錯(cuò)誤的提交,則可以使用
git bisect start --term-new fixed --term-old broken
然后,使用git bisect <term-old>
和git bisect <term-new>
代替git bisect good
和git bisect bad
標(biāo)記提交。
要查看當(dāng)前剩余的可疑對(duì)象gitk
,請(qǐng)?jiān)趯?duì)分過(guò)程中發(fā)出以下命令:
$ git bisect visualize
view
也可以用作同義詞visualize
。
如果DISPLAY
沒(méi)有設(shè)置環(huán)境變量,git log
則用來(lái)代替。您還可以提供諸如-p
和--stat
的命令行選項(xiàng)。
$ git bisect view --stat
在將修訂標(biāo)記為好或不好之后,發(fā)出以下命令以顯示迄今為止所做的工作:
$ git bisect log
如果您發(fā)現(xiàn)在指定修訂狀態(tài)時(shí)出錯(cuò),可以將此命令的輸出保存到文件中,對(duì)其進(jìn)行編輯以刪除不正確的條目,然后發(fā)出以下命令以返回到更正的狀態(tài):
$ git bisect reset $ git bisect replay that-file
如果在平分會(huì)話中,您知道建議的修訂版不適合測(cè)試(例如,它無(wú)法構(gòu)建并且您知道失敗與您正在追蹤的錯(cuò)誤沒(méi)有任何關(guān)系),那么您可以手動(dòng)選擇一個(gè)附近的提交并測(cè)試那個(gè)。
例如:
$ git bisect good/bad # previous round was good or bad.Bisecting: 337 revisions left to test after this (roughly 9 steps)$ git bisect visualize # oops, that is uninteresting.$ git reset --hard HEAD~3 # try 3 revisions before what # was suggested
然后編譯并測(cè)試所選修訂版,然后以通常方式將修訂版標(biāo)記為好或不好。
您可以通過(guò)發(fā)出以下命令來(lái)請(qǐng)求 Git 為您執(zhí)行:
$ git bisect skip # Current version cannot be tested
但是,如果您跳過(guò)與您正在尋找的相鄰的提交,那么 Git 將無(wú)法準(zhǔn)確地確定哪些提交是第一個(gè)不合格提交。
您也可以使用范圍表示法跳過(guò)一系列提交,而不是僅提交一次提交。例如:
$ git bisect skip v2.5..v2.6
這告訴平分過(guò)程,在測(cè)試之后v2.5
,直到并包括v2.6
,都不應(yīng)該進(jìn)行提交。
請(qǐng)注意,如果您還想跳過(guò)該范圍的第一次提交,則可以發(fā)出以下命令:
$ git bisect skip v2.5 v2.5..v2.6
這表明平分過(guò)程,應(yīng)該跳過(guò)v2.5
和v2.6
(包括)之間的提交。
如果通過(guò)發(fā)出bisect start
命令時(shí)指定路徑參數(shù),您可以進(jìn)一步減少試驗(yàn)次數(shù),如果您知道您要追蹤的問(wèn)題涉及哪部分樹(shù),請(qǐng)執(zhí)行以下操作:
$ git bisect start -- arch/i386 include/asm-i386
如果事先知道多個(gè)好提交,則可以在發(fā)出bisect start
命令時(shí)通過(guò)在錯(cuò)誤提交之后立即指定所有好提交來(lái)縮小對(duì)分空間:
$ git bisect start v2.6.20-rc6 v2.6.20-rc4 v2.6.20-rc1 -- # v2.6.20-rc6 is bad # v2.6.20-rc4 and v2.6.20-rc1 are good
如果您有一個(gè)腳本可以確定當(dāng)前源代碼是好還是壞,可以通過(guò)發(fā)出以下命令來(lái)平分:
$ git bisect run my_script arguments
注意,my_script
如果當(dāng)前源代碼是好的/舊的,腳本(在上面的例子中)應(yīng)該以代碼0退出,并且以1和127之間的代碼(包括125)退出,除非125,如果當(dāng)前源代碼是壞的/新的。
任何其他退出代碼將中止對(duì)分過(guò)程。應(yīng)該指出的是,一個(gè)程序,通過(guò)exit(-1)
leaves $? = 255,(參見(jiàn)出口(3)手冊(cè)頁(yè)),因?yàn)橹当?code>& 0377切斷。
當(dāng)不能測(cè)試當(dāng)前源代碼時(shí),應(yīng)使用特殊退出碼125。如果腳本以此代碼退出,則當(dāng)前修訂將被跳過(guò)(參見(jiàn)git bisect skip
上文)。125被選為用于此目的的最高敏感值,因?yàn)?POSIX shell 使用126和127來(lái)表示特定的錯(cuò)誤狀態(tài)(127表示找不到命令,126表示找到的命令但不可執(zhí)行 - 這些細(xì)節(jié)不會(huì)問(wèn)題,因?yàn)樗鼈冊(cè)谀_本中是正常的錯(cuò)誤,就其bisect run
而言)。
你可能經(jīng)常會(huì)發(fā)現(xiàn),在平分會(huì)話期間,你希望進(jìn)行臨時(shí)修改(例如,在頭文件中s/#define DEBUG 0/#define DEBUG 1/,或者“沒(méi)有這個(gè)提交的修訂版本需要這個(gè)補(bǔ)丁應(yīng)用于解決方法另一個(gè)問(wèn)題是這種平分不感興趣“)適用于正在測(cè)試的版本。
為了應(yīng)對(duì)這種情況,在內(nèi)部git bisect
發(fā)現(xiàn)下一個(gè)修訂版測(cè)試之后,腳本可以在編譯之前應(yīng)用修補(bǔ)程序,運(yùn)行真實(shí)測(cè)試,然后確定修訂版(可能包含所需修補(bǔ)程序)是否通過(guò)測(cè)試,然后倒帶樹(shù)到原始狀態(tài)。最后,腳本應(yīng)該以真實(shí)測(cè)試的狀態(tài)退出,讓git bisect run
命令循環(huán)確定對(duì)分會(huì)話的最終結(jié)果。
--no-checkout
在平分過(guò)程的每次迭代中,不要簽出新的工作樹(shù)。相反,只需更新一個(gè)特定的引用BISECT_HEAD
,使其指向應(yīng)該測(cè)試的提交。
當(dāng)您在每個(gè)步驟中執(zhí)行的測(cè)試不需要檢出樹(shù)時(shí),此選項(xiàng)可能很有用。
假設(shè)--no-checkout
,如果存儲(chǔ)庫(kù)是裸露的。
在v1.2和HEAD之間自動(dòng)平分一個(gè)破損的構(gòu)建:$ git bisect start HEAD v1.2 - #HEAD不好,v1.2很好$ git bisect run make?!癿ake”構(gòu)建應(yīng)用程序$ git bisect reset#quit平分會(huì)議
自動(dòng)平分原點(diǎn)和 HEAD 之間的測(cè)試失?。?/p>
$ git bisect start HEAD origin -- # HEAD is bad, origin is good $ git bisect run make test # "make test" builds and tests $ git bisect reset # quit the bisect session
Automatically bisect a broken test case:
$ cat ~/test.sh #!/bin/sh make || exit 125 # this skips broken builds ~/check_test_case.sh # does the test case pass? $ git bisect start HEAD HEAD~10 -- # culprit is among the last 10 $ git bisect run ~/test.sh $ git bisect reset # quit the bisect sessionHere we use a test.sh
custom script. In this script, if make
fails, we skip the current commit. check_test_case.sh
should exit 0
if the test case passes, and exit 1
otherwise.
It is safer if both test.sh
and check_test_case.sh
are outside the repository to prevent interactions between the bisect, make and test processes and the scripts.
通過(guò)臨時(shí)修改自動(dòng)平分(熱修復(fù)):
$ cat ~/test.sh #!/bin/sh # tweak the working tree by merging the hot-fix branch # and then attempt a build if git merge --no-commit hot-fix && make then # run project specific test and report its status ~/check_test_case.sh status=$? else # tell the caller this is untestable status=125 fi # undo the tweak to allow clean flipping to the next commit git reset --hard # return control exit $status
這適用于在每次測(cè)試運(yùn)行之前從熱修復(fù)分支進(jìn)行的修改,例如,如果您的構(gòu)建或測(cè)試環(huán)境發(fā)生變化,以便舊版本可能需要修復(fù)哪些新版本已經(jīng)修復(fù)。(確保燙分支是基于關(guān)閉提交其包含在你平分所有修訂,使合并沒(méi)有太多拉,或使用git cherry-pick
替代git merge
。)
自動(dòng)對(duì)分破損的測(cè)試用例:$ git bisect start HEAD HEAD?10 - #ctrprit是最后10個(gè)$ git bisect運(yùn)行sh -c“make || exit 125;?/ check_test_case.sh”$ git bisect reset#quit平分會(huì)話這表明,如果您在單行上編寫(xiě)測(cè)試,則可以不使用運(yùn)行腳本。
在損壞的存儲(chǔ)庫(kù)中找到對(duì)象圖的一個(gè)好區(qū)域
$ 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 # quit the bisect session
在這種情況下,當(dāng)git bisect run
完成時(shí),bisect / bad 將引用一個(gè)提交,該提交至少有一個(gè)可達(dá)圖git pack objects
可完全遍歷的父對(duì)象。
在代碼中尋找修復(fù)而不是回歸
$ git bisect start $ git bisect new HEAD # current commit is marked as new $ git bisect old HEAD~10 # the tenth commit from now is marked as old
or:
$ git bisect start --term-old broken --term-new fixed$ git bisect fixed $ git bisect broken HEAD~10
使用git bisect
得到一個(gè)簡(jiǎn)短的使用說(shuō)明,以及git bisect help
或git bisect -h
獲得長(zhǎng)期的使用說(shuō)明。