← 블로그로 돌아가기

Git 커밃을 취소하는 방법 (작업을 잃지 않고)

tutorial git

되돌리고 싶은 commit을 했습니다. 이제 어떻게 해야 할까요?

누구에게나 일어나는 일입니다. 너무 일찍 commit하거나, 포함하지 말았어야 할 파일을 넣거나, 잘못된 메시지를 쓰거나, 코드가 맞지 않다는 것을 깨닫거나. 좋은 소식은: Git은 이를 처리하도록 설계되었습니다. 더 좋은 소식은: 대부분의 경우 작업을 잃지 않고 commit을 되돌릴 수 있습니다.

올바른 접근법은 하나의 핵심 질문에 달려 있습니다: commit이 remote에 push되었는가, 아니면 아직 로컬에 있는가? 로컬 commit은 더 많은 유연성을 제공합니다. Push된 commit은 다른 사람들이 이미 여러분의 변경사항을 pull했을 수 있으므로 더 안전한 전략이 필요합니다.

git reset으로 로컬 commit 되돌리기

commit이 아직 로컬(push되지 않은)인 경우, git reset이 가장 일반적인 도구입니다. branch 포인터를 이전 commit으로 되돌려 사실상 commit을 "취소"합니다. 그 변경사항에 어떤 일이 일어나는지는 사용하는 플래그에 따라 다릅니다.

git reset --soft: commit 되돌리기, 모든 것을 staging에 유지

git reset --soft HEAD~1

이것은 마지막 commit을 되돌리지만 모든 변경사항을 staging(인덱스)에 유지합니다. 작업 디렉토리는 영향을 받지 않습니다. git commit을 실행하지 않은 것과 같습니다 -- commit하기 직전 시점으로 돌아갑니다.

사용 시기: commit 메시지를 변경하거나, commit에 더 많은 파일을 추가하거나, commit을 더 작은 것들로 나누고 싶을 때. 코드는 괜찮고, 단지 너무 일찍 commit한 것입니다.

git reset --mixed: commit 되돌리기, 변경사항을 staging에서 제거

git reset --mixed HEAD~1

이것은 git reset의 기본 동작입니다(--mixed 플래그를 생략할 수 있습니다). commit을 되돌리고 변경사항을 staging에서 제거하지만, 파일은 작업 디렉토리에서 수정된 상태로 남습니다. 아무것도 잃지 않습니다.

사용 시기: commit에 무엇을 포함할지 다시 생각하고 싶을 때. 일부 파일만 staging하거나, 다시 commit하기 전에 변경사항을 검토하고 싶을 수 있습니다.

git reset --hard: commit 되돌리기, 모든 변경사항 삭제

git reset --hard HEAD~1

이것은 commit을 되돌리고 모든 변경사항을 영구적으로 삭제합니다. 작업 디렉토리는 이전 commit과 일치하도록 reset됩니다. 일반적인 Git 작업으로는 삭제된 변경사항을 복구할 방법이 없습니다.

사용 시기: 변경사항이 전혀 필요 없다고 확신할 때. 작동하지 않는 실험적 코드를 commit했고 깨끗한 상태로 시작하고 싶을 때. 주의해서 사용하세요.

더 이전으로 되돌리기

HEAD~1은 현재 HEAD 바로 이전 commit을 가리킵니다. 더 이전으로 갈 수 있습니다:

git reset --soft HEAD~3

이것은 마지막 세 개의 commit을 되돌리고 모든 변경사항을 staging 영역에 합칩니다. 해시로 특정 commit을 지정할 수도 있습니다:

git reset --soft a1b2c3d

git commit --amend로 마지막 commit 수정하기

마지막 commit을 완전히 되돌리지 않고 수정만 하면 되는 경우, --amend가 가장 빠른 옵션입니다:

git commit --amend -m "corrected commit message"

이것은 이전 commit을 새 것으로 대체합니다. 잊어버린 파일을 추가하는 데도 사용할 수 있습니다:

git add forgotten-file.ts
git commit --amend --no-edit

--no-edit 플래그는 원래 commit 메시지를 유지합니다. 결과는 "이런" commit 연속 대신 단일 수정된 commit입니다.

중요: reset과 마찬가지로 amend도 이력을 재작성합니다. push되지 않은 commit에만 사용하세요. push된 commit을 amend한 후 force-push하면, 원래 commit을 pull한 사람 모두에게 문제가 발생합니다.

git revert로 push된 commit 되돌리기

commit이 공유 remote에 push된 후에는 이력을 재작성해서는 안 됩니다. 다른 개발자들이 그 commit을 기반으로 작업했을 수 있습니다. 대신 git revert를 사용하세요:

git revert HEAD

이것은 대상 commit의 정확한 반대 작업을 수행하는 새 commit을 생성합니다. 원래 commit이 줄을 추가했다면 revert commit은 그것을 제거합니다. 파일을 삭제했다면 revert commit은 그것을 복원합니다. 원래 commit은 이력에 남고, revert가 그 위에 추가됩니다.

사용 시기: 이미 push된 commit을 되돌려야 할 때마다. 이력을 재작성하지 않고 추가하므로 안전합니다.

이전 commit을 revert하기

가장 최근 commit뿐만 아니라 어떤 commit이든 revert할 수 있습니다:

git revert a1b2c3d

Git은 해당 특정 commit의 변경사항만 되돌리는 revert commit을 생성하려고 시도합니다. 그 변경사항이 이후 작업과 겹치면 수동으로 해결해야 하는 충돌이 발생할 수 있습니다.

여러 commit을 revert하기

commit 범위를 revert하려면:

git revert HEAD~3..HEAD

이것은 범위 내 각 commit에 대해 개별 revert commit을 생성합니다. 단일 revert commit을 선호하면 --no-commit 플래그를 추가하고 수동으로 commit하세요:

git revert --no-commit HEAD~3..HEAD
git commit -m "revert last 3 commits"

올바른 접근법 선택하기

상황 방법 변경사항에 일어나는 일
너무 일찍 commit, 다시 staging하고 싶음 git reset --soft HEAD~1 변경사항이 staging에 유지됨
너무 일찍 commit, 다시 작업하고 싶음 git reset --mixed HEAD~1 변경사항이 작업 디렉토리에 유지됨
폐기하고 싶은 것을 commit함 git reset --hard HEAD~1 변경사항이 삭제됨
commit 메시지 수정 또는 파일 추가 필요 git commit --amend 이전 commit이 대체됨
Push된 commit을 안전하게 되돌려야 함 git revert HEAD 새 commit이 변경사항을 되돌림

실수로부터 복구하기

git reset --hard를 사용한 후 사용하지 말았어야 한다고 깨달아도, 복구할 방법이 있는 경우가 많습니다. Git은 HEAD가 가리켰던 위치의 로그를 유지하며, 이를 reflog라고 합니다:

git reflog

이것은 최근 HEAD 위치의 목록을 보여줍니다. 잃어버렸다고 생각한 commit을 찾아 그곳으로 돌아갈 수 있습니다:

git reset --hard HEAD@{2}

reflog는 안전망입니다. 항목은 기본적으로 90일 동안 보관되므로 실수로부터 복구할 충분한 시간이 있습니다.

GitSquid에서 commit 되돌리기

GitSquid는 가장 일반적인 되돌리기 작업을 간소화합니다. Commit한 직후 Cmd+Z(Windows와 Linux에서는 Ctrl+Z)를 눌러 마지막 commit을 되돌릴 수 있으며, 변경사항은 staging에 유지되어 다시 작업할 준비가 됩니다. 더 구체적인 작업의 경우, 그래프에서 아무 commit이나 오른쪽 클릭하면 컨텍스트 메뉴를 통해 reset과 revert 옵션에 접근할 수 있어, 플래그를 외우지 않고도 되돌리고 싶은 commit을 정확히 지정할 수 있습니다.

Git commit을 되돌리는 것은 스트레스가 될 필요가 없습니다. reset, amend, revert의 차이를 이해하고 상황에 맞는 것을 알면, 자신 있게 실수를 수정할 수 있습니다. 가장 중요한 구분은 간단합니다: 로컬이면 reset 또는 amend. push되었으면 revert.