10. 되돌리기 — 리셋(Reset)과 리버트(Revert)

🎯 이 장의 목표
  • 커밋을 되돌리는 두 방식, 리셋과 리버트의 차이를 이해한다
  • reset의 soft / mixed / hard 옵션을 명확히 구분한다
  • revert로 안전하게 되돌리는 법을 익힌다
  • 실수했을 때 reflog로 복구하는 법을 안다

10.1 되돌리기의 두 철학: Reset vs Revert

실수한 커밋을 되돌리는 방법은 크게 두 가지이며, 철학이 완전히 다릅니다.

Reset (리셋)Revert (리버트)
방식커밋을 없던 일로 되감기되돌리는 새 커밋을 추가
이력역사를 지움/변경역사를 보존 (취소 기록 남김)
안전성위험 (공유 커밋엔 부적합)안전 (공유 커밋에도 OK)
비유타임머신으로 과거로 회귀"취소했음"을 일지에 적기
💡 팁
핵심 구분
  • 혼자만의 로컬 커밋을 정리 → Reset
  • 이미 push해서 공유된 커밋을 되돌리기 → Revert (반드시!)

10.2 리셋(Reset)의 3가지 모드

git reset은 HEAD(현재 위치)를 과거 커밋으로 옮깁니다. 이때 워킹 디렉터리와 스테이지를 어떻게 처리하느냐에 따라 세 가지 모드가 있습니다. 이것이 reset 이해의 전부입니다.

CODE
                    --soft   --mixed(기본)  --hard
커밋 이력 되돌림        ✅          ✅           ✅
스테이지 비움          ❌          ✅           ✅
워킹 디렉터리 변경      ❌          ❌           ✅ (파일도 되돌림!)

세 영역(워킹 디렉터리 / 스테이지 / 저장소)을 떠올리며 보면 명확합니다.

--soft — 커밋만 취소, 변경은 스테이지에 남김

BASH
git reset --soft HEAD~1
  • 마지막 커밋을 취소하지만, 그 변경 내용은 스테이지에 그대로 남습니다.
  • "커밋 메시지만 다시 쓰고 싶을 때", "마지막 커밋을 합치고 싶을 때" 유용합니다.
  • 바로 다시 git commit 하면 새 커밋이 됩니다.
CODE
커밋 취소 → 변경은 "git add된 상태(스테이지)"로 보존

--mixed — 커밋·스테이지 취소, 변경은 워킹에 남김 (기본값)

BASH
git reset HEAD~1          # 옵션 생략하면 --mixed
git reset --mixed HEAD~1
  • 커밋을 취소하고 스테이지도 비웁니다.
  • 변경 내용은 워킹 디렉터리에 수정된 상태로 남습니다.
  • "커밋과 add를 모두 무르고, 파일은 다시 손보고 싶을 때" 사용합니다. 가장 흔히 쓰입니다.
CODE
커밋 취소 + add 취소 → 변경은 "수정됨(Modified)" 상태로 보존

--hard — 전부 되돌림 ⚠️ (파일 내용까지!)

BASH
git reset --hard HEAD~1
  • 커밋, 스테이지, 그리고 워킹 디렉터리의 파일 내용까지 모두 과거로 되돌립니다.
  • 마지막 커밋 이후의 모든 작업이 사라집니다.
🚨 매우 위험: --hard는 커밋 안 한 작업을 복구 불가능하게 삭제합니다. 정말 다 버려도 되는지 세 번 확인하세요. (단, "커밋했던" 내용은 reflog로 살릴 수 있습니다 — 10.6 참고.)

비유로 정리

📦 이사 비유 (마지막 커밋 = 방금 싼 택배 상자)
  • --soft: 상자만 풀기 (물건은 책상 위 그대로 = 스테이지)
  • --mixed: 상자 풀고 물건도 여기저기 흩어놓기 (= 워킹 디렉터리)
  • --hard: 상자째 버리기 (물건도 전부 사라짐 😱)

10.3 리셋 실전 활용

마지막 커밋 메시지를 다시 쓰고 싶을 때

BASH
git reset --soft HEAD~1
git commit -m "올바른 메시지"

(또는 더 간단히 git commit --amend)

여러 커밋을 하나로 합치고 싶을 때

BASH
git reset --soft HEAD~3      # 최근 3개 커밋 취소(변경은 스테이지에 모임)
git commit -m "Combine three commits into one"

스테이지만 비우기 (커밋은 유지)

BASH
git reset                    # = git reset --mixed HEAD
# 또는 특정 파일만
git restore --staged file.txt

특정 커밋으로 이동

BASH
git reset --hard a1b2c3d     # 해당 커밋 상태로 완전히 되돌림(주의)

소스트리에서는 커밋을 우클릭 → "Reset current branch to this commit"을 선택하고 Soft/Mixed/Hard를 고를 수 있습니다. 시각적으로 어느 커밋으로 가는지 보여 실수를 줄여줍니다.

10.4 리버트(Revert) — 안전한 되돌리기

revert는 과거를 지우지 않습니다. 대신 "그 커밋의 변경을 정반대로 적용하는 새 커밋"을 추가합니다. 역사가 그대로 남으므로 협업에 안전합니다.

gitGraph
    commit id: "A"
    commit id: "B"
    commit id: "C (되돌릴 대상)"
    commit id: "C' (C의 반대)" type: REVERSE
revert는 C를 지우지 않습니다. C의 변경을 정반대로 적용한 새 커밋 C'를 추가할 뿐이라, C는 이력에 그대로 보존됩니다.
BASH
git revert HEAD              # 마지막 커밋 되돌리기
git revert a1b2c3d           # 특정 커밋 되돌리기
  • 실행하면 되돌림 커밋의 메시지 편집기가 열립니다(기본값 OK).
  • 결과적으로 코드는 그 커밋 이전 상태가 되지만, 이력에는 "되돌렸다"는 기록이 남습니다.
💡 팁
왜 push한 커밋엔 revert를 쓸까? reset은 역사를 지워서, 이미 그 커밋을 받아간 동료와 어긋납니다. 반면 revert는 정상적인 "새 커밋 추가"라서 누구와도 충돌 없이 공유됩니다. 공유된 코드를 되돌릴 땐 무조건 revert.

병합 커밋 되돌리기

병합 커밋은 부모가 둘이라, 어느 쪽을 기준으로 되돌릴지 지정해야 합니다.

BASH
git revert -m 1 <병합커밋해시>      # 보통 1번 부모(병합 받은 쪽) 기준

여러 커밋을 한 번에, 커밋은 만들지 않고 모아서 처리할 수도 있습니다.

BASH
git revert --no-commit HEAD~2..HEAD   # 변경만 모으고
git commit -m "Revert recent changes" # 한 번에 커밋

소스트리에서는 커밋 우클릭 → "Reverse commit"으로 동일하게 실행됩니다.

10.5 작업·병합 취소 빠른 참조

하고 싶은 것명령
워킹 디렉터리 수정 버리기git restore <file>
스테이지에서 내리기git restore --staged <file>
마지막 커밋 취소(변경 유지)git reset --soft HEAD~1
마지막 커밋+add 취소(변경 유지)git reset HEAD~1
마지막 커밋 완전 폐기git reset --hard HEAD~1 ⚠️
진행 중 병합 취소git merge --abort
진행 중 리베이스 취소git rebase --abort
공유된 커밋 안전하게 되돌리기git revert <commit>

10.6 실수했을 때의 구원자 — git reflog

"reset --hard로 커밋을 날렸어요! 끝장인가요?" 대부분 아닙니다. Git은 HEAD가 움직인 모든 기록reflog에 남겨둡니다.

BASH
git reflog
CODE
a1b2c3d (HEAD -> main) HEAD@{0}: reset: moving to HEAD~1
e5f6g7h HEAD@{1}: commit: Important work I thought I lost
c3d4e5f HEAD@{2}: commit: Earlier work

날린 줄 알았던 커밋(e5f6g7h)이 보입니다. 그곳으로 돌아가면 복구됩니다.

BASH
git reset --hard e5f6g7h      # 잃어버린 커밋으로 복귀
# 또는 안전하게 새 브랜치로
git switch -c recovered e5f6g7h
💡 팁
reflog는 Git의 블랙박스입니다. "커밋했던" 내용은 웬만하면 reflog로 살릴 수 있습니다(기본 90일 보관). 단, 한 번도 커밋한 적 없는 변경(워킹 디렉터리에만 있던 것)은 reflog로도 못 살리니, reset --hardgit clean 전에는 항상 신중하세요.

10.7 리셋 작업 시 주의사항 정리

  • --hardgit clean은 되돌릴 수 없는 작업을 포함한다. 실행 전 git status로 무엇이 사라질지 확인.
  • 이미 push한 커밋은 reset 하지 말 것. 공유 이력엔 revert를 사용.
  • 헷갈리면 일단 현재 상태를 새 브랜치로 백업: git switch -c backup.
  • 막히면 git reflog를 떠올린다.

10.8 이 장에서 배운 것 (요약)

  • Reset: 역사를 되감음(로컬 정리용). Revert: 되돌림 커밋 추가(공유 안전)
  • reset 3모드: soft(커밋만)/mixed(커밋+add, 기본)/hard(전부, 위험)
  • 공유된(push된) 커밋을 되돌릴 땐 반드시 revert
  • 병합/리베이스 중단은 --abort
  • git reflog로 잃어버린 커밋 복구 (단, 커밋한 적 있는 것만)

✍️ 확인 문제

  1. reset --soft, --mixed, --hard는 각각 어디까지 되돌리나요?
  2. 동료와 공유 중인 main의 잘못된 커밋을 되돌릴 때 reset과 revert 중 무엇을 써야 하나요?
  3. reset --hard로 커밋을 날렸습니다. 가장 먼저 시도할 명령은?
여기까지가 3부(합치기와 되돌리기)입니다. 다음 단계(마지막)에서는 버전을 표시하고 배포하는 태그(Tag)를 다룹니다.