commit 또는 push 했던 내용이 잘못되어서 이전 상태로 되돌려야 하는 경우는 종종 발생한다.
로컬에 commit만 하는 경우에는 쉽게 reset 기능으로 처리할 수 있지만, 원격 저장소까지 push가 된 경우엔 revert를 사용한다.
Reset
Revert
Git을 서로 다른 세 트리를 관리하는 컨텐츠 관리자로 생각하면 reset을 더 쉽게 이해할 수 있다,
트리 is '파일의 묶음'
Git은 일반적으로 세 가지 트리를 관리하는 시스템이다.
마지막 커밋 스냅샷, 다음 커밋의 부모 커밋
현재 브랜치를 가리키는 포인터이며, 브랜치는 브랜치에 담긴 커밋 중 가장 마지막 커밋을 가리킨다.
현재 브랜치 마지막 커밋의 스냅샷 / 다음 커밋의 부모
바로 다음에 커밋할 스냅샷
'Staging Area' > 사용자가 git commit 명령을 실행했을 때 Git이 처리할 것들이 있는 곳
워킹 디렉토리에서 마지막으로 checkout 한 브랜치의 파일 목록과 파일 내용으로 채우고, 이후 작업한 내용으로 index를 업데이트
git commit 명령을 실행하여 index는 새 커밋으로 변환
샌드박스 ( 다음 커밋을 위한 작업 공간 )
HEAD 와 Index는 .git 디렉토리에 저장되고, 워킹 디렉토리는 실제 파일로 존재한다.
바로 눈에 보이기 때문에 사용자가 편집하기 수월하며 commit 하기 전에는 Index에 올려놓고 얼마든지 변경할 수 있다.
특정 지점의 과거 커밋으로 이동, 이동된 이후의 커밋은 삭제된다.
사용 상 주의 요망 : 과거 커밋으로 이동하면서 그 이후 커밋은 삭제되어 되돌릴 수 없으므로 주의가 필요하다.
특히, push 후에는 다른 사람의 코드에 문제를 일으킬 소지가 있으므로 금지한다.
즉, 애초에 commit 하지 않은 것처럼 예전 커밋으로 브랜치를 옮기는 것이다.
주로 사용하는 옵션 3가지 : --mixed, --hard, --soft / 기본값은 --mixed
커밋ID는 앞자리 일부만 사용 가능하다.
#git reset [--옵션] 커밋ID
프로젝트 디렉토리에 ‘text.txt’파일을 추가 커밋
git reset --hard 이전커밋아이디 명령어를 실행한다.
‘text.txt’ 파일은 삭제되며 git status에서도 확인이 불가능하다.
프로젝트 디렉토리에 ‘text.txt’파일을 추가 커밋
git reset --hard 이전커밋아이디 명령어를 실행한다.
‘text.txt’파일은 살아있으며, Index영역에는 추가되지 않은 상태다.
프로젝트 디렉토리에 ‘text.txt’파일을 추가 커밋
다시 ‘text2.txt’ 파일을 git add text2.txt
git reset --soft 이전커밋아이디 명령어를 실행한다. > ‘text.txt’, ‘text2.txt’ 파일 모두 git status를 확인 해보면 add된 상태
--hard: reset하기 전까지 했던 staging area, working directory의 작업까지 모두 reset!
(모든 게 잘못됐어! 나 돌아갈래~ 꽃피던 때부터 정갈하게 다시 해보자!)
--mixed(default): staging area은 reset, reset하기 전까지 했던 working directory의 작업은 남겨둠.
(현재 작업물은 지우긴 싫고, 이전 버전으로 돌아가서 add할지 말지 결정해야 할 때)
--soft: reset하기 전까지 했던 staging area, working directory의 작업은 남겨둠.
(reset한 버전과 현재까지의 작업을 합쳐 새로운 버전 만들 때)
$ git reset HEAD~6 : 현재부터 6개 이전 이력으로 돌아가라라고 상대적으로 지정할 수 있다.
로컬 저장소의 커밋 히스토리가 원격 저장소의 커밋 히스토리보다 뒤에 있어 (non-fast-forward) 인 경우, push를 진행시 오류가 발생한다.
이럴 때는 강제로 덮어써야 하므로 push에 -f 또는 -force 옵션을 주어 강제로 덮어쓴다.
혼자 사용하는 브랜치가 아니므로 reset 후, 삭제될 커밋 중 다른 사람이 작성한 커밋이 있을 수 있다.
또, 커밋들을 되돌리기 전 다른 사람이 커밋들을 땡겨갔다면 다른 사람들의 로컬 저장소에는 내가 되돌린 커밋이 남아있다.
그래서 reset은 혼자만 사용하는 브랜치일 때 / 다른 사람들이 해당 브랜치를 받은 적이 없다고 확인된 경우 사용한다.
reset 주의사항을 고려한 변경하고 해당 되돌린 내용을 다른 사람들과 공유할 수 있는 기능이다.
특정 지점의 과거 커밋으로 이동, 변경 내역은 유지한다.
즉, 이력이 남기 때문에 많은 사람들과 작업할때 유용하다.
git revert 2664ce8
git revert 2664ce8..15413dc
작업을 하다가 rebase 실수 또는 잘못된 명령어나 조작 실수 등 다양한 이유로 인해 작업이 날라 가는 경우가 있다.
git의 명령어 중에 reference logs 라는 의미를 가진 reflogs 라는 옵션을 사용하여 해결한다.
위 명령어가 실행되면 나오는 화면에서 저장소 tree에 일반적으로 보이지 않는 모든 commit들을 살펴볼 수 있다.
여기서 유실된 commit을 찾은 후 해당 commit의 commitID를 찾아서 상황에 맞게 다음 명령어들을 사용하면 된다.
해당 유실된 커밋을 HEAD로 하는 tree로 돌려놓으려면 아래처럼 리셋 명령어를 실행하면된다.
해당 유실된 커밋만 현재 브랜치로 가져오려면 아래처럼 체리픽을 이용한다.