git bisectの使い方


438

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

誰かがいくつかのコードサンプルで実証してください:

  1. それの使い方?
  2. まるでsvn blame

@ 01:git bookが言うように:プロジェクトの履歴を通じてブルートフォース検索を実行します。
eckes

7
/// brute :-)ではないので、バイナリ検索を使用します。
cojocar 2011年

「git blame」は「svn blame」に似ています。「git bisect」はまったく別のものです
ウィリアムパーセル

価値があることについては、Pro Gitのbisectについての適切な説明もあります。シルヴァンの答えは、もう一つの良いショットです。すべてを確認してもまだ理解できない場合は、より具体的な質問をすることをお勧めします。一般的な質問は一般的な答えを生みます。
Cascabel

回答:


655

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

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

プログラムがcurrentリビジョンで正しく動作していないこと、およびプログラムがリビジョンで動作していたことがわかります0。だから、回帰がそうコミットの1に導入されました12345current

各コミットをチェックアウトしてビルドし、リグレッションが存在するかどうかを確認することができます。多数のコミットがある場合、これには長い時間がかかる可能性があります。これは線形検索です。バイナリ検索を行うことで、より良い結果が得られます。これは、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 ... >

この単純な状況では、我々は唯一のテストに3つのバージョンを持っていた(345)の代わりに、4( 、12、)。3 4これは小さな勝利ですが、これは私たちの歴史が非常に小さいためです。検索範囲がNコミットである場合、git bisect線形検索で約N / 2コミットではなく、1 + log2 Nコミットをテストする必要があります。

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


5
ここではこれとは対照的です。これはbisectの良い説明ですが、実際に使用するのに役立ちません。特に、良いコミットを見つけることができ、今はそのブランチにいます。この立場から、この説明はまったく役に立ちません。たとえば、チェックアウトせずに不良ブランチを指定する方法
PandaWood

4
を使用git bisect bad <rev> [<rev>...]して、特定のリビジョンを不良(またはで良好git bisect good <rev> [<rev>...])としてマークできます。revブランチ名、タグ、コミットハッシュ(またはコミットハッシュの一意のプレフィックス)などのリビジョン識別子を指定できます...
Sylvain Defresne

39
...そして完了したら、タイプgit bisect resetして最近のコミットにすべてを戻します
peetonn

17
スタック上で最も素晴らしい答えの1つ。非常によく連結されています。私はこのプロセスを何年も手動で行ってきました。ちょうど良いコミットと悪いコミットの間の任意の中間点を選び、次にそれが良いか悪いかに応じて、そのコミットと良い/悪いコミットの間でもう一度選びます。それはいつもお尻の痛みで、今日までこのgitサブコマンドについて聞いたこともありませんでした... haha​​ha
Chev

3
@Nemoden、そうです。基本的に、あらゆるタイプのプロジェクトに役立ちます。「テストを実行する」ステップを「Webサイトをデプロイして問題を再現する」に置き換えるだけです
alex.b

158

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+最初badgood、一度に:

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

これは、timeout終了124時にエラーが発生するので終了しtest-commandます1

魔法の終了ステータス

git bisect run 終了ステータスについて少しうるさいです:

  • 127を超えると、2等分が失敗します。

    git bisect run failed:
    exit code 134 from '../test -aa' is < 0 or >= 128
    

    特に、C assert(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でテスト済み。


7
gitは、以前の/悪いリビジョン(新しく作成したテストがなかったもの)に戻す/二分するときに、新しいテストが消えないようにする方法を知っていますか?
thebjorn 14

8
@thebjornあなたはポイントを持っています:私の知る限り、テストはPATHの外部実行可能ファイル、またはリポジトリ内の追跡されていないファイルでなければなりません。多くの場合、これは可能です。テストを別のファイルに入れ、巧妙に作成されたtest_script+モジュール式テストスイートに必要なテストボイラープレートを含め、2分割するときに別のファイルから実行します。修正したら、テストをメインのテストスイートにマージします。
Ciro Santilli郝海东冠状病六四事件法轮功

1
@CiroSantilli六四事件法轮功纳米比亚威视申し訳ありませんが、以下の編集を元に戻しました。初心者にはわかりやすく、回答にさらにポイントを追加しているだけです(正確な回答ではありません。そのため、ポイントを追加するには)
Nicks

1
「git bisect run」で問題が発生する方法はたくさんあります。たとえば、適切なコミットが悪いマージによってどのように取り消されたかを確認します。それは出入りし、再び出入りし、最後の「出」だけが悪い。ただし、いつでも手動で「git bisect」を実行できます。それは二等分なので、数ステップしかかかりません-例えば、10ステップで1024回のコミット。
コンビ

1
@combinatorist正解です。失敗する可能性があります。私が見つけbisect runテストが終了するのに長い時間がかかる場合、特別に便利な、と私はかなり確信してテストシステムが壊れていないということです。このように、私はそれをバックグラウンドで実行したままにするか、リソースが多すぎる場合は一晩、脳のコンテキスト切り替え時間を失うことなく実行できます。
Ciro Santilli郝海东冠状病六四事件法轮功

124

TL; DR

開始:

$ git bisect start
$ git bisect bad
$ git bisect good <goodcommit>

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

3
gitリポジトリのルートにいることを確認してください。そうしないと、「作業ツリーのトップレベルからこのコマンドを実行する必要があります」という奇妙なメッセージが表示されます。エラー。
PRホワイトヘッド

したがって、エラーが存在しなかったときに、最初のコミットでgit badを最初のコミットでgit goodにしました。それでは次に何をすべきか?バグが存在しない場合、git bisectは次のコミットに移動するのに適していますか?
Gobliins、2018

@Gobliinsバグが存在しない場合は、修正して、git bisect good次のコミットに移動します。
ジェフリーヘイル

40

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

git bisect startバグが特定のファイルに起因していることがわかっている場合は、ファイル名またはパスを指定できます 。たとえば、リグレッションの原因となった変更がcom / workingDirディレクトリにあることがわかっているとしたら、次のコマンドを実行できます。git bisect start com/workingDirつまり、このディレクトリのコンテンツを変更したコミットのみがチェックされ、これにより状況がさらに速くなります。

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


15

$ git bisect ..基本的にデバッグ用のGitツール。'Git Bisect' は、最後の(既知の)作業コミット以降の以前のコミットを経由してデバッグします。バイナリ検索を使用してこれらすべてのコミットを実行し、回帰/バグを導入したコミットに到達します。

$ git bisect start #二等分を開始

$ git bisect bad #現在のコミット(v1.5)にはリグレッション/「悪い」ポイントを設定していると述べる

$ git bisect good v1.0 #最後の適切に機能するコミットに言及(リグレッションなし)

この「悪い」および「良い」点について言及すると、git bisect(バイナリ検索)が中央の要素を選択するのに役立ちます(commit v1.3)。コミットv1.3でリグレッションがある場合、それを新しい「悪い」ポイントとして設定します(つまり、良い-> v1.0と悪い-> v1.3)。

$ git bisect bad

または同様に、コミットv1.3にバグがない場合は、それを新しい「良い点」として設定します(* Good-> v1.3およびBad-> v1.6)。

$ git bisect good

2

注:用語goodbadあなたがまたは特定のプロパティなしでコミットをマークするために使用することができるだけではありません。

Git 2.7(2015年第4四半期)に新しいgit bisectオプションが導入されました。

 git bisect start [--term-{old,good}=<term> --term-{new,bad}=<term>]
                  [--no-checkout] [<bad> [<good>...]] [--] [<paths>...]

ドキュメントを追加すると:

場合によっては、破損を引き起こしたコミットではなく、他の「古い」状態と「新しい」状態の間に変化を引き起こしたコミットを探していることがあります。

たとえば、特定の修正を導入したコミットを探している場合があります。
または、ソースコードのファイル名が最終的にすべて会社の命名基準に変換された最初のコミットを探しているかもしれません。または何でも。

そのような場合、「変更前の状態」と「変更後の状態」を指すのに「良い」と「悪い」という用語を使用することは非常に混乱する可能性があります。

ので、代わりに、あなたは「用語を使用することができますold」と「new」の代わりに、それぞれ、「good」と「bad」。
(ただし、「good」と「bad」を「old」と「new」と一緒に1つのセッションで混在させることはできません。)

このより一般的な使用法でgit bisectは、 " new"コミットにいくつかのプロパティがあり、 " old"コミットにそのプロパティがありません。

git bisectコミットをチェックアウトするたびに、そのコミットにプロパティがあるかどうかをテストします。プロパティがある
場合は、コミットを " new" としてマークします。それ以外の場合は、「old」とマークします。

二分割が完了git bisectすると、プロパティを導入したコミットが報告されます。


Matthieu Moy(によるコミット06e6a74コミット21b55e3コミットfe67687(2015年6月29日)を参照してください。Antoine Delaite()によるcommit 21e5cfd(2015年6月29日)を 参照してください。(による合併Junio C浜野- -コミット22dd6eb、2015年10月5日)moy
CanardChouChinois
gitster

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.