모든 개발자가 언젠가 마주하는 질문
지난달까지는 분명히 잘 동작했습니다. 확실합니다. 사이드바는 가지런히 정렬되어 있었고, 날짜 파서는 타임존을 제대로 처리했으며, 버튼은 딱 알맞은 파란색이었습니다. 그런데 버그 리포트가 날아오고, 이제 2년치 히스토리를 가진 파일을 들여다보며 겉보기에는 단순한 질문에 답하려 애쓰고 있습니다. 이게 언제 바뀌었고, 어떤 commit이 범인일까?
곧바로 두 번째 질문이 따라옵니다. 누가 그 변경을 했고, 왜 했을까? commit 메시지가 설명해 줄 수도 있습니다. 작성자가 기억하고 있을 수도 있습니다. 하지만 먼저 그 commit을 찾아야 하고, 바로 거기서 머릿속 곡예가 시작됩니다.
CLI 도구 상자, 그리고 그 한계
파일의 히스토리를 조사하는 데 필요한 모든 것은 이미 Git에 들어 있습니다. 이 도구들은 강력하고 오랜 실전에서 검증되었습니다. 마찰은 어느 한 명령어에 있는 것이 아니라, 얼마나 많은 명령어를 연달아 엮어야 하는지에 있습니다.
git log --follow
git log --follow --oneline -- src/styles/sidebar.css
이 명령은 파일 이름이 바뀐 경우까지 추적하며, 해당 파일을 건드린 모든 commit을 나열합니다. 출발점으로는 정확합니다. 하지만 얻는 것은 SHA와 commit 메시지일 뿐, 내용은 아닙니다. 특정 시점에 파일이 실제로 어떤 모습이었는지 보려면 다음 명령어가 필요합니다.
git show SHA:path
git show a3b4c5d:src/styles/sidebar.css
이 명령은 해당 commit 시점의 파일 전체를 출력합니다. 두 버전을 비교하려면 두 번 실행해서 출력을 비교하거나 git diff a3b4c5d 9f2e1d0 -- src/styles/sidebar.css를 사용해야 합니다. 그리고 이것을 후보 commit마다 반복합니다. 30개의 commit이 파일을 건드렸다면, 한동안 SHA를 복사해 붙여넣으면서 버전 간 차이를 내내 머릿속에 담아 두어야 합니다.
git blame
git blame src/styles/sidebar.css
blame은 각 줄에 그 줄을 마지막으로 수정한 commit을 표시해 줍니다. 의심스러운 줄이 아직 파일에 남아 있고 누가 작성했는지 알고 싶을 때는 탁월합니다. 하지만 회귀의 원인이 삭제된 줄에 있거나, 어떤 줄의 가장 최근 변경이 무해한 포맷 정리여서 정작 알고 싶은 변경을 가려 버릴 때는 별로 도움이 되지 않습니다. 그러면 git blame SHA^ -- path를 반복 실행하면서 히스토리를 한 겹씩 벗겨 내는 처지가 됩니다.
git bisect
bisect는 전체 히스토리에 대해 이진 탐색을 수행하여 테스트 가능한 동작을 망가뜨린 commit을 찾아냅니다. "망가졌다"가 빌드 실패나 테스트 실패를 뜻한다면 bisect가 정확히 맞는 도구이며, GUI의 그 어떤 기능도 이를 대체하지 못합니다. 하지만 "이 CSS 규칙이 언제 바뀌었지?" 같은 질문에 쓰기에는 너무 무거운 장비입니다. 단계마다 프로젝트를 checkout하고 다시 빌드할 필요는 없습니다. 그저 파일 하나가 시간에 따라 어떻게 변했는지 보고 싶을 뿐이니까요.
그래서 "이 파일의 변천을 지켜보고 싶다"에 대한 CLI의 답은 이렇습니다. log로 commit을 나열하고, show로 각 버전을 출력하고, 쌍마다 손으로 diff를 뜨고, 모든 상태를 머릿속에 유지하는 것. 명령어 하나하나는 잘 동작합니다. 문제는 워크플로우입니다.
파일 타임라인: 시각적인 해답
GitSquid는 v2.6에서 파일 타임라인을 출시했고, 무료 플랜에 포함되어 있습니다. 아이디어는 단순합니다. 파일의 변천을 commit 단위로 머릿속에서 재구성하는 대신, 화면에서 직접 지켜보는 것입니다.
우클릭으로 열기
아무 파일이나 우클릭하고 히스토리 보기를 선택하세요. 그 파일 하나에만 집중한 히스토리 뷰가 열립니다.
commit마다 눈금 하나
파일 뷰어 위에 타임라인 스트립이 자리잡고 있습니다. 파일을 건드린 commit마다 눈금이 하나씩 찍힙니다. 파일의 일생이 가로로 펼쳐지는 것이죠. commit이 3개인 파일은 차분해 보이고, 눈금이 60개인 파일은 코드를 한 줄도 읽기 전에 그 파일의 변경 빈도에 대해 무언가를 말해 줍니다.
슬라이더로 버전 훑어보기
슬라이더를 드래그하면 뷰어가 드래그하는 대로 갱신됩니다. 이것이 이 기능의 핵심입니다. 머릿속으로 diff를 떠야 하는 불연속적인 스냅샷 사이를 점프하는 것이 아니라, 파일이 변해 가는 과정을 그대로 지켜보는 것입니다. 처음 한 번 훑고 나면 스크럽이 즉각적으로 느껴지기 때문에, 히스토리를 한 번 가로지른 뒤에는 의심스러운 구간 주변을 자유롭게 오가며 변화가 일어난 정확한 commit을 좁혀 갈 수 있습니다.
마우스를 올려 누가 무엇을 바꿨는지 확인
아무 눈금에나 마우스를 올리면 그 시점의 작성자와 commit 정보가 표시됩니다. "누가 언제 작성했지?"라는 질문에 타임라인을 떠나지 않고, blame을 한 번도 실행하지 않고 답할 수 있습니다.
재생 버튼 누르기
▶를 클릭하면 GitSquid가 히스토리를 자동으로 재생합니다. 낯선 파일을 처음 살펴볼 때 직관을 쌓는 가장 빠른 방법입니다. 구조가 생겨나고, 자라나고, 리팩토링되는 과정이 눈에 보입니다. diff 30개를 읽는 것과 타임랩스를 보는 것의 차이라고 할 수 있습니다.
Snapshot 또는 Diff
헤더의 Snapshot / Diff 토글로 두 가지 뷰를 전환할 수 있습니다. 해당 commit 시점의 파일 전체 내용, 아니면 익숙한 부모 commit 대비 diff. Snapshot 모드는 "그때 파일이 어떤 모습이었지?"에 답하고, Diff 모드는 "이 commit이 정확히 무엇을 바꿨지?"에 답합니다. 회귀 사냥은 대개 Snapshot 모드에서 시작해 Diff 모드에서 끝납니다.
특정 버전으로 이동
원하는 버전을 찾았다면, 오른쪽의 세 가지 액션이 다음 단계로 안내합니다. SHA 복사는 commit 해시를 클립보드에 담아 어디서든 쓸 수 있게 하고, commit 열기는 전체 commit으로 이동해 해당 파일 외에 무엇이 함께 바뀌었는지 보여 주며, Checkout detached는 옛날 코드를 실제로 실행해 봐야 할 때 워킹 디렉터리를 정확히 그 commit으로 맞춰 줍니다.
실전 예시: CSS 회귀 찾기
구체적인 예를 들어 보겠습니다. 앱의 사이드바에서 padding이 사라졌는데, 언제부터인지 아무도 모릅니다. 파일 타임라인을 이용한 추적은 이렇게 진행됩니다.
sidebar.css우클릭 → 히스토리 보기. 타임라인에 8개월에 걸친 24개의 눈금이 표시됩니다.- 최신에서 과거 방향으로 스크럽하면서 padding 규칙을 지켜봅니다. 3분의 2 지점쯤에서 규칙이 눈에 띄게 바뀝니다. 첫 훑기 이후에는 스크럽이 즉각적이므로, 그 구간 주변에서 슬라이더를 좌우로 흔들어 값이 바뀐 정확한 눈금을 골라냅니다.
- 눈금에 마우스 올리기. 3주 전, 팀 동료가 레이아웃 리팩토링이라고 적힌 commit에서 한 변경이었습니다. 미스터리가 절반은 풀렸습니다.
- Diff로 전환. 토글이 부모 commit 대비 diff를 보여 줍니다. padding이 축약 속성으로 합쳐지는 과정에서 값 하나가 사라진 것입니다. 바로 그 회귀입니다.
- commit 열기. 전체 commit을 보니 일괄 정리 작업의 일환으로 파일 12개를 건드린 변경이었습니다. 리뷰가 소홀해지기 쉬운 종류의 변경이죠. 애초에 이런 변경이 히스토리에 어떻게 들어가야 하는지 팀에서 논쟁 중이라면 rebase vs merge를 참고하세요.
- SHA를 복사하고 수정. 문제의 commit을 특정했으니 revert하거나, 앞으로 나아가며 고치거나, cherry-pick으로 우회할 수 있습니다. 어떤 상황에 어떤 방법이 맞는지는 Git commit 되돌리는 방법 가이드에서 다룹니다.
총 소요 시간은 몇 분. SHA를 외울 필요도, 터미널 스크롤백을 발굴할 필요도 없습니다.
여전히 blame이나 bisect가 정답인 경우
타임라인이 도구 상자의 나머지를 대체하는 것은 아니며, 그렇지 않은 척하는 것은 정직하지 못한 일입니다.
- blame을 쓰세요. 이미 특정 줄을 보고 있고 그 자리에서 마지막 작성자를 알고 싶을 때. 최근에 포맷 정리를 거치지 않은 한 줄이라면 blame이 여전히 가장 빠른 길입니다.
- bisect를 쓰세요. 증상이 "빌드가 깨졌다"거나 "테스트가 실패한다"인데 어떤 파일이 원인인지 모를 때. bisect는 저장소 전체의 히스토리를 탐색하고, 타임라인은 파일 하나를 들여다봅니다. 둘은 서로 다른 질문에 답합니다.
- 타임라인을 쓰세요. 질문이 파일 하나의 변천에 관한 것일 때. 언제 바뀌었고, 누가 바꿨고, 이전에는 어떤 모습이었는지.
당신의 코드가 진화하는 모습을 지켜보세요
파일 타임라인은 GitSquid의 무료 플랜에 포함됩니다. 계정 불필요, 텔레메트리 없음, macOS와 Windows, Linux에서 네이티브로 동작합니다. 저장소를 열고, 늘 궁금했던 파일을 우클릭한 다음, 재생 버튼을 눌러 보세요.
GitSquid Free를 다운로드하고, 다음 회귀 사냥에는 SHA 목록 대신 타임라인을 사용해 보세요.