# 끝내는 결국 `git bisect`를 사용하게 된다

> Clean Markdown view of GeekNews topic #24117. Use the original source for factual precision when an external source URL is present.

## Metadata

- GeekNews HTML: [https://news.hada.io/topic?id=24117](https://news.hada.io/topic?id=24117)
- GeekNews Markdown: [https://news.hada.io/topic/24117.md](https://news.hada.io/topic/24117.md)
- Type: GN+
- Author: [neo](https://news.hada.io/@neo)
- Published: 2025-11-04T05:32:50+09:00
- Updated: 2025-11-04T05:32:50+09:00
- Original source: [kevin3010.github.io](https://kevin3010.github.io/git/2025/11/02/At-the-end-you-use-git-bisect.html)
- Points: 14
- Comments: 2

## Summary

대규모 **monorepo**에서 갑작스러운 테스트 실패가 발생했을 때, 로그만으로는 원인을 찾기 어렵습니다. 이때 **`git bisect`** 는 단순한 면접 문제로 여겨지던 **이진 탐색 알고리듬**을 실무 디버깅에 적용해, “첫 번째 나쁜 커밋”을 자동으로 찾아내는 강력한 도구로 빛을 발합니다. **테스트 스크립트와 결합한 자동 탐색**을 통해 수백 개의 커밋 중 문제 지점을 빠르게 좁혀가며, 복잡한 코드베이스에서도 원인 추적 시간을 획기적으로 단축합니다. 알고리듬이 추상적 개념을 넘어 실전 생산성 도구로 작동하는 순간을 보여주는 멋진 사례입니다.

## Topic Body

- **이진 탐색(binary search)** 개념은 면접 문제뿐 아니라 실제 개발 도구인 **Git**에서도 활용됨  
- 대규모 **monorepo 환경**에서 테스트가 갑자기 실패했을 때, 로그만으로는 원인을 추적하기 어려운 상황이 발생  
- 한 동료가 **좋은 커밋과 나쁜 커밋을 지정해 `git bisect`로 자동 탐색**을 수행해 버그가 시작된 문제 커밋을 정확히 찾아냄  
- 각 단계에서 스크립트를 실행해 테스트 결과에 따라 커밋을 자동 분류하며, **첫 번째로 실패한 커밋**을 식별  
- 이진 탐색 원리를 활용한 `git bisect`는 **대규모 코드베이스에서 버그 원인을 신속히 추적하는 강력한 도구**임  
  
---  
### 알고리듬과 실제 사례  
- **이진 탐색(binary search)** 알고리듬은 단순한 면접 문제를 넘어 **실제 디버깅 도구에서도 핵심 원리로 작동함**  
- `git bisect`는 “버그를 처음 도입한 커밋(first bad commit)”을 찾기 위해 이진 탐색을 사용하는 도구”로 사용 가능  
  - Leetcode의 **“First Bad Version”** 문제와 유사한 원리로 작동함  
  
  
### 실제 업무 환경에서의 문제 상황  
- 대규모 **monorepo**를 사용하는 환경에서는 수백~수천 개의 커밋이 하루에도 발생함   
- 특정 테스트 실패의 원인을 **로그만으로는 추적하기 어려움**  
- 실패 원인은 **원격 호출에 필요한 토큰을 얻는 설정 파일의 문자열 변경**으로, 다른 계정을 참조하게 되어 테스트가 실패함  
- 이 변경은 통합 테스트를 통과했지만 실제로는 문제를 일으켰고, 수많은 커밋 중 어느 시점에서 발생했는지 찾기 어려웠음  
  
### `git bisect`를 이용한 문제 해결  
- 다른 팀의 동료가 **`git bisect` 명령어를 사용해 문제 커밋을 빠르게 식별**  
  - **좋은 커밋(good)** 과 **나쁜 커밋(bad)** 을 지정한 후 자동으로 중간 커밋들을 체크아웃하며 테스트를 수행하고 **원인을 좁혀감**  
  - 각 테스트 실행은 시간이 걸렸지만, 결국 **정확히 문제를 도입한 커밋을 찾아냄**  
  - 해당 커밋을 되돌리자 테스트가 모두 정상으로 복구됨  
  
### `git bisect` 실행 과정  
- 예시 커밋 히스토리  
  - Commit 1: 초기 커밋 (정상)  
  - Commit 2: 리팩터링 (정상)  
  - Commit 3: 버그 도입 (오류 발생)  
  - Commit 4~10: 비기능적 변경 (오류 유지)  
- 실행 명령 예시  
  ```  
  git bisect start  
  git bisect bad HEAD  
  git bisect good HEAD~9  
  git bisect run ./test_script.sh  
  ```  
- 테스트 스크립트(`test_script.sh`)는 **성공 시 0, 실패 시 비정상 코드**를 반환  
- `git bisect`는 중간 커밋을 자동으로 체크아웃하고 테스트 스크립트를 실행하며,  
  테스트 실패 시점을 기준으로 **첫 번째 나쁜 커밋**을 식별  
- 출력 결과에서 `b982ed9373fe235fe61c74b15faf264bc7142398` 커밋이 **첫 번째 버그 커밋**으로 확인됨  
  
### 결론  
- `git bisect`는 **이진 탐색 원리를 코드 히스토리 탐색에 적용한 실용적 도구**  
- 대규모 저장소나 복잡한 변경 이력에서도 **버그 도입 시점을 신속히 추적**할 수 있음  
- **테스트 자동화와 결합**하면 대규모 코드베이스에서도 안정적 디버깅이 가능함

## Comments



### Comment 45852

- Author: kandk
- Created: 2025-11-04T13:11:49+09:00
- Points: 1

이런 문제들 때문에 TBD(trunk-based-develop)을 사용합니다.

### Comment 45829

- Author: neo
- Created: 2025-11-04T05:32:50+09:00
- Points: 1

###### [Hacker News 의견](https://news.ycombinator.com/item?id=45791882) 
- 예전에 **테스트 커버리지**도 없고 추상화도 엉망인 거대한 코드베이스에서 일할 때, `git bisect`는 거의 유일하게 쓸 만한 도구였음  
  코드가 너무 복잡해서 논리적으로 버그를 추적하는 게 불가능했기 때문에, 어떤 커밋에서 문제가 생겼는지를 찾는 게 훨씬 쉬웠음  
  하지만 품질이 높은 코드베이스에서는 굳이 bisect가 필요하지 않았음. 각 컴포넌트를 독립적으로 테스트할 수 있고, **관측성(observability)** 도 잘 되어 있어서 어디를 봐야 할지 명확했음  
  - `git bisect`는 절대 불필요하지 않다고 생각함. 단순히 버그를 찾는 것뿐 아니라 **왜** 그 버그가 생겼는지를 이해하게 해줌  
    커밋 메시지가 충실한 프로젝트라면, bisect를 통해 과거 커밋의 맥락을 파악하고 그 내용을 버그 수정 커밋에 반영할 수 있음. 이런 순환이 커밋 문화 자체를 강화시킴  
  - 예전에 OSS 프로그램에서 이상한 문자열이 들어간 버그를 찾은 적이 있음. C 코드였고 초기화되지 않은 변수 때문이었음  
    직접 추적은 불가능했지만, bisect 스크립트를 작성해 30분 정도 돌리니 문제의 커밋을 정확히 찾아냈음  
  - `git bisect`는 원래 **Linux 커널 회귀(regression)** 를 찾기 위해 도입된 도구였음  
    하드웨어 드라이버처럼 테스트가 불가능한 경우에도, 일반 사용자가 직접 커널을 bisect해서 문제 커밋을 특정할 수 있게 되었음  
    예전에는 이메일로 개발자에게 도움을 요청해야 했지만, 이제는 사용자가 스스로 문제를 좁혀갈 수 있게 되었음  
  - 단순히 버그를 고치는 게 목적이라면 bisect가 필요 없을 수도 있음. 하지만 버그가 **언제부터 존재했는지** 알아야 할 때가 있음  
    예를 들어 잘못 처리된 데이터의 범위를 추적하거나, “이게 버그인가 기능인가”를 판단할 때 유용함  
  - 때로는 버그가 **언제 수정되었는지** 알아야 할 때도 있음  
    예를 들어 고객이 6년 전 버전에서 문제를 겪고 있을 때, 4년 전 버전으로 업그레이드하면 해결되는지 확인할 수 있음  
    혹은 코드가 크게 리팩터링되었을 때, 버그 수정이 의도적이었는지 우연이었는지도 파악 가능함  

- `git bisect`는 잘 작동할 때는 훌륭하지만, 모든 버그를 찾을 수 있는 건 아님  
  어떤 버그는 도입 당시에는 증상이 없고, 나중에 다른 변경으로 인해 드러나기도 함  
  이런 경우 bisect의 전제(좋은 커밋과 나쁜 커밋 사이에 단 한 번만 버그가 등장함)가 깨짐  
  테스트 불가능한 커밋은 `skip`할 수 있지만, 그게 문제 커밋이면 결과가 애매해짐  

- 최근 처음으로 진지하게 `git bisect`를 써봤는데, 거의 **마법 같음**  
  두 개의 동일한 이름의 함수가 있었고, 코드 포매팅 작업 중에 올바른 함수의 import가 제거되면서 문제가 발생했음  
  여러 번 코드를 검토했지만 bisect로 문제 커밋을 특정하기 전까지는 원인을 전혀 몰랐음  

- 나는 보통 버그가 생긴 파일이나 함수의 범위를 이미 알고 있어서 bisect를 자주 쓰진 않음  
  대신 `git log -L :func_name:path/to/file.c` 명령으로 특정 함수의 변경 이력을 추적함  
  `.gitattributes` 설정이 필요함  
  - `.gitattributes` 설정이 궁금하다는 질문이 있었음. 어떤 내용이 필요한지 더 알고 싶다는 반응이었음  
  - 매일 bisect를 쓴다는 사람도 있었음. 워크플로우가 완전히 다름  
  - C++처럼 **다형성 함수**가 있는 경우에는 `git log -L`이 약함. 동일한 이름의 오버로드 함수 중 특정 버전을 추적하기 어렵기 때문임  
  - `.gitattributes`가 없다면 `git log -S`로 특정 문자열이 포함된 커밋을 찾는 것도 방법임  

- 테스트 스크립트에서 **exit code 125**를 알아두면 좋음  
  빌드 실패처럼 테스트 결과를 판별할 수 없는 경우, 125를 반환하면 bisect가 해당 커밋을 건너뜀  
  관련 내용을 [내 블로그 글](https://speechcode.com/blog/git-bisect)에 정리했음  
  - 병합 커밋이 CI 통과 지점을 의미하는 저장소에서는 `git bisect --first-parent`를 쓰면 유용함  
    이렇게 하면 “어떤 PR이 버그를 도입했는가”를 빠르게 찾을 수 있고, 이후 해당 브랜치에서 세부 bisect를 한 번 더 돌리면 됨  

- **플레이키 테스트(flaky test)** 가 생겼을 때 bisect가 빛을 발함  
  레이스 컨디션으로 인해 테스트를 수십만 번 돌려야 확신할 수 있는 경우, bisect 스크립트를 백그라운드로 돌려두면 현실적으로 해결 가능함  
  - 이런 경우에는 **베이지안 이진 탐색**을 적용하면 테스트 횟수를 훨씬 줄일 수 있을 것 같음  

- 최근 Svelte로 만든 음악 플레이어 프로젝트([lets-make-sweet-music.com](https://lets-make-sweet-music.com))에서 bisect로 버그 원인을 찾았음  
  테스트도 없고, 오류 로그도 없었는데, `dependabot` 업데이트로 커밋이 많아져서 추적이 어려웠음  
  bisect 덕분에 문제의 커밋을 찾아냈고, 원인은 내가 교체한 파일이 **이벤트 다중 바인딩 기능**을 구현하지 않았던 것임  
  커밋을 작게 유지하면 bisect로 찾은 문제의 원인을 빠르게 좁힐 수 있음  

- 누군가 “면접에서 **이진 탐색(binary search)** 을 배워야 한다는 건 억지”라고 했는데, `git bisect`는 그 개념을 실제로 보여주는 좋은 예임  
  하지만 직접 구현할 필요는 없음. 대부분의 언어에는 이미 표준 라이브러리로 제공됨  
  - 흥미롭게도, 이진 탐색이 1940년대에 처음 제안됐지만 **버그 없는 구현**이 1960년대에야 나왔다는 이야기가 있음  
    중간 인덱스를 계산할 때 `(low + high) / 2`로 하면 오버플로가 생길 수 있음  
  - 개인적으로는 모든 개발자가 한 번쯤 **임의 정밀도 정수 언어**(예: Python)로 이진 탐색을 직접 구현해보는 게 좋다고 생각함  
    **불변식(invariant)** 기반 사고를 훈련하는 최고의 연습임  

- Git에는 bisect 외에도 `log -L`, `log -S`, `blame` 같은 훌륭한 코드 탐색 도구가 있음  
  예전에 이 주제로 [블로그 글](https://news.ycombinator.com/item?id=39877637)을 쓴 적이 있음
