私はそれ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 ... >
この単純な状況では、我々は唯一のテストに3つのバージョンを持っていた(3
、4
、5
)の代わりに、4( 、1
、2
、)。3
4
これは小さな勝利ですが、これは私たちの歴史が非常に小さいためです。検索範囲がNコミットである場合、git bisect
線形検索で約N / 2コミットではなく、1 + log2 Nコミットをテストする必要があります。
回帰を引き起こしたコミットを見つけたら、それを調べて問題を見つけることができます。これが完了したら、を使用git bisect reset
して、git bisect
コマンドを使用する前にすべてを元の状態に戻します。
git bisect bad <rev> [<rev>...]
して、特定のリビジョンを不良(またはで良好git bisect good <rev> [<rev>...]
)としてマークできます。rev
ブランチ名、タグ、コミットハッシュ(またはコミットハッシュの一意のプレフィックス)などのリビジョン識別子を指定できます...
git bisect reset
して最近のコミットにすべてを戻します
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
終了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でテスト済み。
test_script
+モジュール式テストスイートに必要なテストボイラープレートを含め、2分割するときに別のファイルから実行します。修正したら、テストをメインのテストスイートにマージします。
bisect run
テストが終了するのに長い時間がかかる場合、特別に便利な、と私はかなり確信してテストシステムが壊れていないということです。このように、私はそれをバックグラウンドで実行したままにするか、リソースが多すぎる場合は一晩、脳のコンテキスト切り替え時間を失うことなく実行できます。
$ 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
git bisect good
次のコミットに移動します。
さらにポイントを追加するだけです:
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(バイナリ検索)が中央の要素を選択するのに役立ちます(commit v1.3)。コミットv1.3でリグレッションがある場合、それを新しい「悪い」ポイントとして設定します(つまり、良い-> v1.0と悪い-> v1.3)。
$ git bisect bad
または同様に、コミットv1.3にバグがない場合は、それを新しい「良い点」として設定します(* Good-> v1.3およびBad-> v1.6)。
$ git bisect good
注:用語good
とbad
あなたがまたは特定のプロパティなしでコミットをマークするために使用することができるだけではありません。
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