Git의 주요 특징 중 하나는 "작업을 되돌리는 것"입니다. 이것은 버전 관리 시스템의 핵심 기능입니다. 여러 버전을 나누고 기록된 버전으로 돌아가고 수정하고 복구하는 것이 가능합니다.
기본적으로 작업을 되돌릴 때 사용하는 git 명령어는 3가지가 있습니다. 각자 특정 상황에서 사용되기에 잘 알아두는 것이 중요합니다. 핵심만 요약해보자면 다음과 같습니다.
- git restore: 파일을 되돌리고 싶은 경우, 사용한다.
- git revert: 커밋(commit)을 되돌리고 싶은 경우, 사용한다.
- git reset: 시간을 되돌려 어떤 시점으로 돌아가고 싶은 경우, 사용한다.
지금부터 Git에서 작업을 되돌리는 명령어들을 자세히 알아보도록 하겠습니다.
git restore
먼저, git restore 명령어는 파일을 최근 커밋 시점으로 되돌릴 때 사용됩니다. git restore 명령어에 파일 이름을 붙이면 가장 최근에 커밋이 된 상태(HEAD 커밋)로 복구가 가능합니다.
git restore <file name>
git restore 명령어도 여러 옵션을 붙일 수 있습니다. 대표적으로 source와 staged 옵션이 있습니다.
git restore --source
git restore에 --source 옵션을 붙이면 특정 파일을 특정 커밋 시점으로 복구할 수 있습니다. 사용법은 다음과 같습니다. 명령어 뒤에 커밋 해쉬와 파일명을 붙이면 됩니다.
git restore --source <commit> <file name>
git restore --staged
git restore에 --staged 옵션을 붙이면 스테이징된 파일을 다시 취소시킬 수 있습니다. 즉, git add를 취소시킬 수 있는 것입니다.
git restore --staged <file name>
git revert
git revert 명령어는 커밋한 내용을 되돌릴 때 사용하는 방법입니다. git revert 명령어를 사용하면, "버전을 되돌리되, 되돌아간 상태에 대한 새로운 버전(커밋)을 만들게 됩니다". 즉, 특정 커밋에 있었던 일이 지워지지만 기존의 버전이 삭제되진 않습니다. 또한 git revert 명령어로 되돌린 버전 이외의 버전들은 전혀 영향을 받지 않습니다.
git revert <취소할 commit>
그림을 통해 시각적으로 이해해보도록 이해해보도록 하겠습니다.
커밋들이 이렇게 쌓여있을 때, 예를 들어 Commit 3번으로 되돌아가고 싶으면 git revert 명령어를 통해 돌아갈 수 있습니다. 이때, 주의할 것은 3번 Commit 자체로 돌아가는 것이 아니라, Commit 3번의 내역을 지우고, 3번 커밋을 새로운 커밋(Revert Commit 3)으로 생성하는 것입니다. 그런데... 여기서 주의할 것이 있습니다.
git revert의 경우, 취소할 커밋들 뒤에 커밋이 쌓여있다면(취소할 커밋 시점~최근 커밋 시점), 충돌(Conflict)을 일으킬 가능성이 있습니다. 위의 그림과 같은 경우도 곧장 git revert <commit 3>을 할 경우 충돌이 일어나게 됩니다. 왜냐하면 4번 Commit이 여전히 존재하기 때문입니다.
이를 해결하기 위해서는 먼저 git revert <commit 4>를 하고, 4번 커밋을 취소하고 새로운 커밋을 만든 후, 또 git revert <commit 3>을 하여 3번 커밋을 취소해야 합니다. 이 방식은 커밋이 적을 때는 괜찮겠지만 커밋이 많이 있을 경우 상당히 번거로운 작업입니다. 충돌 없이 간편하게 git revert를 하고 싶을 때는 다음 명령어를 사용합니다.
git revert <취소하고자 하는 commit ID>..<현재 commit ID>
예를 들어 Commit 2번으로 돌아가고 싶다면, git revert <commit 2> HEAD 명령어를 사용할 수 있습니다.
충돌을 해결하는 방법은 추후에 더 자세히 다뤄보도록 하겠습니다.
git reset
git reset 명령어 또한 커밋한 내용을 되돌릴 때 사용하는 방법입니다. 그러나 git reset 명령어는 git revert 명령어와 달리 되돌아가고자 하는 시점으로 완전히 돌아가는 방식입니다. git reset 명령어를 사용하면 "특정 시점 커밋으로 돌아가고 그 시점 이후의 버전은 모두 삭제됩니다".
위의 상태의 Commit들이 있을 때, Commit 2 시점으로 돌아가고자 git reset 명령어를 사용하면 다음과 같은 상태가 됩니다.
git reset 명령어에는 크게 soft, mixed, hard 3가지 옵션을 사용할 수 있습니다. 차례대로 알아보도록 하겠습니다.
git reset --soft
git reset --soft 옵션은 "작업 디렉토리 내 변경 사항과 스테이지에 추가된 변경 사항은 유지하며, 커밋한 사실만 되돌립니다." 즉, reset을 진행하여 특정 커밋 후의 내역들은 모두 삭제하되 삭제된 커밋 내용들은 스테이징이 되어 있습니다. (git add 상태)
git reset --sort
git reset --mixed
git reset --mixed 옵션은 "작업 디렉토리 내 변경 사항은 유지하며, 스테이지와 커밋만 되돌립니다." 즉, reset을 진행하여 특정 커밋 후의 내역들은 모두 삭제하되 삭제된 커밋 내용들은 스테이징 되지 않은 상태로 남아있습니다. (unstaged 상태)
git reset --mixed
git reset에 어떠한 옵션도 붙이지 않았을 경우, 자동으로 mixed 옵션으로 reset이 됩니다.
git reset --hard
git reset --hard 옵션은 "작업 디렉토리 내 변경 사항, 스테이지, 커밋 모두 되돌립니다." 즉, reset을 진행하여 특정 커밋 후의 내역들은 모두 깡그리 다 삭제합니다. (복구할 수 있는 방법은 존재합니다. git reflog를 사용하는 방법이 있습니다.)
git reset --hard
git reset 주의사항
협업하는 경우, 보통 reset을 사용하는 것은 "지양"해야합니다. 소스코드가 갑자기 사라질 수 있기 때문에 그렇습니다. 특히나 git reset --hard 옵션을 사용하고 원격저장소에 강제로 푸쉬(push -f)하는 것은 더욱 위험합니다. (지금 이해하지 못해도 괜찮습니다.)
git reset은 가능한 혼자 진행하는 프로젝트나 다른 사람들이 사용하지 않는 브랜치에서만 사용하는 것이 좋습니다.