TT Lab
はじめる
学ぶ 学習パス コース

Git実戦

40のコミットから犯人を見つける

TT Labで続きを見る

目標

「前は動いていたのですが」から、コミットを1つ特定します。そして、自動化が終わる場所に、自分で出会います。

環境

/root/repoに、空のリポジトリが1つあります。履歴は自分で作ります。下のコードをそのまま貼り付けてください。この部分は課題ではなく、準備です。

cd /root/repo && mkdir -p app
i=1
while [ "$i" -le 40 ]; do
  if [ "$i" -eq 22 ]; then printf '#!/bin/sh
echo $(( 100 +
' > app/calc.sh
  elif [ "$i" -lt 23 ]; then printf '#!/bin/sh
echo 100
' > app/calc.sh
  else printf '#!/bin/sh
echo 250
' > app/calc.sh; fi
  echo "note $i" > app/notes.txt
  git add -A && git commit -qm "change $i"
  i=$((i + 1))
done
printf 'timeout=3
retries=2
' > app/settings.ini
git add -A && git commit -qm "설정값 도입"
printf '  timeout=3
  retries=2
' > app/settings.ini
git add -A && git commit -qm "포매터 실행"
git tag -f v1 "$(git rev-list --reverse HEAD | sed -n '2p')"
mkdir -p /root/arch

app/calc.shは、本来100を出力する必要があります。今は250を出力します。そして、途中のどこかに、文法が壊れていて実行すらできないコミットが1つあります。

作るもの

/root/check.sh          판정 스크립트 — 종료코드로 good/bad/skip 을 말한다
/root/wrong-check.sh    125 를 일부러 뺀 것 (4단계에서 비교용)
/root/arch/bisect.txt   bisect run 의 결과
/root/arch/wrong.txt    125 를 뺐을 때의 결과
/root/arch/culprit.txt  범인과 배제 근거
/root/arch/pickaxe.txt  log -S 로 찾은 결과
/root/arch/blame.txt    blame 과 blame -w 의 차이
/root/arch/report.md    정리

判定スクリプトをリポジトリの外に置くのには、理由があります。リポジトリの中に置くと、bisectがコミットを移動して回るときに、そのスクリプトまで一緒に変わってしまいます。

ステップ

  1. 履歴と基準タグを作ります。
  2. /root/check.shを書きます。3種類の終了コードを、正確に区別する必要があります。
  3. git bisect start HEAD v1のあとに、git bisect run sh /root/check.shを実行します。結果をそのままbisect.txtに書き写します。1つには絞り込めません。
  4. 125を抜いたwrong-check.shで、同じ二分探索をもう一度実行します。今度は、自信を持って答えを出します。そして、その答えは間違っています。2つを並べて書いてください。
  5. 2つの候補のうち、どちらが犯人かをgit showで確認し、もう一方をなぜ除外したかまで書きます。
  6. git log -Sで、同じ答えを一度で出します。
  7. app/settings.iniに、git blameとgit blame -wを、それぞれ実行してみます。
  8. 4つのツールをいつ使うかを、まとめます。

参考

ステップ3で、画面にThe first bad commit could be any of:が表示されれば、正しく進んでいます。失敗ではなく、正直な答えです。判定できなかったコミットが残っていると、bisectはそこまでしか言えません。ステップ4と比べてみると、間違った答えを自信を持って出すより、こちらのほうがよいことが、はっきりします。

履歴と基準点を作る

履歴と基準タグを作ります。

指示文の準備ブロックをそのまま実行します。v1タグは「このときは動いていた」という基準点で、二分探索は、goodとbadが1つずつないと始められません。

終了コードで語る判定スクリプト

/root/check.shを書きます。3種類の終了コードを、正確に区別する必要があります。

0はgood、1–124はbad、125は判定不能(skip)です。実行すらできないコミットをbadとして扱うと、二分探索が見当違いの場所に収束します。sh -nで、まず文法だけを確認します。

二分探索を実行すると、どこまで絞り込めるか

git bisect start HEAD v1のあとに、git bisect run sh /root/check.shを実行します。 結果をそのままbisect.txtに書き写します。1つには絞り込めません。

git bisect start HEAD v1で開始し、git bisect run sh /root/check.shを実行します。終わったら、必ずgit bisect resetで後始末をしてください。結果を要約せず、画面に表示されたとおりに書き写してください。

125を抜くと何が起きるか

125を抜いたwrong-check.shで、同じ二分探索をもう一度実行します。今度は、自信を持って答えを出します。そして、その答えは間違っています。2つを並べて書いてください。

判定不能なときにも1(bad)を返すスクリプトを別に作り、同じ二分探索をもう一度実行します。今度は、1つを自信を持って指名しますが、その答えは間違っています。2つの結果を並べて書いてください。

最後の一歩は人が決める

2つの候補のうち、どちらが犯人かをgit showで確認し、もう一方をなぜ除外したかまで書きます。

候補が2つなら、git show <해시>:app/calc.shで、それぞれに何が入っているかを見ます(プレースホルダーはハッシュです)。除外したほうの根拠まで書いておかないと、次の人がもう一度確認することになります。

何を探すかがわかっているときの近道

git log -Sで、同じ答えを一度で出します。

git log -S <문자열>は、その文字列が追加または削除されたコミットだけを出力します(プレースホルダーは文字列です)。二分探索を6回回す必要はなく、一度で出ます。ただし、何を探すかをすでに知っていないと使えません。

フォーマッターのコミットを飛び越えて、値を決めたコミットへ

app/settings.iniに、git blameとgit blame -wを、それぞれ実行してみます。

git blame app/settings.iniとgit blame -w app/settings.iniを、それぞれ実行してみてください。前者はインデントだけを変えたコミットを指し、-wはそれを飛ばします。2つのハッシュを並べて書いてください。

いつ何を先に使うか

4つのツールをいつ使うかを、まとめます。

3つのツールが答える問いが、それぞれ違います。そして、今回自分で体験したこと、つまり自動化がどこで終わるかも、一緒に書いてください。