git에서 작업을 되돌리는 명령어는 2가지가 있다.
$ git reset [--option] COMMIT_ID
reset은 브랜치를 예전의 커밋으로 이동시키고 그 이후의 커밋 기록들을 삭제하는 명령어이다.
--mixed (default)
커밋 기록은 전부 삭제되지만, 파일이 변경된 내용에 대해서는 unstaged 상태로 남아 있음
--soft
--mixed
와 마찬가지로 커밋 기록은 전부 삭제되지만, 파일이 변경된 내용에 대해서는 --mixed
와는 다르게 stage에 올라간 상태로 남아 있음
--hard
커밋 기록과 파일이 변경된 내용 둘 다 삭제됨
// reset 전의 커밋은 ORIG_HEAD 이름으로 참조 가능
$ git reset --hard ORIG_HEAD
원격 저장소에 push 되어있는 커밋을 reset하게 되면 로컬 저장소의 커밋 히스토리가 원격 저장소의 커밋 히스토리보다 뒤에 있게 되므로 git push -f
로 원격 저장소에 덮어써야 한다.
그러나, 강제 push를 하기 전에 팀원들이 이미 pull을 통해 내가 되돌렸던 커밋들을 받았을 수 있다.
그렇게 되면 팀원들의 로컬 저장소에는 내가 되돌렸던 커밋들이 남아있게 되고, 팀원들이 코드를 push할 경우 내가 되돌렸던 커밋들이 다시 원격 저장소에 추가되는 일이 발생한다.
그래서
위 조건에 해당할 때 사용하는 것이 좋다.
$ git revert COMMIT_ID
커밋을 되돌리고 이 되돌린 내용을 다른 사람들과 공유하기 위해서는 revert를 써야 한다.
revert를 사용하면 새로운 커밋이 생기는데, 특정 커밋을 되돌리는 작업도 하나의 커밋으로 간주하여 커밋 히스토리에 추가하는 것이다.
reset은 명령어에 쓴 커밋ID 이후로는 싹 다 날리지만
revert는 명령어에 쓴 커밋ID만 되돌린다.
commit A -> commit B -> commit C 순서로 커밋 히스토리가 쌓여있을 때, 다시 원래대로 돌리기 위해서는 C -> B -> A 순으로 revert 해야 한다.
이렇게 되면 되돌리고 싶은 커밋 수 만큼 불필요한 revert 커밋이 생긴다.
이때 --no-commit
옵션을 이용하면 revert를 위한 하나의 커밋만 생성할 수 있다.
(revert 커밋이 자동으로 생성되지 않고 working directory와 staging area에만 변경 사항이 적용됨)
git revert --no-commit HEAD~3..
or
git revert --no-commit HEAD~3..master
// --no-commit 없으면 각각 커밋 메세지 쓰면서 진행됨
B 이후의 커밋 C가 B 변경과 연관있는 변경이면 충돌이 발생하기 때문에 충돌을 해결해야 한다. (관련없으면 잘 됨)
revert로 인해 conflict가 발생할 경우
git revert --continue # 진행하거나
git revert --abort # 취소할 수 있다.