如何使用 git bisect 快速找出有 bug 的 commit ?

在知道 git bisect
的用法之前如果要找出有 bug 的 commit,往往是 checkout 回之前的 commit,測試程式碼,再 checkout 到更早之前的 commit,測試程式碼,一直試到這個 commit 沒問題,才知道程式是在下一個 commit 開始壞掉的,這樣的找法實在很沒效率。
git 提供你一個更快速的方法,使用 git bisect
做二分搜尋法來找出有問題的 bug commit。你必須先告訴 git 一個已知是壞掉的 commit 當作是開頭,然後一個已知是正常的 commit 當作是結尾。 git bisect
會用這個範圍做二分搜尋法不斷地問你這個 commit 是好的還是壞的,一直問到找出有 bug 的 commit 為止。
以下指令將會使用 https://github.com/kmsheng/git-bisect-demo 這個 repo 說明,有興趣操作的讀者可以自行 clone 下來。有 bug 的 commit 是 02acafd feat: This is the commit that breaks add function
,從這個 commit 開始 add 方法會丟出 error 不能使用。
使用的方法大概是這樣,先執行 git bisect start
進入 bisect 模式,這時候再下 git status 可以發現已經進入 bisect 模式了,執行 git bisect reset
可以取消退出。
$ git bisect start
$ git statusOn branch master
Your branch is up to date with 'origin/master'.You are currently bisecting, started from branch 'master'.
(use "git bisect reset" to get back to the original branch)nothing to commit, working tree clean
Ok,我的 HEAD 現在是在 d6b143d add file multply.js
,是爛的,所以我執行 git bisect bad
告訴 git 我當前的 commit 是爛的,請當做是執行 bisect 的開頭。( git bisect bad 後面沒有分支名稱或 hash,就表示使用當前所在的 commit )
然後我確定 commit fa38f8d add file add.js
是好的,所以可以當作 bisect 搜尋的結尾。執行 git bisect good fa38f8d
$ git bisect good e6910a1513e673e70deee47526793307f46e02abBisecting: 4 revisions left to test after this (roughly 2 steps)
[c56f1ef0689081bf621e69e74fcc1bb0e53668e4] docs: add comments for function add params
然後繼續執行 git bisect good
或 git bisect bad
直到找出錯的 commit 為止 ( 畫面會出現 {hash} is the first bad commit
)
$ git bisect good
02acafda466e88fa95a04b7a712b1d50869d9f59 is the first bad commitcommit 02acafda466e88fa95a04b7a712b1d50869d9f59
Author: kmsheng <kmsh3ng@gmail.com>
Date: Sun Mar 31 18:56:16 2019 +0800feat: This is the commit that breaks add function.:100644 100644 047e14165724dba2831d6b68d8dacaf2e43d5e20 6ef896f4d49969a37f90d735b2ac8b035af479c1 M add.js
git 在 bisect 模式可以允許你跳過不需要檢查的 commit,例如我有很多 commit 是排版或是改文件的,可以執行 git bisect skip {hash}
來跳過這些 commit。
有的時候我們不是要檢查程式是否有 bug,而是程式的行為是否有改變,這個時候用 good 或 bad 來形容就怪怪的,所以 git 也允許你使用 old 與 new。
例如 git bisect old
或 git bisect new
,或者,你也可以定義自己想要的關鍵字。
git bisect start --term-old fast --term-new slow
定義完忘記,還可以執行 git bisect terms
來看看目前定義的關鍵字是什麼
$ git bisect terms
Your current terms are fast for the old state
and slow for the new state.
git bisect
支援印出 log,使用的指令是 git bisect log
。
例如:
$ git bisect log
git bisect start
# bad: [41d0e0c26061f24b085cba44372d770fe47efd9e] docs: add references to README.md
git bisect bad 41d0e0c26061f24b085cba44372d770fe47efd9e
# good: [e6910a1513e673e70deee47526793307f46e02ab] add file add.js
git bisect good e6910a1513e673e70deee47526793307f46e02ab
可以把存到一個檔案,再利用 git bisect replay
重新回到修改後的 bisect 狀態。如果之前有選錯 good 或 bad,也可以修改 log 上面的 good 或 bad 修正。
$ git bisect log > bisect.log
透過 git bisect replay
指令還原 bisect 的狀態:
$ git bisect replay bisect.log
Previous HEAD position was 0c2623b docs: add comments for function add
Switched to branch 'master'
Your branch is up to date with 'origin/master'.
Bisecting: 4 revisions left to test after this (roughly 2 steps)
[0c2623b6ac03eb34a74825dad4399e296f030691] docs: add comments for function add
除了可以手動執行 node check.js
檢查之外,也可以使用 git bisect run
搭配程式路徑自動檢查 commit 是不是好的。
Exit code 為 0 時視為程式正常、125 時執行 git bisect skip
、1 ~ 127 視為程式爛掉。
$ git bisect start
$ git bisect bad d6b143d
$ git bisect good e6910a1
$ git bisect run bash -c 'node ./check.js'
References: