Git 실전 · 이등분과 고고학 · 이론
1,000개 커밋에서 범인을 10번 만에 찾기
한 줄 요약
"두 달 전엔 됐는데 지금은 안 된다" 에서 커밋 하나를 특정하는 데 필요한
검사 횟수는 커밋 수가 아니라 log₂(커밋 수) 입니다. 1,000개면 10번입니다.
왜 이게 필요했나
버그 리포트가 왔습니다. "예전엔 잘 됐는데요."
git log 를 열면 그 사이에 커밋이 800개 있습니다. 하나씩 확인하면
800번이고, 눈으로 훑으면 "관련 있어 보이는" 커밋에 편향됩니다. 그리고
경험상 범인은 대개 관련 없어 보이는 커밋입니다.
git bisect 는 이진 탐색을 자동으로 해 줍니다.
git bisect startgit bisect bad # 지금은 깨져 있다git bisect good v1.4.0 # 이 버전에서는 됐다# → git 이 중간 커밋으로 체크아웃한다# 확인 후git bisect good 또는 git bisect bad# 반복. 10번이면 끝난다.git bisect reset자동화 — bisect run
검사를 스크립트로 쓸 수 있으면 사람이 앉아 있을 필요도 없습니다.
git bisect start HEAD v1.4.0git bisect run ./check.shcheck.sh 는 종료코드로 말합니다.
| 종료코드 | 뜻 |
| --- | --- |
| 0 | good |
| 1–124, 126, 127 | bad |
| 125 | skip — 이 커밋은 판정 불가(빌드 실패 등) |
125가 중요합니다. 중간에 빌드가 깨진 커밋이 섞여 있을 때, 그걸 bad 로
판정하면 엉뚱한 곳으로 수렴합니다. 판정할 수 없으면 skip 을 돌려야 합니다.
#!/bin/bashmake build || exit 125 # 빌드 실패 = 판정 불가./run-test.sh || exit 1 # 테스트 실패 = badexit 0 # 통과 = goodbisect 를 위한 전제
이등분이 잘 되려면 커밋 하나하나가 빌드되고 실행되는 상태여야 합니다.
"WIP", "작업 중", "일단 커밋" 같은 커밋이 잔뜩이면 skip 만 늘어납니다.
평소에 작고 완결된 커밋을 쌓는 습관이 여기서 값을 합니다.
log -S — 그 코드가 언제 들어왔나
특정 문자열이 추가되거나 삭제된 커밋만 찾습니다.
git log -S 'timeout=3' --oneline"이 설정값이 언제 3으로 바뀌었지?" 에 한 번에 답합니다. 정규식으로
찾으려면 -G 를 씁니다.
git log -p -- path/to/file 로 파일 하나의 변경 이력만 볼 수도 있고,--follow 를 붙이면 이름이 바뀐 이력까지 따라갑니다.
blame — 누가 아니라 왜
git blame 은 각 줄을 마지막으로 고친 커밋을 보여 줍니다. 목적은
책임자 찾기가 아니라 맥락 찾기 입니다. 그 줄이 왜 그렇게 쓰였는지는
커밋 메시지와 그 커밋의 다른 변경에 있습니다.
git blame -L 40,60 src/app.py # 40~60행만git blame -w # 공백 변경 무시git blame -C # 다른 파일에서 옮겨온 코드도 추적-w 가 특히 유용합니다. 포매터를 한 번 돌린 저장소에서는 모든 줄이
"포매팅 커밋" 으로 나오는데, -w 는 그걸 건너뛰고 실제 변경을 찾아 줍니다.
reflog — 잃어버린 것을 되찾기
git reflog 는 HEAD 가 움직인 모든 기록입니다. 리베이스를 잘못했거나
브랜치를 지웠어도, 커밋 자체는 한동안 살아 있습니다.
git reflog# a1b2c3d HEAD@{5}: rebase (finish): returning to refs/heads/main# 9f8e7d6 HEAD@{6}: commit: 잃어버린 작업git checkout -b rescue 9f8e7d6"git 에서 커밋한 것은 웬만하면 안 사라진다" 는 말의 근거가 reflog 입니다.
현장에서 만나는 모습
- 성능이 언제부터 나빠졌는지 모름 → 벤치마크 스크립트로
bisect run. - 이상한 상수가 코드에 박혀 있음 →
log -S로 들어온 커밋과 이유를 찾음. - 리베이스 중 커밋이 사라짐 → reflog 로 복구.
다음 실습에서 할 것
40개짜리 이력을 직접 만들고 범인을 찾습니다. 그 이력에는 **판정할 수 없는
커밋이 하나** 섞여 있어서, 125 를 안 쓰면 bisect 가 엉뚱한 커밋을 확신 있게
지목합니다. 두 스크립트를 나란히 돌려 그 차이를 눈으로 봅니다.
그리고 125 를 제대로 쓰면 이번에는 bisect 가 **후보 두 개까지만 좁히고
멈춥니다.** 마지막 한 걸음은 사람이 정합니다 — 자동화가 끝나는 자리가
어디인지가 이 실습의 결론입니다.