🔥 git reset
git reset
명령어는 현재 브랜치가 가리키고 있는 커밋을 변경할 때 사용하는 강력한 도구예요. 이 명령어를 사용하면 이전 커밋으로 되돌아갈 수 있어요. 하지만 주의해서 사용해야 해요. 왜냐하면 git reset
은 커밋 히스토리를 변경하기 때문이죠.
git reset
에는 세 가지 모드가 있어요:
-soft
: 이 모드는 브랜치가 가리키는 커밋만 변경해요. 스테이징 영역과 워킹 디렉토리는 그대로 유지돼요.-mixed
: 이 모드는 브랜치가 가리키는 커밋을 변경하고, 스테이징 영역도 그에 맞게 업데이트해요. 하지만 워킹 디렉토리는 그대로 유지돼요. 이 모드가 기본 모드예요.-hard
: 이 모드는 브랜치가 가리키는 커밋, 스테이징 영역, 워킹 디렉토리까지 모두 지정한 커밋으로 되돌려요. 이 모드를 사용할 때는 매우 주의해야 해요. 왜냐하면 워킹 디렉토리의 변경 사항이 모두 사라지기 때문이죠.
예를 들어, 현재 브랜치를 이전 커밋으로 되돌리고 싶다면 다음과 같이 할 수 있어요:
# 현재 브랜치를 이전 커밋으로 되돌리기 (--mixed 모드가 기본) git reset HEAD~1 # 현재 브랜치를 특정 커밋으로 되돌리기 (--soft 모드 사용) git reset --soft 103d6c8 # 현재 브랜치를 특정 커밋으로 되돌리고, 워킹 디렉토리까지 모두 되돌리기 (--hard 모드 사용) git reset --hard 103d6c8 HEAD is now at 103d6c8 Initial commit
shell
git reset
은 매우 유용한 명령어지만, 신중하게 사용해야 해요. 특히 --hard
모드는 워킹 디렉토리의 변경 사항을 모두 삭제하기 때문에 주의가 필요해요. 만약 실수로 git reset --hard
를 사용했다면, git reflog
를 사용하여 이전 상태로 되돌릴 수 있어요.
$ git reflog
shell
git reflog
는 히스토리 히스토리로 볼 수 있는데요. 이 명령어를 사용하면 git reset --hard
로 삭제된 커밋을 포함한 모든 커밋을 볼 수 있어요. 그리고 원하는 커밋으로 브랜치를 이동시킬 수도 있죠. 현재 브랜치는 feature/signup
입니다.
$ git reflog 103d6c8 (HEAD -> feature/signup, origin/develop) HEAD@{0}: reset: moving to 103d6c84cc6d52f11993fdadd69c8d914e46917e 070ebac HEAD@{1}: reset: moving to 070ebaca5cd8eda7a17b5759dbe2b06c986e876c 2fa353f HEAD@{2}: reset: moving to HEAD~1 1ba1d9b HEAD@{3}: commit: Update README.md 2fa353f HEAD@{4}: commit: Delete README.md caf90de (main, feature/login) HEAD@{5}: checkout: moving from main to feature/signup caf90de (main, feature/login) HEAD@{6}: checkout: moving from feature/signup to main caf90de (main, feature/login) HEAD@{7}: checkout: moving from feature/login to feature/signup caf90de (main, feature/login) HEAD@{8}: checkout: moving from 160ea51d9b3e1d3fdfcb0e22ba94f223646b9724 to feature/login 160ea51 HEAD@{9}: checkout: moving from main to 160ea51d9b3e1d3fdfcb0e22ba94f223646b9724 caf90de (main, feature/login) HEAD@{10}: checkout: moving from 160ea51d9b3e1d3fdfcb0e22ba94f223646b9724 to main 160ea51 HEAD@{11}: checkout: moving from caf90dee1b4c6b3b00c0149039d34864346e90e1 to 160ea51d9b3e1d3fdfcb0e22ba94f223646b9724 caf90de (main, feature/login) HEAD@{12}: checkout: moving from 713d30794120139e6f55aba91c0e2830ada99ff0 to caf90dee1b4c6b3b00c0149039d34864346e90e1 713d307 HEAD@{13}: checkout: moving from 070ebaca5cd8eda7a17b5759dbe2b06c986e876c to 713d30794120139e6f55aba91c0e2830ada99ff0 070ebac HEAD@{14}: checkout: moving from main to 070ebaca5cd8eda7a17b5759dbe2b06c986e876c caf90de (main, feature/login) HEAD@{15}: checkout: moving from feature to main 4b450e2 HEAD@{16}: commit: Implement new feature caf90de (main, feature/login) HEAD@{17}: checkout: moving from main to feature caf90de (main, feature/login) HEAD@{18}: commit: Update README 070ebac HEAD@{19}: commit: Initial commit 713d307 HEAD@{20}: commit: Update hello.txt 160ea51 HEAD@{21}: commit: Add message 9c5b645 HEAD@{22}: commit (amend): Add hello.txt 4045db5 HEAD@{23}: commit: Add hello.txt fe5b5e0 (origin/main, origin/HEAD) HEAD@{24}: reset: moving to HEAD fe5b5e0 (origin/main, origin/HEAD) HEAD@{25}: commit: update README.md 103d6c8 (HEAD -> feature/signup, origin/develop) HEAD@{26}: clone: from github.com:codingmax-tube/git-commands-cookbook.git
shell
현재 디렉토리에서는 아래와 같은 파일이 있습니다.
$ ls -al total 24 drwxr-xr-x 6 codingmax staff 192 3 29 22:12 . drwxr-xr-x 10 codingmax staff 320 3 29 17:47 .. drwxr-xr-x 14 codingmax staff 448 3 29 22:12 .git -rw-r--r-- 1 codingmax staff 2047 3 29 17:37 .gitignore -rw-r--r-- 1 codingmax staff 1066 3 29 17:37 LICENSE -rw-r--r-- 1 codingmax staff 23 3 29 22:12 README.md
shell
이 상태에서 1ba1d9b
로 되돌려 볼게요.
$ git reset --hard HEAD@{3} HEAD is now at 1ba1d9b Update README.md
shell
디렉토리를 다시 보면 사라졌던 hello.txt 가 다시 존재하는 것을 알 수 있습니다.
% ls -al total 32 drwxr-xr-x 7 codingmax staff 224 3 29 22:21 . drwxr-xr-x 10 codingmax staff 320 3 29 17:47 .. drwxr-xr-x 14 codingmax staff 448 3 29 22:21 .git -rw-r--r-- 1 codingmax staff 2047 3 29 17:37 .gitignore -rw-r--r-- 1 codingmax staff 1066 3 29 17:37 LICENSE -rw-r--r-- 1 codingmax staff 15 3 29 22:21 README.md -rw-r--r-- 1 codingmax staff 13 3 29 22:21 hello.txt
shell
이 상태에서 다시 git reflog를 확인해 보면 아래와 같아요.
$ git reflog 1ba1d9b (HEAD -> feature/signup) HEAD@{0}: reset: moving to HEAD@{3} 103d6c8 (origin/develop) HEAD@{1}: reset: moving to 103d6c84cc6d52f11993fdadd69c8d914e46917e 070ebac HEAD@{2}: reset: moving to 070ebaca5cd8eda7a17b5759dbe2b06c986e876c 2fa353f HEAD@{3}: reset: moving to HEAD~1 1ba1d9b (HEAD -> feature/signup) HEAD@{4}: commit: Update README.md 2fa353f HEAD@{5}: commit: Delete README.md caf90de (main, feature/login) HEAD@{6}: checkout: moving from main to feature/signup caf90de (main, feature/login) HEAD@{7}: checkout: moving from feature/signup to main caf90de (main, feature/login) HEAD@{8}: checkout: moving from feature/login to feature/signup caf90de (main, feature/login) HEAD@{9}: checkout: moving from 160ea51d9b3e1d3fdfcb0e22ba94f223646b9724 to feature/login 160ea51 HEAD@{10}: checkout: moving from main to 160ea51d9b3e1d3fdfcb0e22ba94f223646b9724 caf90de (main, feature/login) HEAD@{11}: checkout: moving from 160ea51d9b3e1d3fdfcb0e22ba94f223646b9724 to main 160ea51 HEAD@{12}: checkout: moving from caf90dee1b4c6b3b00c0149039d34864346e90e1 to 160ea51d9b3e1d3fdfcb0e22ba94f223646b9724 caf90de (main, feature/login) HEAD@{13}: checkout: moving from 713d30794120139e6f55aba91c0e2830ada99ff0 to caf90dee1b4c6b3b00c0149039d34864346e90e1 713d307 HEAD@{14}: checkout: moving from 070ebaca5cd8eda7a17b5759dbe2b06c986e876c to 713d30794120139e6f55aba91c0e2830ada99ff0 070ebac HEAD@{15}: checkout: moving from main to 070ebaca5cd8eda7a17b5759dbe2b06c986e876c caf90de (main, feature/login) HEAD@{16}: checkout: moving from feature to main 4b450e2 HEAD@{17}: commit: Implement new feature caf90de (main, feature/login) HEAD@{18}: checkout: moving from main to feature caf90de (main, feature/login) HEAD@{19}: commit: Update README 070ebac HEAD@{20}: commit: Initial commit 713d307 HEAD@{21}: commit: Update hello.txt 160ea51 HEAD@{22}: commit: Add message 9c5b645 HEAD@{23}: commit (amend): Add hello.txt 4045db5 HEAD@{24}: commit: Add hello.txt fe5b5e0 (origin/main, origin/HEAD) HEAD@{25}: reset: moving to HEAD fe5b5e0 (origin/main, origin/HEAD) HEAD@{26}: commit: update README.md 103d6c8 (origin/develop) HEAD@{27}: clone: from github.com:codingmax-tube/git-commands-cookbook.git
shell
위 예제에서 HEAD@{3}
는 reflog에서 세 번째 이전 상태를 의미해요. 이렇게 하면 git reset --hard
로 삭제된 커밋으로 브랜치를 이동시킬 수 있습니다.
이 다이어그램은 git reset
의 세 가지 모드가 어떻게 작동하는지 보여줘요. 그리고 git reflog
를 사용하여 git reset --hard
로 삭제된 커밋을 복구할 수 있다는 것도 보여주고 있죠.
git reset
을 사용할 때는 항상 주의해야 해요. 특히 협업 프로젝트에서는 더욱 그래요. 다른 사람과 공유한 커밋을 git reset
으로 되돌리면 충돌이 발생할 수 있거든요. 따라서 git reset
은 로컬 브랜치에서만 사용하는 것이 좋아요. 그리고 git reflog
를 사용하여 실수로 삭제한 커밋을 복구할 수 있다는 것도 기억해 두세요!