git bisect
私はそれが素晴らしいと言っているいくつかの記事を読みました。しかし、私はネイティブ スピーカーではないので、なぜそれが素晴らしいのか理解できません。
誰かがいくつかのコードサンプルで実演してくれませんか:
- それの使い方?
- のよう
svn blame
ですか?
git bisect
私はそれが素晴らしいと言っているいくつかの記事を読みました。しかし、私はネイティブ スピーカーではないので、なぜそれが素晴らしいのか理解できません。
誰かがいくつかのコードサンプルで実演してくれませんか:
svn blame
ですか?背後にある考え方git bisect
は、履歴でバイナリ検索を実行して特定の回帰を見つけることです。次の開発履歴があるとします。
... --- 0 --- 1 --- 2 --- 3 --- 4* --- 5 --- current
プログラムがリビジョンで正しく動作していないことcurrent
、およびリビジョンで動作していたことがわかります0
。したがって、リグレッションはコミットの 1 つで導入された可能性があります1
, 2
, 3
, 4
, .5
current
各コミットをチェックアウトしてビルドし、回帰が存在するかどうかを確認できます。コミット数が多い場合、これには長い時間がかかることがあります。これは線形検索です。二分探索を行うことで、より良い結果が得られます。これがgit bisect
コマンドの動作です。各ステップで、潜在的に悪いリビジョンの数を半分に減らそうとします。
次のようにコマンドを使用します。
$ git stash save
$ git bisect start
$ git bisect bad
$ git bisect good 0
Bisecting: 2 revisions left to test after this (roughly 2 steps)
[< ... sha ... >] 3
このコマンドの後git
、コミットをチェックアウトします。私たちの場合、それは commit になります3
。プログラムをビルドし、回帰が存在するかどうかを確認する必要があります。また、リグレッションが存在git
するかどうかで、このリビジョンのステータスを伝える必要があります。git bisect bad
git bisect good
commit で回帰が導入されたとしましょう4
。その後、回帰はこのリビジョンには存在せず、それを に通知しgit
ます。
$ make
$ make test
... ... ...
$ git bisect good
Bisecting: 0 revisions left to test after this (roughly 1 step)
[< ... sha ... >] 5
その後、別のコミットをチェックアウトします。4
または(コミット5
が 2 つしかないため)。を選んだとしましょう5
。ビルド後、プログラムをテストし、リグレッションが存在することを確認します。次に、次のように伝えますgit
。
$ make
$ make test
... ... ...
$ git bisect bad
Bisecting: 0 revisions left to test after this (roughly 0 steps)
[< ... sha ... >] 4
最後のリビジョンをテストし4
ます。そして、それが回帰を導入したものであるため、次のように伝えますgit
。
$ make
$ make test
... ... ...
$ git bisect bad
< ... sha ... > is the first bad commit
< ... commit message ... >
この単純な状況では、4 つのバージョン ( 、 、 、 ) ではなく 3 つのバージョン ( 、 、 ) をテストするだけで済み3
ました。これは小さな勝利ですが、これは私たちの歴史が非常に小さいためです。検索範囲が N 個のコミットの場合、線形検索でおおよそ N / 2個のコミットをテストする代わりに、1 + log2 N 個のコミットをテストすることを期待する必要があります。4
5
1
2
3
4
git bisect
リグレッションを引き起こしたコミットを見つけたら、それを調べて問題を見つけることができます。これが完了したら、コマンドgit bisect reset
を使用する前にすべてを元の状態に戻すために使用しますgit bisect
。
git bisect run
自動二分./test
テストが OK の場合に終了ステータスが 0の自動化されたスクリプトがある場合は、次のコマンドを使用してバグを自動的に見つけることができbisect run
ます。
git checkout KNOWN_BAD_COMMIT
git bisect start
# Confirm that our test script is correct, and fails on the bad commit.
./test
# Should output != 0.
echo $?
# Tell Git that the current commit is bad.
git bisect bad
# Same for a known good commit in the past.
git checkout KNOWN_GOOD_COMMIT
./test
# Should output 0.
echo $?
# After this, git automatically checks out to the commit
# in the middle of KNOWN_BAD_COMMIT and KNOWN_GOOD_COMMIT.
git bisect good
# Bisect automatically all the way to the first bad or last good rev.
git bisect run ./test
# End the bisect operation and checkout to master again.
git bisect reset
もちろん、これは、テスト スクリプト./test
が git で追跡されている場合、二分中の以前のコミットで消えないことを前提としています。
ツリー内のスクリプトをツリーの外にコピーし、おそらく - のPATH
ような変数で遊んで、代わりにそこから実行するだけで、問題を解決できることが非常に多いことがわかりました。
もちろん、test
依存するテスト インフラストラクチャが古いコミットで壊れる場合、解決策はなく、コミットを 1 つずつテストする方法を手動で決定する必要があります。
しかし、この自動化を使用すると、多くの場合うまくいくことがわかりました。タスクのバックログに横たわっている遅いテストでは、一晩実行して翌朝までにバグを特定できる可能性があるため、時間を大幅に節約できます。価値があります。試してください。
bisect に戻るのではなく、最初に失敗したコミットにとどまりますmaster
。
git bisect reset HEAD
start
+ 初期bad
およびgood
一度に:
git bisect start KNOWN_BAD_COMMIT KNOWN_GOOD_COMMIT~
以下と同じです:
git checkout KNOWN_BAD_COMMIT
git bisect start
git bisect bad
git bisect good KNOWN_GOOD_COMMIT
これまでにテストされたものを参照してください (マニュアルgood
およびbad
またはによってrun
):
git bisect log
出力例:
git bisect log
git bisect start
# bad: [00b9fcdbe7e7d2579f212b51342f4d605e53253d] 9
git bisect bad 00b9fcdbe7e7d2579f212b51342f4d605e53253d
# good: [db7ec3d602db2d994fe981c0da55b7b85ca62566] 0
git bisect good db7ec3d602db2d994fe981c0da55b7b85ca62566
# good: [2461cd8ce8d3d1367ddb036c8f715c7b896397a5] 4
git bisect good 2461cd8ce8d3d1367ddb036c8f715c7b896397a5
# good: [8fbab5a3b44fd469a2da3830dac5c4c1358a87a0] 6
git bisect good 8fbab5a3b44fd469a2da3830dac5c4c1358a87a0
# bad: [dd2c05e71c246f9bcbd2fbe81deabf826c54be23] 8
git bisect bad dd2c05e71c246f9bcbd2fbe81deabf826c54be23
# bad: [c536b1b7242d5fcf92cd87e9a534bedb1c0c9c05] 7
git bisect bad c536b1b7242d5fcf92cd87e9a534bedb1c0c9c05
# first bad commit: [c536b1b7242d5fcf92cd87e9a534bedb1c0c9c0
時間のより良い概念を得るために、git ログに良い参照と悪い参照を表示します。
git log --decorate --pretty=fuller --simplify-by-decoration master
これは、対応する参照を持つコミットのみを表示します。これにより、ノイズが大幅に削減されますが、次のタイプの自動生成された参照が含まれます。
refs/bisect/good*
refs/bisect/bad*
これにより、どのコミットが良いまたは悪いとマークされたかがわかります。
コマンドを試してみたい場合は、このテスト リポジトリを検討してください。
時々:
これらのケースでは、たとえば、失敗が常に 5 秒以内に発生すると仮定し、実際に必要なテストをより具体的にするのが面倒な場合は、次のように使用できますtimeout
。
#!/usr/bin/env bash
timeout 5 test-command
if [ $? -eq 1 ]; then
exit 1
fi
これは、timeout
exit124
の失敗時にtest-command
exitが発生するため機能します1
。
git bisect run
終了ステータスについては少しうるさいです:
127 を超えると、二分法は次のように失敗します。
git bisect run failed:
exit code 134 from '../test -aa' is < 0 or >= 128
特に、Cassert(0)
は a につながりSIGABRT
、ステータス 134 で終了し、非常に迷惑です。
125 はマジックで、ランを でスキップしgit bisect skip
ます。
これは、無関係な理由で壊れたビルドをスキップできるようにすることを目的としています。
詳しくman git-bisect
は をご覧ください。
したがって、次のようなものを使用することをお勧めします。
#!/usr/bin/env bash
set -eu
./build
status=0
./actual-test-command || status=$?
if [ "$status" -eq 125 ] || [ "$status" -gt 127 ]; then
status=1
fi
exit "$status"
git 2.16.1 でテスト済み。
$ git bisect start
$ git bisect bad
$ git bisect good <goodcommit>
または
$ git bisect start
$ git bisect good
$ git bisect bad <badcommit>
Bisecting: X revisions left to test after this (roughly Y steps)
問題はまだ存在しますか?
$ git bisect bad
$ git bisect good
<abcdef> is the first bad commit
git bisect reset
さらにポイントを追加するだけです:
git bisect start
バグが特定のファイルから発生したことがわかっている場合は、ファイル名またはパスを指定でき ます。たとえば、リグレッションの原因となった変更が com/workingDir ディレクトリにあることがわかっていると仮定すると、実行できますgit bisect start com/workingDir
。これは、このディレクトリの内容を変更したコミットのみがチェックされることを意味し、これにより処理がさらに高速になります。
また、特定のコミットが良いか悪いかを判断するのが難しい場合は、 を実行git bisect skip
すると無視されます。他のコミットが十分にある場合、git bisect は代わりに別のコミットを使用して検索を絞り込みます。
$ git bisect ..
基本的にデバッグ用の Git ツールです。'Git Bisect'は、最後の (既知の) 作業コミット以降の以前のコミットを調べることによってデバッグします。バイナリ検索を使用して、これらすべてのコミットを調べ、回帰/バグを導入したものに到達します。
$ git bisect start
# 二分開始
$ git bisect bad
# 現在のコミット (v1.5) に回帰/設定の「悪い」ポイントがあることを示す
$ git bisect good v1.0
# 正常に機能する最後のコミット (リグレッションなし) について言及する
この「悪い」点と「良い」点の言及は、git bisect (バイナリ検索) が中間要素を選択するのに役立ちます (コミット v1.3)。コミット v1.3 でリグレッションが存在する場合は、それを新しい「悪い」ポイントとして設定します ( Good -> v1.0 および Bad -> v1.3 ) 。
$ git bisect bad
または同様に、コミット v1.3 にバグがない場合、それを新しい「良い点」として設定します (*良い -> v1.3 および悪い -> v1.6)。
$ git bisect good