포스트

git reflog로 사라진 커밋·브랜치 복구하기

reset·rebase·브랜치 삭제 뒤 보이지 않게 된 커밋을 reflog에서 찾고, 먼저 안전한 브랜치로 보존한 뒤 필요한 상태를 복구하는 절차를 정리한다.

git reflog로 사라진 커밋·브랜치 복구하기

git reset, rebase, 브랜치 삭제 뒤 원하는 commit이 일반 git log에서 보이지 않아도 바로 사라진 것은 아닐 수 있다. Git은 로컬 reference와 HEAD가 이동한 기록을 reflog에 남기므로, 아직 정리되지 않은 commit을 찾아 다시 reference를 붙일 수 있다.

이 글의 목표는:

1
2
3
4
5
6
7
사라진 Commit 찾기
   ↓
안전한 이름으로 먼저 보존
   ↓
필요하면 Branch/HEAD 복구
   ↓
결과 확인

순서로 복구하는 것이다.

reflog는 로컬 저장소의 reference 이동 기록이다. 영구 백업이 아니며 시간이 지나 Git의 정리 대상이 되면 해당 object를 복구하지 못할 수 있다.

1. 먼저 현재 작업을 보호한다

복구 과정에서 바로 reset --hard부터 실행하지 않는다. 현재 working tree에 필요한 변경이 있다면 먼저 commit, stash 또는 별도 복사로 보존한다.

1
git status

특히 reset --hard는 현재 working tree와 index를 대상 commit 상태로 맞추므로 복구하려던 commit과 무관한 현재 변경까지 잃을 수 있다.

2. reflog에서 원하는 시점을 찾는다

1
git reflog

예를 들어 reset이나 rebase 전의 HEAD 이동 기록에서 원하는 commit SHA를 찾는다.

1
2
3
4
5
6
현재 HEAD
   ↑
reflog
   ├─ reset 전 위치
   ├─ rebase 전 위치
   └─ 이전 checkout 위치

reflog의 목적은 파일 내용을 직접 복원하는 것이 아니라 예전에 reference가 가리켰던 commit을 다시 찾는 것이다.

3. 찾은 Commit을 먼저 Branch로 보존한다

원하는 SHA를 찾았다면 바로 현재 브랜치를 강제로 이동시키기보다 임시 브랜치를 하나 만들어 commit에 이름을 붙이는 방법이 안전하다.

1
git branch recovery-work <commit-sha>

확인:

1
git log --oneline --decorate recovery-work -n 10

이제 해당 commit은 recovery-work라는 reference가 가리키므로 이후 복구 방법을 천천히 선택할 수 있다.

1
2
3
4
5
reflog에서 발견한 Commit
        ↓
git branch recovery-work
        ↓
명시적인 Reference로 보존

4. 삭제된 Branch를 다시 만들기

삭제된 브랜치의 마지막 commit을 찾았다면 원하는 이름으로 다시 branch를 만들면 된다.

1
git switch -c <branch-name> <commit-sha>

기존 Git 버전에서는:

1
git checkout -b <branch-name> <commit-sha>

도 사용할 수 있다.

브랜치 삭제는 보통 commit object 자체를 즉시 삭제하는 것이 아니라 그 commit을 가리키던 branch reference를 제거하는 것이므로, commit이 남아 있는 동안 새 reference를 붙이면 복구된다.

5. 현재 Branch 자체를 과거 상태로 되돌려야 한다면

현재 브랜치를 해당 commit으로 실제 이동시키는 것이 목적이라면, 현재 작업을 보호하고 recovery branch까지 만든 뒤 실행한다.

1
git reset --hard <commit-sha>

관계는 다음과 같다.

1
2
3
4
5
현재 Branch
    ↓ reset --hard
과거 Commit으로 Reference 이동
    +
Index / Working Tree도 그 상태로 맞춤

따라서 단순히 “사라진 commit을 다시 보고 싶다”는 목적이라면 reset --hard가 첫 선택일 필요는 없다. 먼저 branch를 붙여 보존하고, 현재 branch까지 이동해야 할 때만 reset을 선택한다.

6. 특정 파일의 과거 History를 찾는 경우

문제가 “브랜치가 사라졌다”가 아니라 특정 파일이 언제 삭제·변경됐는지 찾는 것이라면 전체 reference 복구와 목적이 다르다.

1
git log --all --full-history -- <path-to-file>

이 명령으로 모든 접근 가능한 branch/reference의 history에서 해당 파일 변경을 추적할 수 있다.

원하는 commit을 찾은 뒤 파일 하나만 복원하려면 전체 branch를 reset하기보다 해당 commit의 파일을 현재 working tree로 가져오는 방법을 고려한다.

1
git restore --source=<commit-sha> -- <path-to-file>

7. 복구 결과 확인

브랜치를 복구했다면:

1
git log --oneline --decorate --graph -n 20

현재 상태는:

1
git status

로 확인한다.

원하는 commit이 새 branch나 현재 branch에서 정상적으로 reachable한지 확인한 뒤 불필요한 임시 recovery branch를 정리한다.

정리

reflog 복구의 핵심은 reset --hard 명령 자체가 아니다.

1
2
3
4
5
6
7
8
9
10
Reference가 이동했다
   ↓
reflog에서 이전 Commit을 찾는다
   ↓
새 Branch로 먼저 보존한다
   ↓
목적에 따라
├─ 삭제 Branch 재생성
├─ 현재 Branch reset
└─ 특정 파일만 restore

먼저 commit을 다시 reachable하게 만든 뒤 어떤 상태를 복구할지 선택하는 것이 가장 안전한 접근이다.

이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.