LabHub
배우기 러닝패스 코스

Git実戦

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

LabHub 에서 이어서 보기

한국어 원문으로 표시합니다.

목표

"예전엔 됐는데요" 에서 커밋 하나를 특정합니다. 그리고 자동화가 끝나는 자리를 직접 만납니다.

환경

/root/repo 에 빈 저장소가 하나 있습니다. 이력은 직접 만듭니다 — 아래를 그대로 붙여 넣으세요. 이 부분은 과제가 아니라 준비입니다.

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 을 냅니다. 그리고 중간 어딘가에 문법이 깨져 실행조차 안 되는 커밋이 하나 있습니다.

만들 것

/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. git bisect start HEAD v1 뒤에 git bisect run sh /root/check.sh. 결과를 그대로 bisect.txt 에 옮깁니다. 하나로 안 좁혀집니다.
  4. 125 를 뺀 wrong-check.sh 로 같은 이등분을 다시 돌립니다. 이번에는 확신 있게 답을 냅니다 — 그리고 그 답은 틀렸습니다. 둘을 나란히 적으세요.
  5. 두 후보 중 어느 쪽이 범인인지 git show 로 확인하고, 다른 쪽을 왜 배제했는지까지 적습니다.
  6. git log -S 로 같은 답을 한 번에 냅니다.
  7. app/settings.inigit blamegit blame -w 를 각각 돌려 봅니다.
  8. 네 도구를 언제 쓰는지 정리합니다.

참고

3단계에서 화면에 The first bad commit could be any of: 가 뜨면 제대로 온 것입니다. 실패가 아니라 정직한 답입니다 — 판정할 수 없었던 커밋이 남아 있으면 bisect 는 거기까지만 말할 수 있습니다. 4단계와 비교해 보면, 틀린 답을 확신 있게 내는 쪽보다 이쪽이 낫다는 것이 분명해집니다.

이력과 기준점 만들기

이력과 기준 태그를 만듭니다.

지시문의 준비 블록을 그대로 돌립니다. v1 태그는 '이때는 됐다' 는 기준점이고, 이등분은 good 하나와 bad 하나가 있어야 시작합니다.

종료코드로 말하는 판정 스크립트

/root/check.sh 를 씁니다. 종료코드 세 가지를 정확히 구분해야 합니다.

0 은 good, 1~124 는 bad, 125 는 판정 불가(skip) 입니다. 실행조차 안 되는 커밋을 bad 로 접으면 이등분이 엉뚱한 곳으로 수렴합니다. sh -n 으로 문법만 먼저 봅니다.

이등분을 돌리면 어디까지 좁혀지나

git bisect start HEAD v1 뒤에 git bisect run sh /root/check.sh. 결과를 그대로 bisect.txt 에 옮깁니다. 하나로 안 좁혀집니다.

git bisect start HEAD v1 로 시작하고 git bisect run sh /root/check.sh 를 돌립니다. 끝나면 반드시 git bisect reset 으로 정리하세요. 결과를 요약하지 말고 화면에 나온 대로 옮기세요.

125 를 빼면 무슨 일이 생기나

125 를 뺀 wrong-check.sh 로 같은 이등분을 다시 돌립니다. 이번에는 확신 있게 답을 냅니다 — 그리고 그 답은 틀렸습니다. 둘을 나란히 적으세요.

판정 불가에도 1(bad)을 돌려주는 스크립트를 따로 만들어 같은 이등분을 다시 돌립니다. 이번에는 하나를 확신 있게 지목하는데, 그 답이 틀렸습니다. 두 결과를 나란히 적으세요.

마지막 한 걸음은 사람이 정한다

두 후보 중 어느 쪽이 범인인지 git show 로 확인하고, 다른 쪽을 왜 배제했는지까지 적습니다.

후보가 둘이면 git show <해시>:app/calc.sh 로 각각 무엇이 들어 있는지 봅니다. 배제한 쪽의 근거까지 적어야 다음 사람이 다시 확인하지 않습니다.

무엇을 찾는지 알 때의 지름길

git log -S 로 같은 답을 한 번에 냅니다.

git log -S <문자열> 은 그 문자열이 추가되거나 삭제된 커밋만 냅니다. 이등분을 여섯 번 돌 필요 없이 한 번에 나옵니다 — 다만 무엇을 찾을지 이미 알아야 쓸 수 있습니다.

포매터 커밋을 지나 값을 정한 커밋으로

app/settings.inigit blamegit blame -w 를 각각 돌려 봅니다.

git blame app/settings.inigit blame -w app/settings.ini 를 각각 돌려 보세요. 앞의 것은 들여쓰기만 바꾼 커밋을 가리키고, -w 는 그것을 건너뜁니다. 두 해시를 나란히 적으세요.

언제 무엇을 먼저 쓰는가

네 도구를 언제 쓰는지 정리합니다.

세 도구가 답하는 질문이 다릅니다. 그리고 이번에 직접 겪은 것 — 자동화가 어디서 끝나는지 — 도 함께 적으세요.