TT Lab
Get started
Learn Learning paths Courses

Git in Practice

Finding the Culprit Among 40 Commits

Continue in TT Lab

Goal

You pin down a single commit from "it used to work". And you meet the place where automation ends for yourself.

Environment

There is an empty repository at /root/repo. You create the history yourself — paste in the block below as it is. This part is not an assignment but preparation.

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 is supposed to output 100. Right now it outputs 250. And somewhere in the middle there is one commit whose syntax is broken so it cannot even run.

What to build

/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    정리

There is a reason to put the judging script outside the repository. If you put it inside the repository, that script changes along with everything else when bisect moves between commits.

Steps

  1. Create the history and the reference tag.
  2. Write /root/check.sh. You must distinguish exactly three kinds of exit code.
  3. git bisect start HEAD v1, then git bisect run sh /root/check.sh. Copy the result as it is into bisect.txt. It does not narrow down to one.
  4. Run the same bisection again with a wrong-check.sh that leaves out 125. This time it gives an answer with confidence — and that answer is wrong. Write the two side by side.
  5. Check with git show which of the two candidates is the culprit, and also write down why you ruled out the other.
  6. Produce the same answer in one go with git log -S.
  7. On app/settings.ini, run git blame and git blame -w respectively.
  8. Summarize when to use the four tools.

Notes

If The first bad commit could be any of: appears on screen in step 3, you have arrived correctly. It is not a failure but an honest answer — if a commit that could not be judged remains, bisect can only tell you up to that point. Comparing it with step 4, it becomes clear that this is better than giving a wrong answer with confidence.

Create the history and the reference point

Create the history and the reference tag.

Run the preparation block from the instructions as it is. The v1 tag is the reference point meaning 'it worked at this time', and bisection can start only when there is one good and one bad.

A judging script that speaks through exit codes

Write /root/check.sh. You must distinguish exactly three kinds of exit code.

0 is good, 1–124 is bad, and 125 is cannot-judge (skip). If you fold a commit that cannot even run into bad, bisection converges on the wrong place. First check only the syntax with sh -n.

How far does bisection narrow it

git bisect start HEAD v1, then git bisect run sh /root/check.sh. Copy the result as it is into bisect.txt. It does not narrow down to one.

Start with git bisect start HEAD v1 and run git bisect run sh /root/check.sh. When it finishes, be sure to clean up with git bisect reset. Do not summarize the result; copy it as it appeared on screen.

What happens if you leave out 125

Run the same bisection again with a wrong-check.sh that leaves out 125. This time it gives an answer with confidence — and that answer is wrong. Write the two side by side.

Make a separate script that returns 1 (bad) even for cannot-judge, and run the same bisection again. This time it points at one commit with confidence, but that answer is wrong. Write the two results side by side.

The last step is decided by a person

Check with git show which of the two candidates is the culprit, and also write down why you ruled out the other.

If there are two candidates, use git show <해시>:app/calc.sh to see what each contains. You must also write the grounds for the one you ruled out, so that the next person does not check it again.

A shortcut when you know what you are looking for

Produce the same answer in one go with git log -S.

git log -S <문자열> outputs only the commits in which that string was added or deleted. You do not have to run bisection six times; it comes out in one go — but you can use it only if you already know what to look for.

Past the formatter commit to the commit that set the value

On app/settings.ini, run git blame and git blame -w respectively.

Run git blame app/settings.ini and git blame -w app/settings.ini respectively. The former points at the commit that only changed the indentation, and -w skips it. Write the two hashes side by side.

When to use what first

Summarize when to use the four tools.

The three tools answer different questions. And also write down what you experienced yourself this time — where automation ends.