找了一天找不到 Bug ? 試試 Git 的二分法吧?。?!
你一定遇到過,一個(gè)很久沒修改過的功能,莫名其妙的出現(xiàn)了問題?肉眼查代碼、屢邏輯完全找不到問題點(diǎn)?前兩天還好好的功能,怎么這個(gè)今天就不行了?這兩天改動(dòng)了這么多代碼,到底是那一次改動(dòng)引發(fā)的 Bug?
這樣非崩潰的 Bug,有時(shí)候想要排查出問題,并不是一件容易的事情。我想,這個(gè)時(shí)候你會需要 git bisect !
一、git bisect 基礎(chǔ)使用
git bisect 是 Git 提供的一種 二分法 的調(diào)試工具,它可以按照我們選定的提交,進(jìn)行二分分割,快速定位出出錯(cuò)的提交。來幫我們縮小最小改動(dòng)的代碼,從而快速定位問題。
git bisect 其實(shí)很簡單,主要是基于幾個(gè)基本命令:
- git bisect start:準(zhǔn)備進(jìn)行 bisect debug。
- git bisect good:標(biāo)記一個(gè)提交為 "good"。
- git bisect bad:標(biāo)記一個(gè)提交為 “bad”。
- git bisect reset:退出 bisect debug 的狀態(tài)。
git bisect 涉及到的命令,非常的清晰簡單,下面舉個(gè)實(shí)際的例子,結(jié)合上面的解釋,就更清晰了。
二、git bisect 工作流
我自己生造出 6 個(gè) commit,然后使用 git log 看看我的提交記錄。
這里假設(shè)我正常開發(fā)的階段,到 v6 提交的時(shí)候,突然發(fā)現(xiàn)有個(gè) Bug ,無法定位到問題,但是能明確的知道,在 v1 提交階段,并沒有這個(gè) Bug。
那么,在這樣的情況下,v6 就是一個(gè)有問題的版本,而 v1 則是一個(gè)好的版本,我們就可以借助 git bisect 來進(jìn)行二分超找定位問題來自哪個(gè)提交。
還記得剛才的命令嗎?
我們先用 git bisect start 標(biāo)記開始 bisect debug ,然后使用 git bisect good 和 git bisect bad 分別標(biāo)記出正確的和錯(cuò)誤的提交。
每個(gè)提交,都有一個(gè)針對這個(gè)提交唯一的 SHA-1 值,因?yàn)樘L不方便輸入和閱讀,這里可以直接使用前幾位作為簡寫。
當(dāng)標(biāo)記處正確的和錯(cuò)誤的提交之后,git bisect 立刻就可以幫我們定位出中間提交 v3。
現(xiàn)在 HEAD 就已經(jīng)指向了 v3 提交的代碼了,這個(gè)可以使用 git status 查看當(dāng)前的狀態(tài)。
所以我們可以基于 v3 版本的代碼,直接運(yùn)行項(xiàng)目,測試看該提交是否有問題。
經(jīng)過測試之后,發(fā)現(xiàn) v3 的提交代碼版本,并沒有復(fù)現(xiàn) Bug,那我們就可以縮小錯(cuò)誤提交的范圍,大概落在了 v4、v5、v6 之間。
此時(shí),我們只需要使用 git good 標(biāo)記 v3 版本是正確的。
標(biāo)記好 v3 為 good 之后,立刻又會進(jìn)行一次二分,此次標(biāo)記的為中間提交 v5。
經(jīng)過對 v5 提交的版本代碼,進(jìn)行測試之后發(fā)現(xiàn),它是有問題的。我們繼續(xù)使用 git bisect bad 對它進(jìn)行標(biāo)記。
當(dāng) v5 有問題的時(shí)候,現(xiàn)在只中間一個(gè) v4 版本,所以會立刻指向 v4 提交。
我們繼續(xù)對 v4 版本的代碼進(jìn)行測試,發(fā)現(xiàn) v4 版本也有問題,繼續(xù)標(biāo)記它為 bad 。
此時(shí)就很明確了,出錯(cuò)的提交就是 v4,而 Git 也直接幫我們指出來出錯(cuò)的提交。
雖然這里定位到,出錯(cuò)的提交就是 v4 的問題,我們只需要仔細(xì)閱讀 v4 提交的代碼,然后定位出問題代碼,就達(dá)到了我們的目的。但是我們并不應(yīng)該在 v4 提交上直接修改 Bug,我們應(yīng)該退出 bisect debug 狀態(tài),在***的提交版本上進(jìn)行修改,這里使用 git bisect reset 退出,再進(jìn)行修改即可。
到這里,就是 git bisect 的完整工作流程。
三、bisect的后悔藥
對提交進(jìn)行 good 和 bad 的標(biāo)記,都是人為來進(jìn)行的,難免有出錯(cuò)的情況。而提交比較少的時(shí)候,大不了就是 reset 之后,重頭來過。
但是如果有幾十個(gè)提交,再從頭進(jìn)行一次 bisect 就比較麻煩了。Git 考慮到這一點(diǎn),已經(jīng)為我們配好了后悔藥。
想要擦除之前的標(biāo)記狀態(tài),就涉及到一個(gè)命令:
- git bisect replay:重置到某個(gè)狀態(tài)。
replay 需要制定一個(gè)回退的點(diǎn),這個(gè)點(diǎn)是需要使用 git bisect log > log.txt 輸出的 Log 文件, 我們需要通過修改這個(gè) Log 文件,來確定回退的點(diǎn)。
舉個(gè)例子,我們使用 log 命令,輸出一個(gè) log.txt 文件。
可以看到,這個(gè) log.txt 文件,記錄了我們剛才所有的操作。
在這個(gè)例子中,假如我們的操作,對 v5 進(jìn)行 bad 的這個(gè)標(biāo)記錯(cuò)了,那么,我們把這個(gè)操作之下的 Log 全部刪除掉,然后執(zhí)行 git bisect replay log.txt。
這樣就將回退到判斷 v5 提交好壞的地方,重新進(jìn)行標(biāo)記。
在修改 Log.txt 文件的時(shí)候,***只執(zhí)行刪除操作,不要對其中的順序有所修改,畢竟我們只是想要一個(gè)回滾的動(dòng)作,并不是要改動(dòng)我們之前的某些操作。
【本文為51CTO專欄作者“張旸”的原創(chuàng)稿件,轉(zhuǎn)載請通過微信公眾號聯(lián)系作者獲取授權(quán)】