CSVの集計を直したあとに合計が合わなくなり、どの変更から変わったか分からない。正常だったコミットと不具合のあるコミットが分かるなら、Gitのbisectで履歴を絞り込めます。履歴の途中のコミットを選び、同じ条件で正常か異常かを判定します。
試験中は過去のコードへ切り替わるため、作業中の変更がある場所では始めません。ここでは新しい練習用フォルダーを作り、架空の集計関数だけで流れを確かめます。既存リポジトリの変更や外部への送信は行いません。
合計300を判定条件にする
calc.pyのtotalへ100と200を渡したとき、300を返せば正常という条件です。判定するcheck_total.pyは次の内容にします。終了コード0が正常、1が異常です。
from pathlib import Path
import runpy
calc = Path(__file__).resolve().parent / "calc.py"
total = runpy.run_path(str(calc))["total"]
raise SystemExit(0 if total([100, 200]) == 300 else 1)
runpy.run_pathはそのファイルのコードを実行するので、内容を確認した練習用コードだけを対象にします。信頼できない過去のコードを、認証情報がある環境で動かす手順にはしません。
練習用の履歴を三つ作る
WindowsのPowerShellで、次のように練習場所を作れます。一時フォルダーの下へ毎回違う名前を作るため、既存のファイルは上書きしません。先ほどのcheck_total.pyを、この新しい場所へ保存してから初回コミットを作ります。
$practiceDir = Join-Path ([IO.Path]::GetTempPath()) ('bisect-' + [guid]::NewGuid())
New-Item -ItemType Directory -Path $practiceDir -ErrorAction Stop | Out-Null
Set-Location -LiteralPath $practiceDir
git init --initial-branch=main
git config user.name 'Practice'
git config user.email 'practice@example.invalid'
Set-Content -LiteralPath 'calc.py' -Encoding utf8 -Value 'def total(values): return sum(values)'
# check_total.pyを、このフォルダーへ保存してから続けます。
git add calc.py check_total.py
git commit -m 'normal total'
Set-Content -LiteralPath 'calc.py' -Encoding utf8 -Value 'def total(values): return sum(values) + 1'
git add calc.py
git commit -m 'change total calculation'
Set-Content -LiteralPath 'README.txt' -Encoding utf8 -Value 'practice only'
git add README.txt
git commit -m 'add practice note'
2番目の変更で結果が301となり、3番目では説明だけを追加しています。個々のGitコマンドでエラーが出た場合は、そこで止めて状態を確認してください。後続のコマンドまで正常に終わったとみなさないようにします。
同じ試験で途中の履歴を判定する
練習用の履歴が三つできたら、直近のコミットを異常、二つ前を正常として指定します。Pythonが起動できる環境で実行してください。
git bisect start HEAD HEAD~2
git bisect run python check_total.py
git bisect reset
期待する結果は、change total calculationという説明のコミットが最初の異常として示されることです。出力に現れるハッシュはその場で作った履歴によって変わります。最後のgit bisect resetで、試験前のブランチへ戻ります。調査が止まった場合も、現在の状態を確認してから終了してください。
判定できない状態を異常と混ぜない
git bisect runは、判定コマンドの終了コードを使います。正常を0、異常を1〜127のうち125以外で表し、125は試験できないコミットを飛ばす用途です。環境が起動できなかっただけなのに、集計の不具合と同じ結果で判定していないかをログで確認します。
この例で確認できるのは、固定入力の合計が変わった変更です。金額の丸め、欠損、別の入力、外部APIの変化まで正しいとは言えません。実際の集計では困っている入力を個人情報のない小さな例へし、正常・異常の判断を同じ条件で繰り返せるようにします。
関連する記事
GitでPythonスクリプトを管理する基本|戻せる作業環境を作る
Pythonスクリプトを配布する前に見ること|設定ファイルとREADME
