使用git bisect二分法定位問題的基本步驟:
- git bisect start [最近的出錯的commitid] [較遠的正確的commitid]
- 測試相應的功能
- git bisect good 標記正確
- 直到出現問題則 標記錯誤 git bisect bad
- 提示的commitid就是導致問題的那次提交
問題描述
我們以Vue DevUI元件庫的一個bug舉例子?
5d14c34b
這一次commit,執行yarn build
報錯,報錯資訊如下:
✓ building client + server bundles...
✖ rendering pages...
build error:
ReferenceError: document is not defined
我可以確定的是上一次發版本(d577ce4)是可以build成功的。
git bisect 簡介
git bisect
命令使用二分搜尋演算法來查詢提交歷史中的哪一次提交引入了錯誤。它幾乎能讓你閉著眼睛快速定位任何原始碼導致的問題,非常實用。
你只需要告訴這個命令一個包含該bug的壞commit ID
和一個引入該bug之前的好commit ID
,這個命令會用二分法在這兩個提交之間選擇一箇中間的commit ID
,切換到那個commit ID
的程式碼,然後詢問你這是好的commit ID
還是壞的commit ID
,你告訴它是好還是壞,然後它會不斷縮小範圍,直到找到那次引入bug的凶手commit ID
。
這樣我們就只需要分析那一次提交的程式碼,就能快速定位和解決這個bug(具體定位的時間取決於該次提交的程式碼量和你的經驗),所以我們提交程式碼時一定要養成小批量提交的習慣,每次只提交一個小的獨立功能,這樣出問題了,定位起來會非常快。
接下來我就以Vue DevUI之前出現過的一個bug為例,詳細介紹下如何使用git bisect
這把利器。
定位過程
git bisect start 5d14c34b d577ce4
or
git bisect start HEAD d577ce4
其中5d14c34b
這次是最近出現的有bug的提交,d577ce4
這個是上一次發版本沒問題的提交。
執行完啟動bisect
之後,馬上就切到中間的一次提交啦,以下是列印結果:
kagol:vue-devui kagol$ git bisect start 5d14c34b d577ce4
Bisecting: 11 revisions left to test after this (roughly 4 steps)
[1cfafaaa58e03850e0c9ddc4246ae40d18b03d71] fix: read-tip icon樣式洩露 (#54)
可以看到已經切到以下提交:
[1cfafaaa] fix: read-tip icon樣式洩露 (#54)
執行命令:
yarn build
構建成功,所以標記下good
:
git bisect good
kagol:vue-devui kagol$ git bisect good
Bisecting: 5 revisions left to test after this (roughly 3 steps)
[c0c4cc1a25c5c6967b85100ee8ac636d90eff4b0] feat(drawer): add service model (#27)
標記萬good
,馬上又通過二分法,切到了一次新的提交:
[c0c4cc1a] feat(drawer): add service model (#27)
再次執行build
命令:
yarn build
build失敗了,出現了我們最早遇到的報錯:
✓ building client + server bundles...
✖ rendering pages...
build error:
ReferenceError: document is not defined
標記下bad
,再一次切到中間的提交:
kagol:vue-devui kagol$ git bisect bad
Bisecting: 2 revisions left to test after this (roughly 2 steps)
[86634fd8efd2b808811835e7cb7ca80bc2904795] feat: add scss preprocessor in docs && fix:(Toast) single lifeMode bug in Toast
以此類推,不斷地驗證、標記、驗證、標記...最終會提示我們那一次提交導致了這次的bug,提交者、提交時間、提交message等資訊。
kagol:vue-devui kagol$ git bisect good
c0c4cc1a25c5c6967b85100ee8ac636d90eff4b0 is the first bad commit
commit c0c4cc1a25c5c6967b85100ee8ac636d90eff4b0
Author: nif <lnzhangsong@163.com>
Date: Sun Dec 26 21:37:05 2021 +0800
feat(drawer): add service model (#27)
* feat(drawer): add service model
* docs(drawer): add service model demo
* fix(drawer): remove 'console.log()'
packages/devui-vue/devui/drawer/index.ts | 7 +++--
.../devui-vue/devui/drawer/src/drawer-service.ts | 33 ++++++++++++++++++++++
packages/devui-vue/devui/drawer/src/drawer.tsx | 3 ++
packages/devui-vue/docs/components/drawer/index.md | 29 +++++++++++++++++++
4 files changed, 69 insertions(+), 3 deletions(-)
create mode 100644 packages/devui-vue/devui/drawer/src/drawer-service.ts
最終定位到出問題的commit:
c0c4cc1a is the first bad commit
https://github.com/DevCloudFE/vue-devui/commit/c0c4cc1a25c5c6967b85100ee8ac636d90eff4b0
整個定位過程幾乎是機械的操作,不需要了解專案原始碼,不需要了解最近誰提交了什麼內容,只需要無腦地:驗證、標記、驗證、標記,最後git會告訴我們那一次提交出錯。
這麼香的工具,趕緊來試試吧!
問題分析
直到哪個commit出問題了,定位起來範圍就小了很多。
如果平時提交程式碼又能很好地遵循小顆粒提交的話,bug呼之欲出。
這裡必須表揚下我們DevUI的田主(Contributor)們,他們都養成了小顆粒提交的習慣,這次導致bug的提交c0c4cc1a
,只提交了4個檔案,涉及70多行程式碼。
我們在其中搜尋下document
關鍵字,發現了兩處,都在drawer-service.ts
整個檔案中:
一處是12行的:
static $body: HTMLElement | null = document.body
另一處是17行的:
this.$div = document.createElement('div')
最終發現罪魁禍首就是12行的程式碼!
破案!
此處@lnzhangsong我們的田主,有空麻煩修下這個bug。