들어가며
코딩을 하다보면 특정 시점으로 되돌아가야 하는 경우가 종종 발생합니다. 이런 경우 git restore, git revert, git reset을 사용합니다. 하지만 저 또한 정리가 제대로 안 되어서 할 때 마다 고생을 하고 시간을 많이 소요되게 되어 이번 기회에 블로그에 정리하게 되었습니다. “Git 되돌리기” 어떤 경우에 어떻게 사용하는 걸까요?
우선은 특정 commit 시점으로 되돌리는 명령어들을 테이블로 간단히 정리 한 뒤,
실제 해당 명령어들이 어떻게 작동 되는지 그림과 함께 정리해보았습니다.
Git 되돌리기 명령어 요약 정리
Git restore
git restore [파일명]
윈도우의 Ctrl+Z와 같은 기능을 하는 굉장히 유용한 명령어 입니다.
Git history가 남기 때문에 얼마든지 유용하게 사용할 수 있습니다.
옵션 | 설명 | 시나리오 | 파일 변경 | 스테이징 변경 | 커밋 변경 | Git 기록에 대한 위험도 |
---|---|---|---|---|---|---|
-s, --source | 복원할 커밋을 지정합니다 (예: 마지막 커밋의 경우 --source=HEAD ) | 특정 커밋이나 브랜치에서 변경 사항을 선택적으로 복원할 때 유용 | O | O | X | 낮음 |
--staged | 스테이징 영역에서 복원합니다. | 해당 커밋 메시지에 어울리지 않은 변경 파일들을 스테이징 하지 않는 경우 유용 | X | O | X | 낮음 |
--worktree | 작업 디렉터리에서 복원합니다. | 아직 준비되지 않은 작업 디렉터리의 변경 사항을 되돌릴 때 유용 | O | X | X | 낮음 |
Git revert
git revert [commit ID]
되돌리기를 수행하면서 새 커밋을 생성합니다.
공식적으로 코드를 되돌린 것을 commit 기록으로 명시하고 싶을 때 사용하면 좋습니다.
예를 들어 매개변수나, 로직을 변경했는데 해당 변경사항이 옳지 않음이 증명되었을 때 사용하면 좋습니다.
옵션 | 설명 | 시나리오 | 파일 변경 | 스테이징 변경 | 커밋 변경 | Git 기록에 대한 위험도 |
---|---|---|---|---|---|---|
-n, --no-commit | 되돌리기를 수행하지만 새 커밋을 생성하지 않아 추가 수정이 가능합니다. | 특정 commit의 오류를 인정하고 이를 바고 잡고 싶은 경우 유용 | O | ? | X | 낮음 |
Git reset
git reset [commit ID]
단순한 되돌리기가 아닙니다. Git의 commit 기록 자체를 지워버리고 싶은 경우 사용합니다.
원격 저장소와 연결된 경우, git commit을 지우는 것은 git log를 엉망으로 만들 수 있습니다.
웬만해서는 git restore와 git revert를 사용해서 수정을 끝내는 걸 권장합니다.
“HEAD를 지정된 커밋으로 재설정한다”의 설명에서 HEAD는 가장 마지막 commit을 의미합니다. 때문에 “HEAD를 지정된 커밋으로 재설정한다”의 의미는 git history를 해당 commit으로 되돌린다는 의미입니다.
옵션 | 설명 | 시나리오 | 파일 변경 | 스테이징 변경 | 커밋 변경 | Git 기록에 대한 위험도 |
---|---|---|---|---|---|---|
--soft | HEAD를 지정된 커밋으로 재설정합니다. 하지만 인덱스 및 실제 파일 내용들은 그대로 둡니다. | 1. 로컬에서 커밋을 완료했으나 원격 저장소로 보내기 전에 커밋을 취소하고 파일에서 추가 수정이 필요한 경우 2. 파일의 변경사항은 유지하면서 커밋만 수정하고 싶은 경우 | X | X | O | 높음 |
--mixed (기본값) | HEAD를 지정된 커밋으로 재설정하면서 인덱스도 재설정 합니다. 실제 파일 내용들은 그대로 둡니다. | 1. 로컬에서 커밋을 완료했으나 원격 저장소로 보내기 전에 커밋을 취소하고 파일에서 추가 수정이 필요한 경우 2. 파일의 변경사항은 유지하면서 커밋만 수정하고 싶은 경우 | X | O | O | 높음 |
--hard | 모든 것을 지정된 커밋으로 되돌립니다. | 빠꾸 없는 롤백….;; | O | O | O | 높음 |
Git restore 시나리오 : Ctrl + z 과 같은 git 되돌리기
다음과 같은 git history로 구성된 파일들이 있는 경우를 예로 들어보겠습니다.
![](http://3.35.198.107/wp-content/uploads/2024/03/image-60-1024x577.png)
commit log는 저장 시점에 대한 기록이기 때문에 이는 건들지 않고 특정 시점들로 되돌아갈 수 있습니다.
저장 시점이 전부 그대로 있기 때문에 언제든 가장 마지막 시점으로 되돌아올 수도 있습니다.
![](http://3.35.198.107/wp-content/uploads/2024/03/image-61-1024x577.png)
-s 옵션을 사용해서 특정 commit 시점으로 돌아갈 수 있는 걸 수 아래 화면에서 확인 할 수 있습니다.
![](http://3.35.198.107/wp-content/uploads/2024/03/image-62-1024x580.png)
-s 옵션에 HEAD
를 입력하여 commit hash(id)를 입력하지 않고도 가장 최신 지점으로 되돌아갈 수 있습니다.
![](http://3.35.198.107/wp-content/uploads/2024/03/image-63-1024x585.png)
git restore는 파일 내용 변경 뿐만 아니라 잘못된 git add를 취소 하는 기능도 가지고 있습니다.
git restore –staged [파일명]을 입력하면 잘못 스테이징된 파일을 unstage 할 수 있습니다.
관련 없는 파일들이 commit에 저장되지 않게 하는 겁니다.
![](http://3.35.198.107/wp-content/uploads/2024/03/image-64-1024x573.png)
Git revert 시나리오 : 고급 되돌리기 및 수정
특정 시점으로 돌아가 변경을 원할 시 유용합니다.
특히 공식적으로 변경 상황을 철회하고 수정을 진행하는 경우 사용하면 좋습니다.
revert 이후 commit에 무엇 때문에 철회를 하였고 수정을 하였다고 commit 메시지에 남기면 git history를 명시적으로 관리할 수 있게 되는 겁니다.
![](http://3.35.198.107/wp-content/uploads/2024/03/image-65-1024x576.png)
git revert를 사용하면 아래와 같은 메시지가 뜹니다.
여기서 내용을 추가 수정을 원한다면 추가 수정을 진행한 후에 commit을 진행합니다.
commit까지 완료해야 revert 과정이 완료되게 됩니다.
![](http://3.35.198.107/wp-content/uploads/2024/03/image-66.png)
-n 옵션이 없다면 revert 이후 바로 commit을 진행하게 됩니다.
![](http://3.35.198.107/wp-content/uploads/2024/03/image-67-1024x558.png)
![](http://3.35.198.107/wp-content/uploads/2024/03/image-68-1024x517.png)
Git revert 과정에서 conflict 발생 시
git revert 과정에서 conflict가 발생하더라도 당황하지 마시고 충돌을 확인 후 진행 방향을 설정해 주시면 됩니다.
![](http://3.35.198.107/wp-content/uploads/2024/03/image-69-1024x558.png)
![](http://3.35.198.107/wp-content/uploads/2024/03/image-70-1024x533.png)
특정 시점의 변경사항만 되돌리기
commit1 -> commit2 -> commit3 -> commit4 와 같은 순서로 commit 지점이 존재한다고 가정해봅니다.
이때 commit1, 3, 4에 대한 기록은 유지한 채, commit2에 대한 부분만 되돌린다거나 수정해야 하는 경우도 발생할 수 있습니다.
이 경우에는 git revert commit2..commit3
명령어를 이용하면 됩니다.
Git reset : 완벽한 배수진 리셋
commit log를 날리기 때문에 (정확히는 HEAD를 댕기는 거지만…) 웬만하면 사용하지 않기를…
정말 commit log를 깔끔히 하고 싶은 경우, git reset --soft
를 사용할 수 있지만 이런 경우는 git rebase
를 사용할 수도 있습니다.
뭐 어떤 경우가 되었든 git reset
은 사용하지 않기를 바라면서 일단 정리는 해봅니다.
git reset –soft
![](http://3.35.198.107/wp-content/uploads/2024/03/image-71-1024x576.png)
git reset –mixed
![](http://3.35.198.107/wp-content/uploads/2024/03/image-73-1024x585.png)
git reset –soft vs git reset –mixed
![](http://3.35.198.107/wp-content/uploads/2024/03/image-74-1024x572.png)
git reset –hard
![](http://3.35.198.107/wp-content/uploads/2024/03/image-75-1024x590.png)
git reset은 HEAD를 댕기는 거기 때문에 실제 git log에는 없는 commit id로도 다시 돌아갈 수는 있습니다.
![](http://3.35.198.107/wp-content/uploads/2024/03/image-76-1024x589.png)
마치며
git restore, git revert, git reset 만 정리하는 데도 시간이 반나절 이상 걸렸네요…ㅠㅜ
git rebase로도 git history를 수정할 수 있습니다. 하지만 git rebase는 단순히 되돌린다기 보다는 말 그대로 “새로운 지점”을 생성하기 위한 명령어에 가까운 것 같긴 합니다.
git을 특정 시점으로 되돌리는 3 가지 명령어를 정리 했지만 로컬 저장소가 아니라 원격 저장소에서 충돌이 일어난다면 git 되돌리기 혹은 수정 절차가 복잡해 질 것 같습니다.
저도 그런 경우는 많이 겪어 보지 못했지만 시간이 된다면 해당 내용도 차후에 정리해보면 좋을 것 같습니다.
참고하면 좋은 글
![git fast forward merge](https://hangbok-archive.com/wp-content/uploads/2024/03/Pasted-image-20240310205207-150x150.png)