빌드노트
파일 이름을 바꾼 뒤 이전 커밋이 안 보이면 git log --follow로 찾는다
이름을 바꾼 파일의 과거 수정이 git log에 안 보이면 단일 파일 --follow로 확인한다. 순수 rename과 내용 수정이 겹친 rename의 실제 출력을 비교하고, 유사도 기준을 조절하거나 부모 커밋의 옛 경로에서 조회를 이어 가는 방법을 설명한다.
파일 이름을 바꾼 뒤 git log -- 새경로에 예전 수정이 나오지 않는다면, 먼저 같은 파일 하나에 --follow를 붙여 본다. 새 경로만 조회한 결과로는 옛 이름으로 수정한 커밋이 빠질 수 있다. --follow는 이름 변경 전 경로로 거슬러 올라가지만, 내용까지 크게 바뀐 커밋에서는 연결을 찾지 못할 수 있다. 그때는 이름 변경 탐지 결과를 읽고, 옛 경로가 있던 시점부터 조회를 이어 간다.
경로만 조회했을 때와 따라갔을 때
Git이 설치되어 있고, 확인할 파일이 현재 브랜치 이력에 커밋되어 있다는 조건이다. 저장소 최상위 폴더에서 실행한다. 아래 docs/guide.txt는 자기 파일의 현재 경로로 바꾼다. -- 뒤는 파일 경로를 적는 자리다.
git log --oneline -- docs/guide.txt
새 합성 저장소에서 파일 생성 → 옛 이름으로 수정 → 내용 그대로 이름 변경 → 새 이름으로 수정을 각각 커밋했다. 일반 경로 조회에는 뒤의 두 커밋만 나왔다.
f1e794c 04 edit guide
700b1c5 03 rename only
같은 파일에 --follow를 붙이고 --name-status로 경로가 어떻게 이어지는지도 보았다. -M50%는 이름 변경 탐지의 유사도 기준을 명시한 것이다.
git log --follow -M50% --oneline --name-status -- docs/guide.txt
f1e794c 04 edit guide
M docs/guide.txt
700b1c5 03 rename only
R100 docs/draft.txt docs/guide.txt
dd9cd74 02 edit draft
M docs/draft.txt
ab9a78e 01 create draft
A docs/draft.txt
위 출력은 빈 줄을 생략했다. M은 수정, A는 추가, R100은 두 경로의 내용이 같은 이름 변경으로 탐지됐다는 뜻이다. 이 예제에서는 docs/draft.txt로 경로를 바꿔 따라간 뒤 앞선 두 커밋도 보였다. 이름 변경 커밋의 해시는 700b1c5다. 해시는 각 저장소에서 달라진다.
-M만 붙이는 것과 --follow는 역할이 다르다. 같은 저장소에서 git log -M50% --oneline -- docs/guide.txt도 두 커밋만 나왔다. -M은 비교할 변경을 rename으로 탐지하고, --follow는 그 연결을 이용해 옛 경로의 이력까지 찾는다. git-log 공식 문서 (새 탭에서 열림)는 --follow를 단일 파일에만 적용한다고 명시한다. 파일 두 개를 함께 넘긴 실험은 종료 코드 128과 fatal: --follow requires exactly one pathspec으로 끝났다. 파일마다 따로 실행한다.
일반 조회부터 옛 이력이 나온다면 log.follow 설정이 켜져 있을 수도 있다. 위의 두 결과 비교는 전역·시스템 Git 설정을 배제한 실험이다.
이름 변경과 내용 수정을 한 커밋에 넣었다면
이름 변경을 탐지할 때 Git은 삭제된 경로와 추가된 경로의 내용을 비교해 충분히 비슷한 쌍을 연결한다. 공식 diffcore 설명 (새 탭에서 열림)에 나오는 처리다. 따라서 작업할 때 git mv를 썼다는 사실만으로 나중의 모든 조회에서 같은 파일로 연결되리라 기대하면 안 된다.
두 번째 합성 저장소에서는 old.txt를 new.txt로 옮기면서 내용을 크게 고쳤다. 각 줄을 LF 포함 64바이트로 맞춘 100줄 파일에서 40줄을 유지하고 나머지 60줄을 같은 길이의 다른 내용으로 바꿨다. 이때 기본 git log --follow --oneline -- new.txt는 다음 커밋 하나에서 멈췄다.
b42dbc7 02 rename and rewrite 40
연결이 끊긴 커밋을 골라 그 부모와 비교한다. 다음은 PowerShell 명령이며, 자기 저장소에서는 $rename에 확인한 커밋 해시를 넣는다. 이 비교에서는 새 경로 하나로 출력을 제한하지 않는다. 같은 커밋에서 사라진 옛 경로도 찾아야 하기 때문이다. 여기서는 병합이 없는 커밋이라 부모가 하나다.
$rename = 'b42dbc7'
git diff --name-status -M50% "${rename}^" $rename
A new.txt
D old.txt
A와 D로 따로 보인다는 사실은 이 탐지 기준에서 두 파일이 rename으로 연결되지 않았다는 뜻이다. 두 경로의 내용과 변경 목적을 확인한 뒤 기준을 낮춰 비교했다.
git diff --name-status -M40% "${rename}^" $rename
R040 old.txt new.txt
같은 두 커밋인데 이번에는 유사도 40%인 이름 변경으로 표시됐다. 이 기준으로 이력도 다시 조회했다.
git log --follow -M40% --oneline -- new.txt
b42dbc7 02 rename and rewrite 40
da7e611 01 create before 40
git-diff의 -M 설명 (새 탭에서 열림)은 기본 기준을 50%로 안내한다. 별도 파일에서 49줄·50줄·51줄을 남겨 비교했을 때도 -M50%는 각각 추가·삭제, R050, R051로 표시했다. 50줄을 남긴 파일의 기준을 -M51%로 올리자 다시 추가·삭제로 갈라졌다. 이 수치는 줄 길이까지 맞춘 입력에서 관찰한 결과다. 임의의 소스 코드에서 “절반의 줄을 바꿨으니 정확히 50%”라고 계산하는 규칙으로 쓰면 안 된다.
탐지 기준을 낮췄다는 이유만으로 두 파일의 관계가 확정되는 것도 아니다. 비슷한 파일이 여럿이면 다른 쌍이 연결될 수 있으므로, 출력의 옛 경로와 실제 내용을 대조한다. 위의 40%는 이 실험에 맞춘 값이지 모든 저장소에 적용할 권장 설정은 아니다.
연결이 불확실하면 옛 경로가 있던 부모에서 이어 본다
이름 변경 탐지를 조절해도 연결이 불확실하다면 옛 경로를 직접 조회한다. 앞에서 삭제된 old.txt가 찾던 파일이라는 것을 확인했다면, 같은 $rename 변수를 둔 상태에서 실행한다.
git log --oneline "${rename}^" -- old.txt
da7e611 01 create before 40
${rename}^는 이 예제에서 이름 변경 직전의 부모 커밋이다. 현재 작업 폴더에 old.txt가 없어도 그 시점의 경로를 조회할 수 있다. 당시 내용은 git show "${rename}^:old.txt"로 읽을 수 있다. 옛 경로가 그보다 앞에서도 바뀌었다면, 그 구간의 파일 하나에 다시 --follow를 적용해 확인한다.
이름만 바꿀 계획이라면 내용 수정과 커밋을 나누면 위의 R100처럼 연결을 확인하기 쉽다. 이미 합쳐진 커밋은 우선 탐지 결과와 옛 경로를 이용해 읽는다.
실행 환경은 Windows 11, Git 2.45.1.windows.1, PowerShell 7.6.6이었다. 검증한 이력은 병합 없는 합성 텍스트 파일이며, 2.45 계열 공식 문서와 현재 문서를 함께 확인했다. 다른 Git 버전, 병합 이력, 비슷한 파일이 대량으로 이동하는 경우는 실행하지 않았다. 2.45 문서도 --follow의 비선형 이력 한계를 명시하므로, 이 결과를 병합이 많은 저장소의 전체 이력 복원 보장으로 확대하지 않는다.