되돌리기 총정리 — reset · revert · restore · reflog · stash
상황에 맞는 되돌리기 명령을 고르는 법. 세 개의 트리로 reset 이해하기부터 커밋 되돌리기, 파일 복원, 임시 보관까지 실무 패턴을 정리한다.
Series
Git 시리즈- 1Git 시작하기 — 가장 자주 쓰는 명령어 9개
- 2혼자 써도 따라야 할 Git Convention — 커밋 메시지부터 브랜치까지
- 3브랜치, 제대로 — 만들고 옮기고 합치고 지우기
- 4merge냐 rebase냐 — 히스토리를 어떻게 그릴 것인가
- 6되돌리기 총정리 — reset · revert · restore · reflog · stash
- 6되돌리기 총정리 — reset · revert · restore · reflog · stash
세 개의 트리 — Git이 보는 세 개의 버전
Git의 모든 되돌리기 명령을 이해하려면 먼저 "세 개의 트리"를 알아야 한다.
HEAD ← Latest commit (Repository)
│
├── Staging Area (Index — git add가 쌓는 대기실)
│
└── Working Directory (Workspace — 너가 지금 보는 파일들)
git reset 과 git restore 는 이 세 영역 사이를 오간다.
- HEAD: 현재 브랜치의 최신 커밋
- Staging Area (Index):
git add로 모은, 커밋 대기 중인 변경사항 - Working Directory: 네 로컬 디스크에 있는 실제 파일들
되돌리기를 할 때마다 "어느 영역을 되돌릴 건가"를 묻게 되는데, 이 세 트리를 알면 선택이 명확해진다.
git reset — 커밋 자체를 되돌리기
git reset 은 HEAD를 옮긴다. 옵션에 따라 staging area와 working directory도 함께 옮긴다.
현재 상태:
* c (HEAD, main)
* b
* a
git reset --soft HEAD~1 후:
* b (HEAD, main) ← HEAD만 옮김
* a
(c는 여전히 working directory·staging에 있음)
세 가지 모드
| 옵션 | HEAD | Staging | Working | 언제 쓰나 |
|---|---|---|---|---|
--soft | ✅ | — | — | 커밋 메시지 수정, 커밋을 쪼개고 싶을 때 |
--mixed (기본값) | ✅ | ✅ | — | git add 한 파일만 취소하고 싶을 때 |
--hard | ✅ | ✅ | ✅ | 커밋과 로컬 변경까지 전부 버릴 때 |
예시로 보자.
# 직전 커밋 메시지 수정 (내용은 그대로)
git reset --soft HEAD~1
git commit -m "올바른 메시지"
# 실수로 git add 한 파일 취소 (파일은 보존)
git reset HEAD myfile.txt
# 방금 커밋한 변경 전부 버리기 (위험!)
git reset --hard HEAD~1⚠️ 주의: --hard 는 돌이킬 수 없다. 확실할 때만 쓰자. 혹시 모를 땐 reflog 가 구해줄 수 있다 (아래 참조).
git revert — 커밋을 무효화하는 새 커밋 만들기
reset 은 커밋 자체를 지우는 반면, revert 는 커밋의 효과를 역으로 돌리는 새 커밋을 만든다.
현재:
* c (c가 "파일 추가" 커밋)
* b
* a
git revert c 후:
* revert c (c의 변경을 역으로)
* c
* b
* a
히스토리는 남는다. 따라서 이미 push 한 커밋을 되돌릴 땐 revert 를 쓴다.
# 직전 커밋 역돌리기
git revert HEAD
# 특정 커밋 역돌리기
git revert abc1234
# 여러 커밋 한 번에 역돌리기 (b, c 역돌림)
git revert b..c충돌이 나면 해결하고 git revert --continue 로 계속 진행한다.
reset vs revert 선택 기준:
- 내 로컬 브랜치 (아직 push 하지 않음):
reset - 이미 공유된 브랜치:
revert
git restore — 파일 단위로 되돌리기
Git 2.23부터 도입된 신문법. "파일을 특정 상태로 복원하는 것"에 특화했다.
Working directory의 파일 복원
# 현재 working directory 변경 버리고 HEAD 기준으로 복원
git restore myfile.txt
# 특정 커밋 기준으로 복원
git restore --source=abc1234 myfile.txt
# 전체 파일 복원
git restore .Staging area 취소 (옛날 git reset HEAD)
# myfile.txt를 staging에서 내려놓기 (working directory 변경은 보존)
git restore --staged myfile.txtrestore 의 장점: reset 처럼 HEAD를 움직이지 않아서 더 안전하고 의도가 명확하다.
git reflog — 실수 복구의 마지막 보루
Git은 모든 HEAD 이동 기록을 남긴다. 심지어 reset --hard 로 지운 커밋도 reflog에 남아있다.
# 최근 30개의 HEAD 이동 보기
git reflog
# 출력 예:
# abc1234 HEAD@{0}: reset: moving to abc1234
# def5678 HEAD@{1}: commit: fixed bug
# 789abcd HEAD@{2}: reset: moving to HEAD~1커밋을 되찾을 수 있다.
# 5번 전의 HEAD로 돌아가기
git reset --hard HEAD@{5}
# 또는 sha로
git reset --hard abc1234언제 쓰나? git reset --hard 후 "어? 이건 지우면 안 됐는데!" 할 때.
git stash — 작업 임시 보관
"지금 하던 작업은 아직 미완성인데 다른 브랜치로 급하게 가야 한다" — 이럴 때 쓴다.
# 현재 working directory와 staging 변경을 스택에 보관
git stash
# 또는 메시지 남기기
git stash push -m "wip: feature x"
# 스택 보기
git stash list
# 가장 최근 stash 꺼내기
git stash pop
# 특정 stash 꺼내기
git stash apply stash@{2}
# 스택에서만 꺼내고 보관은 유지
git stash apply⚠️ 주의: pop 은 꺼낸 후 스택에서 지우지만, apply 는 보관한다. 충돌이 나면 apply → 해결 → git stash drop stash@{0} 으로 수동 삭제.
실무 패턴
패턴 1: 방금 커밋한 파일 "하나만" 빼기
git reset --soft HEAD~1 # 커밋만 취소
git reset HEAD unwanted.txt # 그 파일만 unstage
git commit # 나머지로 다시 커밋패턴 2: 공유 브랜치에서 실수한 커밋 제거
git revert abc1234 # 새로운 반대 커밋 생성
git push # 히스토리 보존, 안전함패턴 3: 로컬 실험 전부 버리고 처음부터
git reset --hard origin/main # 리모트 기준으로 초기화
git clean -fd # untracked 파일까지 정리패턴 4: 어제 한 작업을 오늘 완성하기
git stash # 오늘 것 임시 보관
git checkout old-branch # 어제 브랜치로
git stash apply stash@{0} # 어제 것 꺼내기
# ... 완성 ...
git stash drop stash@{1} # 오늘 것 버리기다음 편 예고
다음 편(Git 시리즈 #7)은 GitHub 활용 — fork · PR · issue · Actions 맛보기 다룬다. 지금까지는 혼자, 또는 git pull/push 로 협업했다면, 이번엔 GitHub의 workflow를 본다. fork로 남의 프로젝트 기여하기, PR로 변경 제안하기, 이 블로그의 CI/CD 파이프라인까지.