reset 명령어
리셋 명령어를 사용하면 지정된 커밋 코드로 되돌아가고 특정 커밋의 해시 값 상태로 모든 코드를 복구한다.
$ git reset 옵션 커밋ID
mixed
리셋 명령어의 기본 옵션이다.
$ git reset --mixed 커밋ID
$ git reset 커밋ID
리셋한 후 스테이지 상태까지 복원하지는 않기 때문에 수정 사항이 Unstaged 상태로 남게 된다.
따라서, 커밋하려면 add 명령을 먼저 실행한다.
soft
soft 옵션은 가장 낮은 단계의 리셋 동작이다. 지정한 커밋 위치로 복귀하면서 스테이지 영역의 상태도 같이 복구시킨다. 즉, 해당 옵션은 파일을 수정하고, add 명령어로 스테이지 영역에 올려 커밋을 실행하기 직전의 단계로 되돌린다.
soft 옵션은 단순히 HEAD 위치만 이동하는 역할을 하므로 직전의 커밋 단계로 체크아웃하라는 명령과 유사하지만 브랜치를 변경하지 않는다는 점에서 차이가 있다.
$ git reset --soft HEAD~
최신 커밋은 사라졌고 커밋하지 않은 변경 사항도 보인다.
수정 사항이 스테이지 영역에 그대로 남아있으므로 다시 커밋할 수도 있다.
git reset --soft HEAD~1 로 마지막 커밋을 되돌린 후, 다시 git commit 하는 방식은 git commit --amend 옵션과 유사하게 마지막 커밋을 수정하는 효과를 낸다.
hard
mixed 옵션과 soft 옵션은 이전 커밋으로 되돌리는 과정에서 복귀 커밋 이후의 작업들을 워킹 디렉토리에 영역에 남겨두어 수정하거나 커밋할 수 있도록 상태만 변경하기 때문에 실제로 삭제되는 내용은 없었다.
반면, hard 옵션은 리셋되는 복귀 시점의 커밋 상태와 해당 커밋의 워킹 디렉토리까지 모두 되돌리므로 커밋 이후의 모든 내용은 삭제된다. 따라서 해당 옵션은 주의해서 사용해야 한다.
$ git reset --hard HEAD~
워킹 디렉토리의 커밋하지 않은 변경 사항이 모두 삭제되었고 이전 커밋으로 완전히 리셋되었다.
커밋 합치기
리베이스 병합의 i 옵션을 사용하면 여러 커밋을 하나로 합치는 동작을 수행할 수 있었다. 리셋의 soft 옵션은 지정한 커밋 이후의 변경 사항들을 스테이징 상태로 되돌리기 때문에 다시 깃 커밋을 하여 모든 변경 사항을 하나의 커밋으로 합칠 수 있다.
복귀 시점의 변경 사항과 이후 커밋들의 변경 사항이 워킹 디렉토리와 스테이지 영역에 추가되었다.
이미 스테이징 되어있기 때문에 add 과정을 생략하고 바로 커밋하면 된다.
스테이지 리셋
add 명령어로 등록된 스테이지 영역의 파일을 다시 Unstaged 상태가 되도록 스테이징을 취소할 수 있다. 리셋 명령어 다음에 커밋 ID 대신 파일 이름을 사용하면 된다.
$ git reset 파일이름
HEAD를 명시하지 않아도 자동으로 현재 커밋이 기준이므로 위 명령은 아래 명령에서 옵션들이 축약되어 있는 것이다.
$ git reset --mixed HEAD 파일이름
다음과 같이 HEAD 대신 다른 커밋 ID를 사용할 수도 있다.
$ git reset 커밋ID 파일이름
$ git reset HEAD~n 파일이름
작업 취소
수정 작업을 완전히 취소하려면 워킹 디렉토리와 스테이지 상태를 모두 제거하여 마지막 커밋 상태로 되돌려 놓아야 한다. 따라서, 리셋할 때의 시점을 현재 HEAD를 기준으로 하면 해당 시점의 수정 작업을 모두 삭제할 수 있다.
$ git reset --hard
$ git reset --hard HEAD
reset 병합 취소
리셋으로 병합된 브랜치도 취소할 수 있다.
현재 main 브랜치에서 새로운 브랜치를 생성하고 해당 브랜치와 main 브랜치를 병합한 상황이다.
hard 옵션이 모든 변경 사항을 강제로 되돌리기 때문에 병합 커밋을 없애고 병합 전의 상태로 돌아가게 된다.
$ git reset --hard HEAD~
revert 명령어
공개된 커밋은 보통 리셋 작업을 하지 않는다. 공개한 저장소에서 커밋을 이전 상태로 되돌리려면 리버트를 사용한다. 리버트와 리셋의 차이점은 커밋의 정보 삭제 여부이다.
리버트를 사용해보기 위해 임시 커밋들을 생성한다.
취소하고자 하는 커밋을 리버트하면 에디터가 열리면서 커밋 메세지를 수정할 수 있게 된다.
$ git revert HEAD
커밋 메세지를 지정하고 에디터를 닫으면 커밋이 삭제되는 대신 취소 커밋이 생성된다.
커밋 시점을 되돌리지만 새로운 커밋이 만들어진다는 점에서 리셋과 차이가 있다.
직전의 커밋이 아닌 다른 커밋을 취소할 때는 커밋 해시 값을 지정한다.
$ git revert 커밋ID
리버트는 한 번에 커밋 하나만 취소하는게 원칙이지만 깃의 범위 지정 연산자를 사용하여 여러 커밋을 리버트할 수도 있다. 즉, 범위를 지정하더라도 실제로는 여러 개의 리버트 커밋을 순서대로 생성한다.
$ git revert 커밋ID..커밋ID
revert 병합 취소
리버트도 병합 커밋을 취소하는 데에 사용할 수 있다. 리셋은 가장 최근에 실행한 병합만 취소하지만 리버트는 히스토리가 보존되어 과거에 실행한 병합도 취소할 수 있다.
main 브랜치에서 새로운 커밋을 생성하지 않고 no fast forward 옵션으로 병합 커밋을 강제로 생성하였다.
병합 커밋은 두 개 이상의 부모 커밋을 가지는 특별한 커밋이다. 리버트로 병합이 취소되면 한 브랜치로 체크아웃해야하기 때문에 mainline 옵션으로 되돌아갈 커밋 번호를 지정한다.
병합 명령을 실행한 브랜치의 가장 최신 커밋이 첫 번째 부모로 커밋 번호 1이고 병합되는 브랜치의 가장 최신 커밋이 두 번째 부모로 커밋 번호 2가 된다.
$ git revert -m 1 병합커밋해시
$ git revert --mainline 1 병합커밋해시
커밋 메세지를 지정하고 에디터를 닫는다.
main 브랜치를 기준으로 되돌렸기 때문에 병합 커밋이 만들어지기 전의 main 브랜치 상태로 되돌린 것과 동일한 효과가 있다. 즉, 병합이 취소되고, feature 브랜치에서 추가된 내용은 main 브랜치에서 제거된다. 하지만, 커밋 기록은 보존되기 때문에, 되돌리기 작업도 히스토리로 남게 된다.