지식
Git
git reflog로 커밋 복구하기
git reset --hard, amend, rebase로 잃어버린 커밋을 reflog에서 찾아 복구하는 방법을 단계별로 설명한다.
지난 글에서 reflog의 개념과 구조를 살펴봤다. 이번에는 reflog를 실제로 활용해 잃어버린 커밋을 복구하는 방법을 단계별로 알아본다. git reset --hard로 커밋을 날려버렸거나 amend로 덮어썼을 때도 reflog가 있으면 대부분 살릴 수 있다.
시나리오 1: reset —hard로 커밋 날림
가장 흔한 실수다. 몇 개의 커밋이 “사라진” 것처럼 보이지만 reflog에는 남아 있다.
# 실수
git reset --hard HEAD~3 # 최근 3개 커밋 날림
# 즉시 reflog 확인
git reflog
# abc1234 HEAD@{0}: reset: moving to HEAD~3
# def5678 HEAD@{1}: commit: feat: 결제 모듈
# ghi9012 HEAD@{2}: commit: feat: 장바구니
# jkl3456 HEAD@{3}: commit: feat: 로그인
복구할 커밋의 SHA(jkl3456)나 인덱스(HEAD@{3})를 찾았다면:
# 방법 1: reset --hard로 되돌리기 (가장 간단)
git reset --hard HEAD@{3}
# 방법 2: SHA 직접 지정
git reset --hard jkl3456
시나리오 2: amend로 덮어쓴 커밋 복원
git commit --amend는 이전 커밋을 새 커밋으로 교체한다. 기존 커밋은 reflog에 남는다.
# amend 실수
git commit --amend -m "잘못된 메시지"
# reflog에서 amend 전 커밋 찾기
git reflog
# abc1234 HEAD@{0}: commit (amend): 잘못된 메시지
# def5678 HEAD@{1}: commit: 원래 올바른 메시지 ← 이게 원본
# 방법 1: reset으로 amend 전으로 되돌리기
git reset --soft HEAD@{1} # 변경사항은 staged로 유지
# 방법 2: 현재 커밋을 유지하면서 원본만 확인
git show HEAD@{1} # 원본 내용 확인
시나리오 3: 특정 커밋만 꺼내기
현재 브랜치는 그대로 두고 잃어버린 커밋의 내용만 가져오고 싶을 때.
# 복구 대상 SHA 확인
git reflog
# abc1234 HEAD@{5}: commit: feat: 중요한 기능
# 새 브랜치로 해당 커밋 체크아웃
git checkout -b recovery/important-feature abc1234
# 또는 cherry-pick으로 현재 브랜치에 가져오기
git cherry-pick abc1234
시나리오 4: 잘못된 rebase 후 복구
interactive rebase 중 실수로 커밋을 drop했거나 rebase 결과가 잘못됐을 때.
# rebase 전 상태 찾기
git reflog
# abc1234 HEAD@{0}: rebase (finish): returning to refs/heads/feature
# def5678 HEAD@{1}: rebase (pick): feat: 기능 C
# ghi9012 HEAD@{2}: rebase (pick): feat: 기능 B
# jkl3456 HEAD@{3}: rebase (start): checkout main
# mno7890 HEAD@{4}: commit: feat: 기능 C ← rebase 전 원본
# rebase 전 상태로 완전 복구
git reset --hard HEAD@{4}
# 또는 ORIG_HEAD 사용 (rebase 직전 기록)
git reset --hard ORIG_HEAD
ORIG_HEAD는 위험한 동작(merge, rebase, reset) 이전의 HEAD를 자동으로 저장하는 특수 ref다.
복구 과정 전체 예시
# 1. 문제 상황 파악
git log --oneline
# abc1234 (HEAD) init ← 최근 커밋만 있음
# 2. reflog 전체 확인
git reflog
# abc1234 HEAD@{0}: reset: moving to HEAD~5
# def5678 HEAD@{1}: commit: feat: 5번째 커밋
# ghi9012 HEAD@{2}: commit: feat: 4번째 커밋
# ...
# 3. 원하는 커밋 내용 미리 확인
git show HEAD@{1} # 변경 내용 확인
git diff HEAD HEAD@{1} # 현재와 차이 확인
# 4. 복구 실행
git reset --hard HEAD@{1}
# 5. 확인
git log --oneline
—hard vs —soft: 복구 방식 선택
# --hard: 워킹 트리·스테이징 모두 복구
git reset --hard HEAD@{3}
# --soft: 커밋 이력만 복구, 변경사항은 staged로 유지
git reset --soft HEAD@{3}
# --mixed (기본): 커밋 이력 복구, 변경사항은 unstaged로 유지
git reset HEAD@{3}
코드를 완전히 그 시점으로 되돌리려면 --hard, 커밋 구조만 되돌리고 변경사항은 남기려면 --soft를 쓴다.
주의사항
# GC 후에는 도달 불가 커밋이 사라짐
# 실수 직후 즉시 시도할 것
# push된 커밋을 reset --hard 후 force push는 팀에 영향
# 개인 브랜치가 아니라면 revert 사용 권장
# reflog는 로컬 전용
# 다른 컴퓨터에서는 reflog가 없음
지난 글: git reflog — 되돌린 이력까지 모두 기록
다음 글: git reflog로 브랜치 복구하기
읽어주셔서 감사합니다. 😊