sy/dev
Study
8 min read

되돌리기 총정리 — reset · revert · restore · reflog · stash

상황에 맞는 되돌리기 명령을 고르는 법. 세 개의 트리로 reset 이해하기부터 커밋 되돌리기, 파일 복원, 임시 보관까지 실무 패턴을 정리한다.

세 개의 트리 — Git이 보는 세 개의 버전

Git의 모든 되돌리기 명령을 이해하려면 먼저 "세 개의 트리"를 알아야 한다.

HEAD ← Latest commit     (Repository)
│
├── Staging Area        (Index — git add가 쌓는 대기실)
│
└── Working Directory   (Workspace — 너가 지금 보는 파일들)

git resetgit 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에 있음)

세 가지 모드

옵션HEADStagingWorking언제 쓰나
--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.txt

restore 의 장점: 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 파이프라인까지.

참고

Comments