Git 기초 #5 되돌리기 — restore·reset·revert 구분
작업을 하다 보면 실수는 반드시 생깁니다. 파일을 잘못 고치고, 엉뚱한 파일을 스테이징하고, 커밋 메시지에 오타를 내고, 올리면 안 되는 커밋을 올립니다. Git은 이 모든 상황을 되돌릴 수 있습니다. 문제는 되돌리는 명령이 restore, reset, revert, amend로 여러 개라서 어느 상황에 무엇을 써야 하는지 헷갈린다는 점입니다. 이번 글의 목표는 이 혼란을 정리하는 것입니다. 기준은 하나입니다. 무엇을 어디까지 되돌리는가를 먼저 정하면 명령은 자동으로 정해집니다.
총 6편으로 구성됩니다.
- #1 Git이란 — 스냅샷 모델과 세 영역
- #2 add·commit·status — 스테이징 영역의 의미
- #3 브랜치와 머지 — fast-forward와 3-way
- #4 원격 저장소 — clone·fetch·pull·push와 origin의 정체
- #5 되돌리기 — restore·reset·revert 구분 ← 이번 글
- #6 GitHub와 첫 Pull Request
이번 글은 실무에서 가장 자주 만나는 다섯 가지 상황을 하나씩 짚고, 마지막에 상황과 명령을 표 하나로 매핑하겠습니다.
되돌리기가 헷갈리는 진짜 이유 #
1편에서 정리한 세 영역 모델을 다시 떠올려 보겠습니다. Git에는 작업 디렉터리(working directory), 스테이징 영역(staging area), 저장소(repository)라는 세 영역이 있고, 변경 사항은 이 순서로 이동합니다.
되돌리기 명령이 헷갈리는 이유는 명령마다 건드리는 영역이 다르기 때문입니다. restore는 작업 디렉터리와 스테이징 영역을 다루고, reset은 저장소의 커밋 위치까지 움직이며, revert는 커밋을 지우는 대신 새 커밋을 쌓습니다. 그래서 “무엇을 되돌리고 싶은가"라는 질문에 먼저 답해야 합니다. 아직 커밋하지 않은 수정인지, 스테이징만 한 파일인지, 방금 만든 커밋인지, 이미 푸시한 커밋인지에 따라 답이 달라집니다.
상황 1 — 커밋하지 않은 수정을 버리기: git restore #
파일을 고치다가 방향이 틀렸다는 판단이 들었습니다. 마지막 커밋 상태로 파일을 되돌리려면 git restore를 사용합니다.
# 파일 하나를 마지막 커밋 상태로 되돌리기
git restore app.py
# 작업 디렉터리 전체를 되돌리기
git restore .여기서 반드시 기억할 점이 있습니다. 커밋하지 않은 수정은 Git이 어디에도 기록해 두지 않았습니다. 즉 git restore로 버린 수정은 복구할 방법이 없습니다. 실행하기 전에 버려도 되는 수정인지 한 번 더 확인하는 습관이 필요합니다.
git status를 실행하면 Git이 상황에 맞는 되돌리기 명령을 함께 안내해 줍니다. use "git restore <file>..." to discard changes 같은 힌트가 그것입니다. 어떤 명령을 써야 할지 막막할 때는 먼저 git status를 읽는 것이 가장 안전한 출발점입니다.상황 2 — 스테이징만 해제하기: git restore –staged #
git add를 실행했는데 이 파일은 이번 커밋에 넣지 않기로 했습니다. 파일 내용은 그대로 두고 스테이징 영역에서만 내리면 됩니다.
git restore --staged app.py상황 1과 다르게 이 명령은 파일 내용을 전혀 건드리지 않습니다. 스테이징 영역에 올라간 스냅샷만 해제하고, 작업 디렉터리의 수정은 그대로 남습니다. 잃어버리는 것이 없는 안전한 명령입니다.
상황 3 — 마지막 커밋을 고치기: git commit –amend #
커밋을 만들고 보니 메시지에 오타가 있거나, 함께 들어갔어야 할 파일을 빠뜨렸습니다. 커밋을 하나 더 쌓는 대신 마지막 커밋 자체를 다시 만들 수 있습니다.
# 메시지만 고치기
git commit --amend -m "fix: 로그인 검증 오류 수정"
# 빠뜨린 파일을 포함해서 다시 커밋하기
git add missed_file.py
git commit --amend --no-edit--no-edit은 메시지를 그대로 두고 내용만 갱신하는 옵션입니다. 주의할 점은 amend가 기존 커밋을 수정하는 것이 아니라 새 커밋으로 교체한다는 사실입니다. 커밋 해시가 바뀝니다. 그래서 amend는 아직 푸시하지 않은 커밋에만 사용해야 합니다. 이미 푸시한 커밋을 amend하면 원격과 히스토리가 어긋납니다.
상황 4 — 커밋을 취소하기: git reset #
마지막 커밋 자체를 없던 일로 만들고 싶다면 git reset입니다. reset은 브랜치가 가리키는 커밋 위치를 뒤로 옮기는 명령이고, 옵션에 따라 세 영역 중 어디까지 함께 되돌리는지가 달라집니다.
# 커밋만 취소, 변경 내용은 스테이징 영역에 유지
git reset --soft HEAD~1
# 커밋과 스테이징을 취소, 변경 내용은 작업 디렉터리에 유지 (기본값)
git reset HEAD~1
# 커밋, 스테이징, 작업 디렉터리 수정까지 전부 삭제
git reset --hard HEAD~1HEAD~1은 현재 커밋의 바로 이전 커밋을 가리키는 표기입니다. 세 옵션의 차이를 세 영역 모델로 정리하면 다음과 같습니다.
| 옵션 | 저장소 (커밋) | 스테이징 영역 | 작업 디렉터리 |
|---|---|---|---|
--soft | 취소 | 유지 | 유지 |
--mixed (기본) | 취소 | 해제 | 유지 |
--hard | 취소 | 해제 | 수정 삭제 |
--soft와 --mixed는 커밋만 풀 뿐 변경 내용 자체는 남아 있으므로 안전합니다. 커밋을 쪼개서 다시 만들거나 메시지를 처음부터 다시 쓰고 싶을 때 유용합니다.
git reset --hard는 이 시리즈에서 다루는 명령 중 가장 위험합니다. 커밋하지 않은 수정까지 경고 없이 삭제하며, 그 수정은 복구할 수 없습니다. 실행 전에 git status로 잃어버릴 것이 없는지 반드시 확인하기 바랍니다. 참고로 reset으로 취소한 커밋 자체는 reflog라는 기록을 통해 한동안 복구할 수 있는데, 이 내용은 별도 글에서 다루겠습니다.상황 5 — 이미 푸시된 커밋 되돌리기: git revert #
문제가 있는 커밋을 이미 원격에 푸시했고 동료들이 그 히스토리를 받아 갔다면, reset을 쓰면 안 됩니다. 내 저장소에서 커밋을 지워도 원격과 동료의 저장소에는 그 커밋이 남아 있어서, 강제 푸시 없이는 올릴 수 없게 되고 강제 푸시를 하면 동료의 히스토리가 함께 꼬입니다.
이때 쓰는 명령이 git revert입니다. revert는 커밋을 지우지 않습니다. 대상 커밋의 변경 내용을 정확히 반대로 적용하는 새 커밋을 위에 쌓습니다.
# 특정 커밋의 변경을 반대로 적용하는 새 커밋 생성
git revert a1b2c3d
# 방금 만든 커밋을 되돌리기
git revert HEAD히스토리는 앞으로만 자라고 이미 공유된 커밋은 그대로 남으므로, 동료들은 평소처럼 pull만 하면 됩니다. 결과적으로 코드가 되돌아갔다는 사실까지 히스토리에 기록으로 남는 것도 장점입니다.
상황별 요약 #
다섯 가지 상황을 표 하나로 정리합니다.
| 상황 | 명령 | 위험도 |
|---|---|---|
| 커밋하지 않은 수정을 버리기 | git restore <파일> | 수정 복구 불가 |
| 스테이징만 해제하기 | git restore --staged <파일> | 안전 |
| 마지막 커밋의 메시지나 내용 고치기 | git commit --amend | 푸시 전에만 |
| 로컬 커밋을 취소하기 | git reset --soft/--mixed/--hard | --hard는 수정 삭제 |
| 푸시된 커밋을 되돌리기 | git revert <커밋> | 안전 |
판단 순서는 위에서 아래입니다. 아직 커밋 전이면 restore, 커밋했지만 푸시 전이면 amend나 reset, 푸시까지 했다면 revert입니다. 공유된 히스토리는 지우지 말고 새 커밋으로 덮는다는 원칙 하나만 지켜도 팀에서 생기는 Git 사고의 대부분을 피할 수 있습니다.
마무리 #
이번 글의 결론은 한 문장입니다. 되돌리기 명령은 외우는 것이 아니라, 무엇을 어디까지 되돌릴지 정하면 따라 나옵니다. 커밋 전에는 restore, 푸시 전에는 amend와 reset, 푸시 후에는 revert입니다.
다음 글인 “Git 기초 #6 GitHub와 첫 Pull Request"는 시리즈의 마지막 편입니다. 지금까지 배운 브랜치, 커밋, 푸시를 모아 협업의 표준 절차인 Pull Request를 처음부터 끝까지 만들어 보겠습니다.