Git 되돌리기 | "실수한 커밋 취소하고 싶어요" reset·revert·rebase 차이

Git 되돌리기 | "실수한 커밋 취소하고 싶어요" reset·revert·rebase 차이

이 글의 핵심

reset·revert·restore와 rebase로 커밋 이력을 안전하게 다루는 실전 가이드.

[Git 실전 가이드 #4] 되돌리기·rebase·정리

이전 글: Git 원격 저장소와 협업(#3)에서 push·pull·PR을 다뤘습니다.

커밋은 프로젝트의 스냅샷이라고 보시면 됩니다. 잘못 찍은 스냅샷을 고치거나, 여러 스냅샷 줄을 한 줄로 정리할 때 쓰는 대표 명령이 reset(HEAD를 옮겨 이력·스테이징·작업 디렉터리를 바꾸는 것), revert(되돌리는 내용을 담은 새 커밋을 추가해 이력을 유지하는 것), rebase(커밋을 다른 베이스 위에 다시 적용해 이력을 정리하는 것)입니다. 마지막 커밋만 취소하거나, 공유된 브랜치에서 안전하게 되돌리는 방법까지 각각의 주의점과 함께 정리했습니다.

이 글을 읽으면:

  • git reset --soft, --mixed, --hard 차이와 git restore·git switch와의 역할 분리를 이해할 수 있습니다.
  • git revertgit reset 선택 기준, push 후 되돌리기 패턴을 알 수 있습니다.
  • git rebase 원리·interactive rebase(squash, fixup, reword, edit)·rebase 충돌 해결을 다룰 수 있습니다.
  • git reset --hard·git push --force 위험과 reflog 복구, merge vs rebase·팀 규칙을 정리할 수 있습니다.

목차

  1. 되돌리기 개요
  2. git reset: 커밋·스테이징 취소
  3. git revert: 되돌리는 커밋 새로 만들기
  4. git rebase: 이력 한 줄로 정리
  5. 실무에서 주의할 점
  6. 자주 묻는 질문 (FAQ)
  7. 되돌리기 명령어 비교
  8. rebase 심화
  9. 실전 시나리오
  10. 위험한 명령어와 복구
  11. 히스토리 정리와 팀 규칙

1. 되돌리기 개요

목적명령특징
”방금 커밋”만 취소하고 수정 이어가기git reset --soft HEAD~1커밋만 취소, 스테이징·작업 디렉터리는 유지
스테이징까지 취소git reset HEAD~1 (또는 —mixed)커밋·스테이징 취소, 파일 수정 내용은 유지
완전히 그 커밋 이전으로 (위험)git reset --hard HEAD~1커밋·스테이징·파일 변경 모두 제거
이미 push한 커밋을 “취소한 것처럼” 보이게git revert <커밋>새 “반대 커밋”을 만들어 이력 유지
브랜치 이력을 한 줄로 정리git rebase main커밋을 main 끝에 다시 붙임 (이력 변경)

이미 원격에 push한 커밋을 없애고 싶을 때는 reset —hard로 되돌리면 다른 사람 이력과 꼬이므로, revert로 “취소하는 커밋”을 새로 만드는 것이 안전합니다. rebase는 이력을 바꾸므로 아직 push하지 않은 로컬 브랜치에서만 쓰는 것을 권장합니다.


2. git reset: 커밋·스테이징 취소

reset —soft

커밋만 취소하고, 스테이징 영역과 작업 디렉터리는 그대로 둡니다:

git reset --soft HEAD~1
# git reset: HEAD 포인터를 이동시키는 명령
# --soft: 커밋만 취소 (스테이징, 작업 디렉터리 유지)
# HEAD~1: 현재 HEAD의 바로 이전 커밋
#
# 동작:
# 1. HEAD를 이전 커밋으로 이동
# 2. 취소된 커밋의 변경사항은 스테이징 영역에 남음
# 3. 작업 디렉터리는 변경 없음
#
# 결과:
# git status → 변경사항이 "Changes to be committed" 상태
# git commit으로 다시 커밋 가능

사용 시나리오:

# 시나리오 1: 커밋 메시지 수정
git commit -m "Fix bug"  # 오타 발견!
git reset --soft HEAD~1
git commit -m "Fix authentication bug"  # 메시지 수정

# 시나리오 2: 파일 추가 후 재커밋
git commit -m "Add feature"
# 아, 파일 하나 빠뜨렸다!
git reset --soft HEAD~1
git add forgotten_file.js
git commit -m "Add feature"  # 모든 파일 포함

# 시나리오 3: 여러 커밋을 하나로 합치기
git reset --soft HEAD~3  # 최근 3개 커밋 취소
git commit -m "Implement user authentication"  # 하나로 합침

HEAD 표기법:

HEAD~1  # 1개 이전 커밋
HEAD~2  # 2개 이전 커밋
HEAD~3  # 3개 이전 커밋

HEAD^   # 1개 이전 커밋 (HEAD~1과 동일)
HEAD^^  # 2개 이전 커밋 (HEAD~2와 동일)

# 특정 커밋 해시로도 가능
git reset --soft abc1234

reset —mixed (기본)

커밋스테이징을 취소하고, 파일 내용 변경만 작업 디렉터리에 남깁니다. “커밋과 스테이징을 취소하고, 일부만 골라서 다시 add하고 싶을 때” 사용합니다.

git reset HEAD~1
# 또는
git reset --mixed HEAD~1

이후 git status하면 변경 파일이 “unstaged”로 보이고, git add로 다시 스테이징한 뒤 git commit할 수 있습니다.

reset —hard

커밋·스테이징·작업 디렉터리를 모두 그 커밋 이전 상태로 되돌립니다. 작업 중이던 미커밋 변경도 사라지므로 사용 전에 필요한 내용은 stash나 다른 브랜치에 백업해 두는 것이 좋습니다.

git reset --hard HEAD~1

이미 push한 브랜치에서 reset —hardforce push하면, 같은 브랜치를 쓰는 다른 사람의 이력과 충돌할 수 있어, 팀 협업 시에는 되도록 피하는 것이 좋습니다.


3. git revert: 되돌리는 커밋 새로 만들기

revert란?

revert는 특정 커밋의 변경을 반대로 적용한 새 커밋을 만듭니다:

git revert HEAD
# git revert: 커밋을 되돌리는 새 커밋 생성
# HEAD: 가장 최근 커밋을 되돌림
#
# 동작:
# 1. HEAD 커밋의 변경사항을 분석
# 2. 그 변경을 반대로 적용 (추가 → 삭제, 삭제 → 추가)
# 3. 새로운 "Revert" 커밋 생성
# 4. 이력은 그대로 유지 (기존 커밋은 남아있음)
#
# 결과:
# A → B → C (HEAD)
#      ↓
# A → B → C → C' (Revert "C", HEAD)
# C'는 C의 변경을 취소하는 내용을 담은 새 커밋

# 특정 커밋 되돌리기
git revert abc1234
# abc1234 커밋의 변경을 취소하는 새 커밋 생성

# 병합 커밋 되돌리기
git revert abc1234 -m 1
# -m 1: 첫 번째 부모를 기준으로 되돌림
# -m 2: 두 번째 부모를 기준으로 되돌림
# 병합 커밋은 부모가 2개이므로 -m 옵션 필수

reset vs revert 비교:

# reset: 이력 변경 (커밋 삭제)
# A → B → C (HEAD)
git reset --hard HEAD~1
# A → B (HEAD)  ← C 커밋이 사라짐
# 위험: 이미 push했다면 다른 사람과 이력 불일치

# revert: 이력 유지 (새 커밋 추가)
# A → B → C (HEAD)
git revert HEAD
# A → B → C → C' (HEAD)  ← C'는 C를 취소하는 커밋
# 안전: 이력이 남아있어 협업에 안전

revert 충돌 처리:

git revert HEAD
# 충돌 발생!

# 1. 충돌 파일 수정
vim conflicted_file.js

# 2. 스테이징
git add conflicted_file.js

# 3. revert 계속
git revert --continue

# 또는 revert 취소
git revert --abort

실전 사용 예시:

# 시나리오: 프로덕션에 버그 있는 커밋이 push됨
git log --oneline
# abc1234 Add buggy feature  ← 이 커밋이 문제
# def5678 Update docs
# 789abcd Initial commit

# 해결: revert로 안전하게 되돌림
git revert abc1234
# "Revert 'Add buggy feature'" 커밋 생성
git push origin main
# 이력은 유지되면서 버그 수정됨

4. git rebase: 이력 한 줄로 정리

rebase의 의미

rebase는 “현재 브랜치의 커밋들을 다른 브랜치(또는 같은 브랜치의 특정 지점) 끝에 다시 붙이는 것”입니다. 결과적으로 이력이 한 줄로 정리되어 보기 쉬워지지만, 기존 커밋 해시가 바뀌므로 이미 push한 브랜치에 rebase하면 협업 시 문제가 됩니다.

사용 예 (feature를 main 최신 위에 올리기)

git checkout feature/login
git rebase main

main이 가리키는 최신 커밋 위에 feature/login의 커밋들이 “다시 적용”됩니다. 충돌이 나면 해당 파일을 수정한 뒤 git addgit rebase —continue를 반복합니다. rebase를 취소하려면 git rebase —abort를 사용합니다.

주의사항

  • 이미 원격에 push한 브랜치를 rebase하면, 그 브랜치를 다시 push할 때 git push —force가 필요하고, 같은 브랜치를 pull하는 다른 사람의 이력이 꼬일 수 있습니다. 따라서 아직 push하지 않은 로컬 브랜치에서만 rebase하는 것이 안전합니다.
  • main/master 같은 공용 브랜치에는 rebase를 하지 않는 것이 원칙입니다.

5. 실무에서 주의할 점

  • push 전: reset, rebase로 로컬에서만 이력을 정리해도 됩니다.
  • push 후: 이미 올린 커밋을 “없던 일로” 하려면 revert로 취소 커밋을 만드는 방식이 안전합니다. force push는 팀과 합의된 경우에만 사용합니다.
  • merge vs rebase: 팀에서 “main에 병합할 때는 항상 merge”로 통일해 두면 이력이 예측 가능하고, rebase는 개인 feature 브랜치에서만 쓰는 식으로 정하면 충돌을 줄일 수 있습니다.

6. 자주 묻는 질문 (FAQ)

Q. reset —hard 한 걸 복구할 수 있나요?

A. reset —hard 직후라면 git reflog로 이전 HEAD 위치를 찾을 수 있습니다. 예: git refloggit reset --hard HEAD@{1}로 그 시점으로 되돌릴 수 있습니다. 한동안 지났거나 reflog가 정리된 경우에는 복구가 어려울 수 있으므로, 중요한 변경은 reset —hard 전에 브랜치stash로 남겨 두는 것이 좋습니다.

Q. revert와 reset의 차이는?

A. reset은 “그 커밋으로 HEAD를 옮겨서” 이력을 바꿉니다(이전 커밋이 사라져 보임). revert는 “그 커밋을 없애는 새 커밋”을 만들어 이력을 지우지 않습니다. 이미 push한 커밋을 취소할 때는 revert를 쓰는 것이 안전합니다.

Q. rebase 중 충돌이 났을 때요?

A. 충돌한 파일을 편집한 뒤 git add <파일> 하고 git rebase —continue를 실행합니다. 계속 충돌이 나면 반복하고, rebase 자체를 포기하려면 git rebase —abort로 rebase 전 상태로 돌아갈 수 있습니다.


마무리

  • reset —soft/—mixed: 커밋(과 스테이징)만 취소, 로컬에서 수정 이어갈 때.
  • reset —hard: 커밋·스테이징·작업 디렉터리 모두 되돌림. push한 브랜치에는 사용 자제.
  • revert: “취소하는 커밋”을 새로 만들어, push한 이력을 안전하게 되돌릴 때.
  • rebase: 이력을 한 줄로 정리. 아직 push 안 한 브랜치에서만 사용 권장.

한 줄 요약: reset·revert·rebase로 커밋을 되돌리고 이력을 정리할 수 있으며, 이미 push한 브랜치에서는 revert가 안전합니다. 다음으로 Git 시리즈 목차에서 다른 주제를 골라 읽어보면 좋습니다.

이전 글: Git 실전 가이드 #3: 원격 저장소와 협업

시리즈 목차: Git 시리즈 전체 목차

reset이 건드리는 세 층 (요약)

flowchart LR
  subgraph layers [한 커밋 기준]
    H[HEAD / 커밋]
    I[스테이징 Index]
    W[작업 디렉터리]
  end
  H --> I --> W

설명: --soft는 HEAD만 이동, --mixed는 스테이징까지 풀고, --hard는 세 층을 모두 베이스 커밋과 맞춥니다.


같이 보면 좋은 글 (내부 링크)

이 주제와 연결되는 다른 글입니다.

  • Git push pull 차이 | 원격 저장소·GitHub 협업·Pull Request 완벽 가이드
  • Git 브랜치와 병합 | “merge conflict 났어요” 충돌 해결 방법 (branch, merge)
  • Git 기초 입문 [#1] — 설치·커밋·브랜치·원격 저장소 한 번에

실전 팁

실무에서 바로 적용할 수 있는 팁입니다.

디버깅 팁

  • 문제가 발생하면 먼저 컴파일러 경고를 확인하세요
  • 간단한 테스트 케이스로 문제를 재현하세요

성능 팁

  • 프로파일링 없이 최적화하지 마세요
  • 측정 가능한 지표를 먼저 설정하세요

코드 리뷰 팁

  • 코드 리뷰에서 자주 지적받는 부분을 미리 체크하세요
  • 팀의 코딩 컨벤션을 따르세요

실전 체크리스트

실무에서 이 개념을 적용할 때 확인해야 할 사항입니다.

코드 작성 전

  • 이 기법이 현재 문제를 해결하는 최선의 방법인가?
  • 팀원들이 이 코드를 이해하고 유지보수할 수 있는가?
  • 성능 요구사항을 만족하는가?

코드 작성 중

  • 컴파일러 경고를 모두 해결했는가?
  • 엣지 케이스를 고려했는가?
  • 에러 처리가 적절한가?

코드 리뷰 시

  • 코드의 의도가 명확한가?
  • 테스트 케이스가 충분한가?
  • 문서화가 되어 있는가?

이 체크리스트를 활용하여 실수를 줄이고 코드 품질을 높이세요.


이 글에서 다루는 키워드 (관련 검색어)

Git, 되돌리기, reset, revert, rebase, git reset, git revert, reflog, restore, interactive rebase, force push, 커밋취소, 이력정리 등으로 검색하시면 이 글이 도움이 됩니다.


관련 글

  • Git 기초 입문 [#1] — 설치·커밋·브랜치·원격 저장소 한 번에
  • Git 브랜치와 병합 | merge conflict·branch
  • Git push pull 차이 | 원격 저장소·GitHub 협업·Pull Request 완벽 가이드
  • Git 실전 가이드 시리즈 목차 | 기초·브랜치·원격·rebase