간만에 공용 저장소에서 커밋들을 pull 해왔을 때, 내 저장소의 코드가 제대로 동작하지 않기 시작하면 정말 난감하기 짝이 없다. 이 때 디버깅이 간단하지 않다면, 천천히 버그의 원인을 찾아보게 된다. 버그의 원인은, 현재 발생하고 있는 버그가 최초로 발생한 커밋에 있을 것이므로 그 커밋을 찾아낼 수 있다면 쉽게 원인도 파악할 수 있을 것이다.
bisect로 찾기
bisect –run
git bisect start
git bisect bad <bad-commit>
git bisect good <good-commit>
git bisect --run <shell command>
버그의 원인으로 의심되는 커밋을 자동으로 찾아주는 아주 편리한 기능이다. git bisect bad
와git 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 bad
와 git 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를 쓰면 정규식으로 검색한다.