546

git bisect私はそれが素晴らしいと言っているいくつかの記事を読みました。しかし、私はネイティブ スピーカーではないので、なぜそれが素晴らしいのか理解できません。

誰かがいくつかのコードサンプルで実演してくれませんか:

  1. それの使い方?
  2. のようsvn blameですか?
4

6 に答える 6

762

背後にある考え方git bisectは、履歴でバイナリ検索を実行して特定の回帰を見つけることです。次の開発履歴があるとします。

... --- 0 --- 1 --- 2 --- 3 --- 4* --- 5 --- current

プログラムがリビジョンで正しく動作していないことcurrent、およびリビジョンで動作していたことがわかります0。したがって、リグレッションはコミットの 1 つで導入された可能性があります1, 2, 3, 4, .5current

各コミットをチェックアウトしてビルドし、回帰が存在するかどうかを確認できます。コミット数が多い場合、これには長い時間がかかることがあります。これは線形検索です。二分探索を行うことで、より良い結果が得られます。これが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 badgit 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 個のコミットをテストすることを期待する必要があります。451234git bisect

リグレッションを引き起こしたコミットを見つけたら、それを調べて問題を見つけることができます。これが完了したら、コマンドgit bisect resetを使用する前にすべてを元の状態に戻すために使用しますgit bisect

于 2011-01-17T14:32:20.930 に答える
199

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*

これにより、どのコミットが良いまたは悪いとマークされたかがわかります。

コマンドを試してみたい場合は、このテスト リポジトリを検討してください。

失敗は早い、成功は遅い

時々:

  • 失敗はすぐに起こります。たとえば、最初のテストの 1 つが壊れます。
  • 成功にはしばらく時間がかかります。たとえば、壊れたテストがパスし、気にしない他のすべてのテストが続きます。

これらのケースでは、たとえば、失敗が常に 5 秒以内に発生すると仮定し、実際に必要なテストをより具体的にするのが面倒な場合は、次のように使用できますtimeout

#!/usr/bin/env bash
timeout 5 test-command
if [ $? -eq 1 ]; then
  exit 1
fi

これは、timeoutexit124の失敗時にtest-commandexitが発生するため機能します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 でテスト済み。

于 2014-03-23T15:04:58.577 に答える
153

TL;DR

始める:

$ 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
于 2016-05-18T17:36:52.870 に答える
46

さらにポイントを追加するだけです:

git bisect startバグが特定のファイルから発生したことがわかっている場合は、ファイル名またはパスを指定でき ます。たとえば、リグレッションの原因となった変更が com/workingDir ディレクトリにあることがわかっていると仮定すると、実行できますgit bisect start com/workingDir。これは、このディレクトリの内容を変更したコミットのみがチェックされることを意味し、これにより処理がさらに高速になります。

また、特定のコミットが良いか悪いかを判断するのが難しい場合は、 を実行git bisect skipすると無視されます。他のコミットが十分にある場合、git bisect は代わりに別のコミットを使用して検索を絞り込みます。

于 2014-09-12T06:12:40.960 に答える
16

$ 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
于 2013-06-27T14:37:52.437 に答える