/엔지니어/Git / CI·CD/git bisect 완전 가이드 — 버그가 처음 생
Git / CI·CD중급ubuntumacoswindowsgitbisectdebugging

git bisect 완전 가이드 — 버그가 처음 생긴 커밋 이진 탐색으로 찾기

수백 개 커밋 속 회귀 버그의 도입 지점을 이진 탐색으로 특정합니다. 수동 bisect부터 git bisect run 자동화, 종료 코드 규칙, 커스텀 판정 스크립트까지.

git bisect란 — 이진 탐색으로 범인 커밋 찾기

"어제까지 잘 되던 기능이 오늘 깨졌다. 그런데 그동안 커밋이 200개다." 이럴 때 커밋을 하나씩 되짚는 대신, git bisect는 **이진 탐색(binary search)**으로 버그가 처음 들어온 커밋을 빠르게 찾아 줍니다.

원리는 단순합니다. "정상(good)"인 커밋과 "고장(bad)"난 커밋을 알려주면, Git이 그 사이 중간 커밋으로 체크아웃해 줍니다. 당신은 테스트해서 good/bad만 답하면, Git이 다시 남은 절반의 중간으로 이동합니다. 커밋 1,000개도 약 10번(log₂1000 ≈ 10)이면 좁혀집니다.

회귀(regression)의 정확한 도입 지점을 알면 원인 분석이 극적으로 쉬워집니다. 200줄짜리 머지 커밋이 아니라 "이 한 줄을 바꾼 커밋"으로 특정되기 때문입니다.


수동 bisect — 기본 흐름

Bash
# 1. 세션 시작
git bisect start

# 2. 현재 커밋이 고장 상태라고 표시
git bisect bad

# 3. 확실히 정상이던 지점 표시 (태그·커밋 해시·상대참조 모두 가능)
git bisect good v1.4.0

이 시점에 Git이 중간 커밋으로 자동 체크아웃하고 남은 후보 수를 알려 줍니다.

CODE
Bisecting: 63 revisions left to test after this (roughly 6 steps)
[a1b2c3d...] Refactor payment handler

이제 이 커밋을 빌드·테스트한 뒤 결과를 답합니다.

Bash
# 여기서 재현되면
git bisect bad
# 여기서 정상이면
git bisect good

Git이 다시 절반으로 좁혀 다음 커밋으로 이동합니다. 반복하면 최종적으로 범인을 지목합니다.

CODE
b9f0e1a2c3... is the first bad commit
commit b9f0e1a2c3...
    Cache user session in memory

세션 종료 — reset 필수

탐색이 끝나면(또는 중단하려면) 반드시 원래 브랜치로 복귀합니다.

Bash
git bisect reset          # 원래 HEAD로 복귀
git bisect reset <커밋>   # 특정 커밋으로 복귀하며 종료

git bisect는 탐색 중 여러 커밋을 오가며 detached HEAD 상태로 만듭니다. reset을 하지 않으면 중간 커밋에 머문 채 작업하게 되니, 끝나면 습관적으로 git bisect reset을 실행하세요.


자동화 — git bisect run

가장 강력한 기능입니다. good/bad를 판정하는 명령이나 스크립트를 넘기면, Git이 끝까지 전자동으로 탐색합니다.

판정 규칙은 **종료 코드(exit code)**로 결정됩니다.

종료 코드의미
0good (정상)
1~124, 126, 127bad (고장)
125skip (이 커밋은 테스트 불가)
128+탐색 중단
Bash
git bisect start
git bisect bad
git bisect good v1.4.0

# 테스트가 통과하면 exit 0(good), 실패하면 exit 1(bad)
git bisect run npm test -- payment.spec.js

Git이 알아서 각 후보 커밋을 체크아웃하고 명령을 돌려, 최종 first bad commit을 출력한 뒤 멈춥니다. 커피 한 잔 마시고 오면 끝나 있습니다.


커스텀 판정 스크립트

빌드가 필요하거나 특정 조건을 검사해야 하면 스크립트를 씁니다. 종료 코드 규칙만 지키면 됩니다.

Bash
#!/usr/bin/env bash
# bisect-test.sh

# 컴파일 자체가 안 되는 커밋은 판정에서 제외(skip)
make build || exit 125

# 특정 증상 재현 여부로 good/bad 판정
if ./run-app --check-feature; then
  exit 0    # good
else
  exit 1    # bad
fi
Bash
chmod +x bisect-test.sh
git bisect run ./bisect-test.sh

exit 125(skip)는 "이 커밋은 빌드 깨짐 등으로 good/bad를 판정할 수 없음"을 뜻해, Git이 근처 다른 커밋으로 우회합니다.


skip과 로그

특정 커밋을 수동으로 건너뛰거나, 진행 기록을 남길 수 있습니다.

Bash
git bisect skip              # 현재 커밋 판정 불가 → 건너뜀
git bisect skip <커밋1> <커밋2>

git bisect log > bisect.log  # 지금까지의 good/bad 기록 저장
git bisect replay bisect.log # 기록을 그대로 재실행

bisect visualize(또는 view)로 남은 탐색 범위를 gitk/로그로 볼 수도 있습니다.


용어 커스터마이즈 — good/bad 대신

"성능 저하"처럼 good/bad가 어색할 때 용어를 바꿀 수 있습니다.

Bash
git bisect start --term-old=fast --term-new=slow
git bisect slow      # 현재가 느림
git bisect fast v1.4.0
git bisect run ./perf-check.sh

실전 팁

  • 재현 절차를 먼저 자동화하세요. bisect run에 넘길 한 줄 명령이 있으면 탐색이 몇 배 빨라집니다.
  • good 지점을 넉넉히 잡으세요. 확실히 정상이던 오래된 태그를 good으로 두면 안전합니다. good이 사실은 이미 고장이었다면 결과가 틀어집니다.
  • 테스트 격리: 각 커밋마다 의존성 설치나 캐시가 필요하면 스크립트 안에 포함하세요(npm ci 등). 안 그러면 이전 커밋의 잔재로 오판할 수 있습니다.
  • 머지 커밋 주의: first bad commit이 머지 커밋이면, 그 브랜치 내부를 다시 bisect해 세부 커밋으로 좁힐 수 있습니다.

버그가 언제 들어왔는지 모를 때, 로그를 눈으로 훑는 것은 선형 탐색입니다. git bisect run으로 판정만 자동화하면, 수백 개 커밋 속 범인을 로그 시간에 정확히 지목할 수 있습니다.

#git#bisect#debugging#regression#버그추적
편집 안내 · Editorial Note

이 가이드는 AI 도구를 활용해 초안을 구성하고 사람이 명령어·문맥을 검토해 발행했습니다. 운영체제와 도구 버전에 따라 결과가 달라질 수 있으므로 적용 전 공식 문서를 함께 확인하세요. 오류를 발견하시면 이메일로 제보해 주세요.

관련 공식 문서Git 공식 문서

질문 & 답변 (Q&A)

이 가이드에 대해 궁금한 점을 질문해보세요. 확인 후 답변드립니다.