git으로 버그의 원인 찾기

간만에 공용 저장소에서 커밋들을 pull 해왔을 때, 내 저장소의 코드가 제대로 동작하지 않기 시작하면 정말 난감하기 짝이 없다. 이 때 디버깅이 간단하지 않다면, 천천히 버그의 원인을 찾아보게 된다. 버그의 원인은, 현재 발생하고 있는 버그가 최초로 발생한 커밋에 있을 것이므로 그 커밋을 찾아낼 수 있다면 쉽게 원인도 파악할 수 있을 것이다.

bisect로 찾기

bisect –run

git bisect start
git bisect bad <bad-commit>
git bisect good <good-commit>
git bisect --run <shell command>

버그의 원인으로 의심되는 커밋을 자동으로 찾아주는 아주 편리한 기능이다. git bisect badgit bisect good으로 버그가 발견된 시점과 버그가 없었던 시점을 알려주고, git bisect --run으로 버그 존재 여부를 확인할 수 있는 쉘 명령을 주면, 최초로 버그가 발생한 시점을 binary search로 찾아낸다.

두 가지 조건을 만족해야 이 기능을 사용할 수 있다.

버그가 발생하지 않았던 시점을 알아야 한다.

........ffff..fffH
        ^  ^  ^
        F1 F2 F3

위와 같은 상태의 저장소가 있다고 가정하자. 첫번째 줄에 나열된 문자들은 히스토리를 상징한다. 문자 하나가 커밋 하나다. .은 버그가 없는 커밋이고 f는 버그가 있는 커밋이며 H는 현재 시점(HEAD)다.

H 시점에서 버그가 발견되었다면, 그 원인은 F3에 있을 것이다. F3이 어디인지 알아내기 위해서는 F2와 F3 사이의 아무 커밋이나 하나를 찍어서 git bisect good으로 해당 시점에는 버그가 없었음을 알려주어야 한다. 그렇게 하면 git bisect는 그 커밋 이후부터의 커밋에서 버그가 발생한 지점을 탐색할 것이고 정확하게 F3을 찾아낼 것이다.

그러나 만약 F1 이전 시점을 good으로 선택했다면 git이 알려주는 최초 버그발생 시점은 F1일 수도 있고 F3일 수도 있다. 앞에서 언급했듯이 binary search를 사용하기 때문이다. 위의 사례처럼 테스트 실패가 방치되는 경향이 있는 프로젝트라면 이런 어려움을 겪을 가능성이 높다.

쉘 명령으로 버그를 탐지하는 것이 가능해야 한다.

이 조건은, 커맨드라인에서 유닛테스트 실행할 수 있도록 되어있다면 간단히 만족된다. git bisect --run은 주어진 쉘 커맨드가 0을 반환하면 버그없음, 0이 아닌값을 반환하면 버그가 있는 것으로 간주한다. 커맨드라인에서 실행가능한 유닛테스트라면 틀림없이 그렇게 동작하도록 구현되어 있을 것이므로 그냥 사용하면 된다.

수동 bisect

git bisect start
git bisect bad <bad-commit>
git bisect good <good-commit>
# ...
git bisect good
# ...
git bisect bad

쉘 명령으로 정상/오류 상태를 판단할 수 없다면 사람이 수동으로 판단할 수 밖에 없다. 이 방법은 위의 git bisect --run 대신 수동으로 하나하나 해 보는 방법이다.

git bisect badgit bisect good으로 버그가 발견된 지점과 버그가 없었던 지점을 각각 선택해주면 그 다음부터 정상동작하는지 테스트가 필요한 지점으로 git이 알아서 checkout 해준다. 수동으로 테스트를 해 보고 버그가 있으면 bad, 없으면 good이라고 알려주면 된다. 몇 차례 반복하면 git이 최초 버그가 발생한 지점이 어디인지 알려줄 것이다.

이 방법 역시 앞에서 이야기한 조건 중 ‘버그가 발생하지 않았던 시점을 알아야 한다’는 만족해야 사용할 수 있다.

log로 검색해서 찾기

모든 버그의 원인을 bisect로 다 밝혀낼 수는 없다. 자동화된 테스트로 탐지되지도 않고 언제부터 버그였는지 짐작도 되지 않는 그런 오류의 근본 원인을 찾아야 하는 상황이라면 더 단순한 도구와 당신의 머리를 활용해서 탐사를 해야 한다.

log –grep

git log --grep <pattern>

커밋로그를 검색한다. 커밋로그를 잘 남겼다면 버그를 일으키는 모듈이나 기능을 언제 추가했는지 이것으로 찾아낼 수 있을 것이다.

log -S 혹은 log -G

git log -S <string>
git log -G <pattern>

모든 커밋의 변경내역을 검색한다. 버그의 원인으로 짐작되는 함수, 변수, 상수를 발견했다면 이 기능을 이용해 최초 추가된 시점을 찾을 수 있을 것이다. -S 대신 -G를 쓰면 정규식으로 검색한다.

Advertisements

답글 남기기

아래 항목을 채우거나 오른쪽 아이콘 중 하나를 클릭하여 로그 인 하세요:

WordPress.com 로고

WordPress.com의 계정을 사용하여 댓글을 남깁니다. 로그아웃 / 변경 )

Twitter 사진

Twitter의 계정을 사용하여 댓글을 남깁니다. 로그아웃 / 변경 )

Facebook 사진

Facebook의 계정을 사용하여 댓글을 남깁니다. 로그아웃 / 변경 )

Google+ photo

Google+의 계정을 사용하여 댓글을 남깁니다. 로그아웃 / 변경 )

%s에 연결하는 중