?
Ce document utilise Manuel du site Web PHP chinois Libérer
git-bisect - 使用二進制搜索來查找引入錯誤的提交
git bisect <subcommand> <options>
該命令根據(jù)子命令采用各種子命令和不同的選項:
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
該命令使用二進制搜索算法來查找項目歷史記錄中的哪個提交引入了錯誤。通過首先告訴它一個已知包含該錯誤的“錯誤”提交以及一個在引入該錯誤之前已知的“良好”提交來使用它。然后git bisect
在這兩個端點之間選擇一個提交,并詢問所選提交是“好”還是“壞”。它繼續(xù)縮小范圍,直到找到引入更改的確切提交。
事實上,git bisect
可以用來發(fā)現(xiàn)改變提交的任何項目的財產(chǎn); 例如,修正錯誤的提交或?qū)е禄鶞市阅芴岣叩奶峤弧榱酥С诌@種更一般的用法,可以使用術語“舊”和“新”來代替“好”和“壞”,或者可以選擇自己的術語。有關更多信息,請參見下面的“替代條款”部分。
作為一個例子,假設您正在嘗試查找違反已知可在v2.6.13-rc2
您的項目版本中工作的功能的提交。你開始平分會議如下:
$ 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
一旦你指定了至少一個壞的和一個好的提交,git bisect
在該歷史范圍的中間選擇一個提交,檢查出來,并輸出類似于以下內(nèi)容的提交:
Bisecting: 675 revisions left to test after this (roughly 10 steps)
您現(xiàn)在應該編譯檢出版本并對其進行測試。如果該版本正常工作,請鍵入
$ git bisect good
如果該版本已損壞,請鍵入
$ git bisect bad
然后git bisect
會用類似的回應
Bisecting: 337 revisions left to test after this (roughly 9 steps)
繼續(xù)重復這個過程:編譯樹,測試它,并根據(jù)它是好還是壞運行git bisect good
或git bisect bad
詢問下一個需要測試的提交。
最終將不會有更多的修訂留下來檢查,并且該命令將打印出第一個錯誤提交的描述。該引用refs/bisect/bad
將指向該提交。
在平分會話之后,要清理平分狀態(tài)并返回到原始 HEAD,請發(fā)出以下命令:
$ git bisect reset
默認情況下,這會將您的樹返回到之前簽出的提交git bisect start
。(一個新的git bisect start
也會這樣做,因為它清理了舊的二分法狀態(tài)。)
使用可選參數(shù),您可以返回到其他提交:
$ git bisect reset <commit>
例如,git bisect reset bisect/bad
將檢查第一個錯誤的修訂,同時git bisect reset HEAD
會讓您處于當前的平分提交并避免切換提交。
有時候你并不是在尋找導致破壞的提交,而是尋找導致其他“舊”狀態(tài)和“新”狀態(tài)之間發(fā)生變化的提交。例如,您可能正在尋找引入特定修補程序的提交?;蛘吣赡苷趯ふ业谝淮翁峤?,其中源代碼文件名最終全部轉(zhuǎn)換為貴公司的命名標準。管他呢。
在這種情況下,使用“好”和“壞”這兩個術語來指代“改變前的狀態(tài)”和“改變后的狀態(tài)”可能會非?;靵y。相反,您可以分別使用術語“舊”和“新”來代替“好”和“壞”。(但請注意,您不能在單個會話中將“好”和“壞”與“舊”和“新”混合在一起。)
在這個更通用的用法中,你提供git bisect
了一個“新”提交,它有一些屬性和一個沒有該屬性的“舊”提交。每次git bisect
檢出提交時,都會測試該提交是否具有該屬性。如果是,則將提交標記為“新”; 否則,將其標記為“舊”。當平分完成后,git bisect
將報告哪個提交引入了屬性。
要使用“old”和“new”而不是“good”和 bad,你必須運行git bisect start
沒有提交作為參數(shù),然后運行以下命令來添加提交:
git bisect old [<rev>]
表明某個提交是在尋求更改之前進行的,或者
git bisect new [<rev>...]
以表明它是在之后。
要獲得當前使用條款的提醒,請使用
git bisect terms
你可以用git bisect term --term-old
or git bisect term --term-good
來獲得舊的(分別是新的)術語。
如果你想用你自己的條件,而不是“壞” /“好”或“新” /“老”,你可以選擇你喜歡的任何名稱(除現(xiàn)有對開子一樣reset
,start
通過使用開始平分,...)
git bisect start --term-old <term-old> --term-new <term-new>
例如,如果您正在尋找引入性能回歸的提交,則可以使用
git bisect start --term-old fast --term-new slow
或者,如果您正在尋找修復錯誤的提交,則可以使用
git bisect start --term-new fixed --term-old broken
然后,使用git bisect <term-old>
和git bisect <term-new>
代替git bisect good
和git bisect bad
標記提交。
要查看當前剩余的可疑對象gitk
,請在對分過程中發(fā)出以下命令:
$ git bisect visualize
view
也可以用作同義詞visualize
。
如果DISPLAY
沒有設置環(huán)境變量,git log
則用來代替。您還可以提供諸如-p
和--stat
的命令行選項。
$ git bisect view --stat
在將修訂標記為好或不好之后,發(fā)出以下命令以顯示迄今為止所做的工作:
$ git bisect log
如果您發(fā)現(xiàn)在指定修訂狀態(tài)時出錯,可以將此命令的輸出保存到文件中,對其進行編輯以刪除不正確的條目,然后發(fā)出以下命令以返回到更正的狀態(tài):
$ git bisect reset $ git bisect replay that-file
如果在平分會話中,您知道建議的修訂版不適合測試(例如,它無法構建并且您知道失敗與您正在追蹤的錯誤沒有任何關系),那么您可以手動選擇一個附近的提交并測試那個。
例如:
$ 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
然后編譯并測試所選修訂版,然后以通常方式將修訂版標記為好或不好。
您可以通過發(fā)出以下命令來請求 Git 為您執(zhí)行:
$ git bisect skip # Current version cannot be tested
但是,如果您跳過與您正在尋找的相鄰的提交,那么 Git 將無法準確地確定哪些提交是第一個不合格提交。
您也可以使用范圍表示法跳過一系列提交,而不是僅提交一次提交。例如:
$ git bisect skip v2.5..v2.6
這告訴平分過程,在測試之后v2.5
,直到并包括v2.6
,都不應該進行提交。
請注意,如果您還想跳過該范圍的第一次提交,則可以發(fā)出以下命令:
$ git bisect skip v2.5 v2.5..v2.6
這表明平分過程,應該跳過v2.5
和v2.6
(包括)之間的提交。
如果通過發(fā)出bisect start
命令時指定路徑參數(shù),您可以進一步減少試驗次數(shù),如果您知道您要追蹤的問題涉及哪部分樹,請執(zhí)行以下操作:
$ git bisect start -- arch/i386 include/asm-i386
如果事先知道多個好提交,則可以在發(fā)出bisect start
命令時通過在錯誤提交之后立即指定所有好提交來縮小對分空間:
$ 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
如果您有一個腳本可以確定當前源代碼是好還是壞,可以通過發(fā)出以下命令來平分:
$ git bisect run my_script arguments
注意,my_script
如果當前源代碼是好的/舊的,腳本(在上面的例子中)應該以代碼0退出,并且以1和127之間的代碼(包括125)退出,除非125,如果當前源代碼是壞的/新的。
任何其他退出代碼將中止對分過程。應該指出的是,一個程序,通過exit(-1)
leaves $? = 255,(參見出口(3)手冊頁),因為值被& 0377
切斷。
當不能測試當前源代碼時,應使用特殊退出碼125。如果腳本以此代碼退出,則當前修訂將被跳過(參見git bisect skip
上文)。125被選為用于此目的的最高敏感值,因為 POSIX shell 使用126和127來表示特定的錯誤狀態(tài)(127表示找不到命令,126表示找到的命令但不可執(zhí)行 - 這些細節(jié)不會問題,因為它們在腳本中是正常的錯誤,就其bisect run
而言)。
你可能經(jīng)常會發(fā)現(xiàn),在平分會話期間,你希望進行臨時修改(例如,在頭文件中s/#define DEBUG 0/#define DEBUG 1/,或者“沒有這個提交的修訂版本需要這個補丁應用于解決方法另一個問題是這種平分不感興趣“)適用于正在測試的版本。
為了應對這種情況,在內(nèi)部git bisect
發(fā)現(xiàn)下一個修訂版測試之后,腳本可以在編譯之前應用修補程序,運行真實測試,然后確定修訂版(可能包含所需修補程序)是否通過測試,然后倒帶樹到原始狀態(tài)。最后,腳本應該以真實測試的狀態(tài)退出,讓git bisect run
命令循環(huán)確定對分會話的最終結果。
--no-checkout
在平分過程的每次迭代中,不要簽出新的工作樹。相反,只需更新一個特定的引用BISECT_HEAD
,使其指向應該測試的提交。
當您在每個步驟中執(zhí)行的測試不需要檢出樹時,此選項可能很有用。
假設--no-checkout
,如果存儲庫是裸露的。
在v1.2和HEAD之間自動平分一個破損的構建:$ git bisect start HEAD v1.2 - #HEAD不好,v1.2很好$ git bisect run make?!癿ake”構建應用程序$ git bisect reset#quit平分會議
自動平分原點和 HEAD 之間的測試失?。?/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.
通過臨時修改自動平分(熱修復):
$ 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
這適用于在每次測試運行之前從熱修復分支進行的修改,例如,如果您的構建或測試環(huán)境發(fā)生變化,以便舊版本可能需要修復哪些新版本已經(jīng)修復。(確保燙分支是基于關閉提交其包含在你平分所有修訂,使合并沒有太多拉,或使用git cherry-pick
替代git merge
。)
自動對分破損的測試用例:$ git bisect start HEAD HEAD?10 - #ctrprit是最后10個$ git bisect運行sh -c“make || exit 125;?/ check_test_case.sh”$ git bisect reset#quit平分會話這表明,如果您在單行上編寫測試,則可以不使用運行腳本。
在損壞的存儲庫中找到對象圖的一個好區(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
在這種情況下,當git bisect run
完成時,bisect / bad 將引用一個提交,該提交至少有一個可達圖git pack objects
可完全遍歷的父對象。
在代碼中尋找修復而不是回歸
$ 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
得到一個簡短的使用說明,以及git bisect help
或git bisect -h
獲得長期的使用說明。