카테고리 없음

git bisect 로 소스의 특정 변경 사항을 찾아내기

wafe 2013. 7. 3. 16:35

ffmpeg의 avpicture_get_size() 함수를 보면 언제부터인가 첫번째 인자 타입이 enum PixelFormat pix_fmt 로 변경되었습니다. 최초로 이런 변경 사항이 적용된 커밋을 찾아서, 이 변경 사항의 영향 범위가 어느 정도인지 파악하고 싶었는데, ffmpeg 프로젝트의 git 저장소를 웹으로 보여주는 인터페이스에서는 그 지점을 찾기가 여간 힘든게 아니네요.

우선 웹 인터페이스를 통해서 0.5 릴리스 브랜치의 가장 최근 커밋(head)에서는 avpicture_get_size()의 첫번째 인자 타입이 int pix_fmt 인 것은 확인을 했고요, 0.6 릴리스 브랜치의 head 에서는 PixelFormat pix_fmt 인 것을 확인했습니다. Get FFmpeg 페이지에서 보면 0.5 릴리스 브랜치가 2009-03-02 에 cut off 되었다고 하니, 0.6 릴리스 브랜치에서 2009-03-02 이전의 커밋을 찾아보면 될 것 같습니다. 페이지를 막~ 넘겨서 60페이지 쯤 가니까 2009년 2월 커밋들이 보이네요. 아무 커밋이나 하나 골라서(c027e91a744c5875a47e5d4bb2a0ff9b112d2e0f) 확인해보니 인자 타입이 int pix_fmt 입니다. 그러면 이 커밋과 0.6 릴리스의 헤드 커밋 사이 어디쯤에선가 인자 형태가 바뀌었다고 볼 수 있겠네요. 어느 커밋에서 그런 변경이 있었는지 bisect 로 찾아보기로 했습니다.

ffmpeg 저장소를 clone 하고, 리모트의 0.6 브랜치를 체크아웃 합니다.

관심 대상인 avcodec.h 파일을 Notepad++ 이나 Sublime Text 같이 파일이 변경되었을 때 자동으로 바뀐 내용으로 새로고침해주는 편집기로 열어둡니다. 이렇게 하면 매번 파일을 새로 열어보는 번거로움을 덜 수가 있습니다.

이제 bisect 를 시작해봅시다.

git command line 을 실행해서 ffmpeg 저장소 루트 디렉토리로 갑니다. 거기서 시작 명령을 내려줍니다.

> git bisect start

그리고 0.6 브랜치의 head 는 PixelFormat pix_fmt 형태이므로, bad 라고 표시를 해 줍니다.

> git bisect bad

또한 int pix_fmt 형태인 커밋의 위치를 알고 있으므로 good 으로 표시해줍니다.

> git bisect good c027e91a744c5875a47e5d4bb2a0ff9b112d2e0f

이렇게 하면 git 은 자동으로 0.6 브랜치의 head 와  c027e91a744c5875a47e5d4bb2a0ff9b112d2e0f 커밋의 중간 지점 커밋을 체크아웃 해 줍니다. 아까 에디터에 열어둔 avcodec.h 파일을 확인해봅니다. 아직은 인자 타입이 PixelFormat 이므로 bad 로 표시합니다.

> git bisect bad

그러면 git 이 자동으로 이 커밋과 가장 처음 good 으로 표시된 지점인 c027e91a744c5875a47e5d4bb2a0ff9b112d2e0f 커밋의 중간 지점 커밋을 체크아웃 해 줍니다. 다시 에디터에서 avcodec.h 를 확인해봅니다. 역시 PixelFormat 이군요. bad 로 표시합시다.

> git bisect bad

이런 식으로 커밋 히스토리를 절반씩 나눠가면서 일종의 바이너리 서치(이진 탐색)을 해서 인자 타입이 int 일 때에는 bad 대신 good 으로 표시해주고, bisect 모드가 끝날 때까지 진행하면 인자 타입이 int 에서 PixelFormat 으로 변경된 커밋을 빠르게 찾을 수 있습니다.

파일에 "avpicture_get_size(enum PixelFormat pix_fmt" 라는 문자열이 포함되어 있는지 확인하는 스크립트를 git bisect run 을 이용하여 실행시키면 지금까지 했던 과정을 자동화할 수도 있죠.

svn 저장소를 활용하면서도 이런 일을 해주는 스크립트들이 상당히 만들어져 있긴 합니다. 하지만 아무래도 svn 은 특정 커밋(리비전)간의 전환을 하려면 네트워크로 파일 전송을 해야 하니 상대적으로 매우 느리죠. git 에는 bisect 기능이 내장되어 있어 잘 알려져 있기도 하고, svn 보다는 git이나 mercurial 같이 커밋간의 전환이 아주 빠른 DVCS 들에서 빛을 보는 기능이라고 할 수 있겠습니다. svn 에서 bisect 할 일이 있으면 git-svn 같은 도구를 이용해서 svn 저장소를 git 저장소로 마이그레이션 한 후에 git bisect 기능을 사용하는게 더 효율적일 거라는 조언도 있네요.