안녕하세요, 강남언니 서비스 백엔드를 담당하고 있는 제이슨입니다! 사용자가 불편함 없이 빠르고 안정적으로 더 좋은 의료 서비스를 이용할 수 있도록 하는 역할을 하고 있습니다.

만약 여러분의 제품에 버그가 발견되었는데 발생 원인을 찾기 힘들다면, 거기에다 '어라 이거 발생한지 좀 된 버그인거 같은데...' 싶으면 어떻게 원인을 찾으시나요?

이번 글에서는 이럴 때 사용하기 좋은 git bisect 명령어를 알아봅시다.

git bisect

개요

bisect 는 'divide into two parts', 즉 '양분하다' 라는 의미를 가지고 있습니다. 그래서 Python 의 배열 이진 분할 알고리즘 이름도 bisect 이죠.

Python3 bisect

그러면 git bisect 는 어떤 명령어일까요?

https://git-scm.com/docs/git-bisect

버그가 발생한 commit 을 찾는데 사용하면 된다고 합니다! 위의 문제 상황에 딱 좋은 방법이겠죠?

사실 원리는 매우 간단합니다.
이름에서도 유추할 수 있듯, 단지 git 에서 commit 이진 탐색을 도와주는 것이죠.
1024 개의 commit 이 있어도 10번이면 버그가 발생한 commit 을 찾을 수 있습니다.

하지만 이 명령어가 없이 직접 이진 탐색을 하는 것은 꽤 고달픈 일이기 때문에, 단순한 기능이지만 역할을 톡톡히 해냅니다.

사용 방법

일단 사용해봅시다.

위와 같이 중간 어딘가의 commit 에 버그가 있는 상황입니다.

git bisect 를 시작하면서, 어느 commit 부터 어느 commit 까지를 탐색할지 설정하면 자동으로 commit 을 옮겨다니면서 이진 탐색을 시작합니다.

# git bisect 시작
$ git bisect start

# 현재 commit 에 버그가 존재하므로 'bad' 로 지정
$ git bisect bad

# 버그가 없는 commit 을 찾아봅시다
# 3.1.0 tag 가 붙어있는 commit 에는 버그가 있을까요?
$ git checkout 3.1.0
...

# ... 아 저 commit 에는 아직 버그가 있네요.
# d1cd42ae6 commit 에도 버그가 있을까요?
$ git checkout d1cd42ae6
...

# 버그가 없는 것을 확인했습니다!
# 그러면 이 commit 을 'good' 으로 지정합니다.
$ git bisect good
Bisecting: 5 revisions left to test after this (roughly 2 steps)
<다음에 탐색할 commit 에 대한 내용..>


이제 계속해서 해당 commit 에 버그가 있는지 없는지 찾아서 `good`/ `bad` 를 지정해나가면 어느 commit 이 문제인지 빠르게 확인할 수 있습니다.최종적으로 버그가 발생한 commit 을 찾게 되면 ` is the first bad commit` ( 는 해당 commit 의 sha) 라는 메시지를 출력해줍니다.
$ git bisect bad
Bisecting: 2 revisions left to test after this (roughly 1 steps)
...

$ git bisect good
Bisecting: 1 revisions left to test after this (roughly 0 steps)
...

# 마지막 탐색 대상 commit
$ git bisect bad
11d51be3567c64120a44bc2ba6704af6e14e69cf is the first bad commit
...

# git bisect 종료
$ git bisect reset

결국 아래와 같은 과정을 거쳐 최초로 버그가 발생한 commit 을 찾게 되었습니다.

commit 이 7개인 경우를 예로 들어서 그다지 드라마틱한 효과가 없어보이지만, 위에서도 언급했듯 1024 개의 commit 이 있어도 10번만에 최초로 버그가 발생한 commit 을 찾을 수 있습니다.

부가 기능

위의 기능만 있다면 좀 아쉽겠죠? git bisect 에서는 위와 같이 이진 탐색에 필수적인 기능 말고도 여러가지 부가 기능을 제공하고 있습니다.

내가 어디까지 했더라?

git bisect log 를 통해 git bisect 과정을 확인할 수 있습니다.

$ git bisect log
git bisect start
# bad: [<commit sha>] <commit message>
git bisect bad <commit sha>
...

이 commit 은 확인할 수가 없는데..

탐색을 하다가 버그가 있는지 없는지 확인할 수 없는 commit (ex. 그러면 안되지만 build 가 안되는 commit 이라든지) 이 걸린 경우에는 git bisect skip 으로 해당 commit 말고 다른 commit 으로 탐색을 계속 진행할 수 있습니다.

$ git bisect skip
Bisecting: 2 revisions left to test after this (roughly 1 steps)
...

bad/good 말고 다른건 안되나요?

버그를 찾을 때는 bad/good 이 맞지만, 만약 새로운 기능이 적용된 commit 을 찾고 싶다면 bad/good 이라는 표현 때문에 오히려 헷갈릴 수 있겠죠? 그래서 그대신 new/old 를 사용해도 되고, 원한다면 시작할 때 --term-old <term-old> --term-new <term-new> 옵션을 통해 자신이 직업 용어를 정해서도 작업할 수 있습니다.

$ git bisect start --term-old wow --term-new woo

앗, 잘못 선택했다

현재 git bisect 에는 undo 기능이 없습니다😓 그 대신 git bisect loggit bisect replay 기능을 이용해서 다시 해당 단계까지 갈 수 있습니다.

# bisect.log 에 log 저장
$ git bisect log > bisect.log

# bisect.log 을 열어서 잘못된 부분 수정
...

# 수정된 bisect.log 로 replay
$ git bisect replay bisect.log

자동으로 어떻게 안되나요?

git bisect run <command> 를 이용해서 자동화가 가능합니다. 예를 들어 뒤늦게 mvn test 가 실패하고 있는 것을 찾았을 때, 처음으로 mvn test 가 깨진 commit 을 찾고 싶다면?

# bisect_test.sh

#!/bin/sh
mvn test

$ git bisect bisect_test.sh

이렇게 하면 mvn test 의 결과에 따라 git bisect 의 진행이 자동으로 진행되어 매우 편리합니다.

마무리

이 기능을 알고만 있다가 실제로 예전에 발생한 버그를 뒤늦게 발견해서 '이 방법을 사용해볼까?' 하고 써봤더니 매우 빠르고 편하게 버그가 발생한 commit 을 찾을 수 있었습니다. (다 뒤져볼 생각하면 끔찍...)

하지만 가장 좋은 것은 이런 기능을 사용할 일이 없는 것이 아닐까 싶기도 하네요😁

Json
Back-end Developer
사용자가 빠르고 안정적으로 강남언니를 이용하실 수 있게 Back-end 를 담당하고 있습니다. 생각하는 개발자입니다.