본문 바로가기
목차
utils/git and github

git reset: 가장 쉬운 되돌리기. 단 공동작업에선 피하자.

by ds31x 2024. 5. 26.
728x90
반응형

https://gcapes.github.io/git-course-mace/07-undoing/

git reset

commit 이력을
특정 상태로 되돌아가기 위해(rest) 사용되는 명령어

  • repository, stage, working tree의 상태를 원하는 시점(or commit id)로 복원하는 데 사용하는 명령
  • 단, commit history의 일부를 삭제하기 때문에 remote repository 를 통해 공동 작업자들이 있는 경우엔 revert 를 대신 사용해야함.
"나만 알고 있는 역사(Local)는 맘대로 고쳐도 되지만,
남들도 알고 있는 역사(Remote)는 고치면 안 된다."

remote repositoryr로 push하기 전에는 자유롭게 reset을 해도 됨.
단, push 가 이루어진 commit 들을 삭제하는 reset은 절대 사용금지임.

3가지 mode

git reset 은 다음과 같이 3가지 모드로 동작함.


--soft : 지정한 commit 으로 reposiory를 복원시킴

  • 해당 commit 이후의 모든 commit은 repository에서 사라짐.
  • 지워진 모든 commit 들의 내용은 하나의 새로운 commit으로 만들어져 stage 에 놓여짐(staging)
  • working tree는 git reset --soft 명령을 수행하기 직전과 같은 상태임.
  • 즉, "과거의 특정 시점으로 돌아가되, 그 이후에 했던 모든 작업(커밋들)을 살려서 '커밋 바로 직전(staged)' 상태로 만들어" 가 soft 방식임.
여러 commit을 하나로 합치는 작업(Squash)을 하는데
git reset --soft 가 사용됨.

--mixed (default): 지정한 commit_id로 repository와 stage를 복원시킴.

  • 지정한 commit 이후의 모든 commit이 repository와 stage에서 사라짐.
  • working tree는 git reset --mixed 명령을 수행하기 직전과 같은 상태임
    (즉, 돌아간 commit_id 이후의 모든 변경은 working tree에만 남아있는 셈임).
  • 주로 "커밋을 했는데, 내용을 좀 더 수정해서 다시 커밋하고 싶거나, 파일을 나누어서 따로따로 커밋하고 싶을 때" 사용
    • 예를 들어, A, B, C 세 개의 파일을 한 번에 커밋했는데,
    • 이걸 취소하고 A 따로, B, C 따로 커밋하고 싶다면 --mixed로 리셋한 뒤 하나씩 add 하여 다시 커밋하는 방식임.

--hard : 지정한 commit_id로 repository, stage, working tree 모두 복원됨.

  • 즉, --hard 인 경우, 현재 working tree의 이후 추가된 파일 등 삭제됨. (주의할 것)

사용법

git reset [mode] [복원할_commit_id]
  • [mode]: --soft, --mixed, --hard 중 하나임. (기본 --mixed)
  • [복원할_commit_id]: reset하고자 하는 commit의 hash 또는 reference.

사용례00

다음은 가장 최근에 수행한 commit을 repository와 stage에서 취소시킴.
(git reset은 commit까지 이루어진 변경사항을 취소시킬 때 사용됨)

git reset HEAD^
  • HEAD^현재 commit인 HEAD 의 바로 이전 commit을 가르킴.
  • HEAD~1 은 현재 commit인 HEAD로부터 1번 전의 commit을 가르키므로 HEAD^와 같음.

기본으로 --mixed로 수정되므로,

  • 가장 최근의 commit에 대한 변경사항이 working tree에만 남아있고,
  • repository와 stage에선 삭제된다.

^(caret) 은 정확히 애기하면 해당 commit의 parent commit을 의미함: HEAD^ 은 HEAD의 parent commit을 의미.

  • merge가 이루어진 경우, 직계 branch의 부모가 ^ 이고, 합쳐진 branch의 부모는 ^2 임.
  • 직계branch의 부모의 부모는 ^^로, 부모의 부모의 부모는  ^^^로 사용함: ^^^2 는 의미가 다름.

2025.07.24 - [utils/git and github] - Relative Reference-Git-caret and tilde + Reflog Reference

 

Relative Reference-Git-caret and tilde + Reflog Reference

Git에서 commit을 가리킬 때 Absolute reference와 Relative reference, Reflog Reference 의 세가지 방식이 있음.Absolute reference: commit id를 사용함.Relative reference: tilde(~)와 caret(^)Reflog reference: at(@) 을 사용함.SHA1 으로

ds31x.tistory.com


사용례01

다음은 hash 3fd92e 가 가르키는 commit id 이후의 모든 commit history를 제거하고,
해당 commit id가 가르키는 상태로 repository, stage, working tree를 복원한다.

git reset --hard 3fd92e

사용례02

다음은 hash 3fd92e 가 가르키는 commit id 이후의 모든 commit history를 제거(취소)하고,
repository를 해당 commit id 시점으로 되돌린다.
단, 취소된 commit들에 포함되었던 모든 변경 사항은 stage 상태로 보존된다.

이는 바로 commit 가능한 상태로 staging되어있음을 의미함.

git reset --soft 3fd92e

주의 사항.

  • git reset은 commit history 자체를 변경하기 때문에, 관련된 변경에 대한 모든 기록이 삭제됨.
  • 이는 remote repository를 통해 이전 commit history를 가지고 있는 공동작업자들에게 심각한 문제를 일으키게 된다.
  • 때문에 remote repository를 통해 공동작업자가 있는 경우, 이전 commit으로 되돌리기 위해선 git revert를 이용해야 함.

절대 remote repository에 적용된 commit을 제거하는 reset은 사용해선 안된다.


2023.12.30 - [utils/git and github] - [git] revert : 특정 commit 취소하기.

 

[git] revert : 특정 commit 취소하기.

revert : 특정 commit 취소하기.revert: 되돌리다. git revertgit revert [취소할 commit id (hash value)] 는 repository에 반영된 내용을 취소해야 하는 경우 사용됨.취소를 시키고 취소된 상태의 새로운 commit을 추가

ds31x.tistory.com

 


참고: remote repository 에 reset 적용하기: git push origin main --force

--force 옵션을 통해 강제적으로 remote repository의 상태를 강제로 덮어쓸 수 있음.

remote repository의 history가 변경되기 때문에 매우 매우 신중하게 사용해야하고, 가급적 사용을 하지 않아야만 함.
(모든 팀원들과 충분히 상의 후 최후의 수단으로...)

  • 기존의 commit history 중 일부가 완전히 삭제되는 작업이므로 충분히 인지하고 수행할 것.
  • 다른 공동작업자에게 치명적인 문제를 낳을 수 있으므로 모든 작업자와 상의 후 수행해야함.
  • 수행 전 전체 내용을 백업하길 권함.

--force-with-lease 옵션을 대신 사용하길 권하는데,

이 옵션은 다른 작업자에 의한 update가 없는 상황에서만 강제 push가 수행되게 해주기 때문에 보다 실수를 줄여준다.
(즉, --force를 사용하기 전 반드시 다른 작업자에 의한 update가 없어야 함을 의미함.)


Tutorial

1. 연습용 git repository 생성.

먼저, 연습용 directory로 이동하고, 해당 directory 를 git repository로 초기화:

cd git_tutorial_reset
git init

2. sample commits 수행.

reset 테스트를 위한 몇 가지 commit을 생성:

echo "Hello" > file.txt
git add file.txt
git commit -m "Initial commit"

echo "World" >> file.txt
git add file.txt
git commit -m "Second commit"
  • 위의 방식에서 한글을 파일에 기재할 경우, cp949로 저장됨 (Notepad에서 utf-8로 열면 한글 깨짐). 
  • utf-8로 저장해야 문제가 안 생기니, chcp 65001 을 통해 현재 cmd의 인코딩을 utf-8(BOM, Byte Order Mask)로 바꾸고 실행할 것.
  • 다시 원래의 cp949로 바꾸려면, chcp 949를 사용할 것.

 

현재 commit history 를 다음으로 확인하면 위의 두 개의 commit이 보임:

git log --oneline

3. --soft 모드

--soft 모드는 HEAD 포인터만 지정된 commit (HEAD~1 or HEAD^)으로 복원하고
stage와 working tree에 복원된 이후의 변경사항이 그대로 보전됨 :

git reset --soft HEAD~1

이 명령을 실행하면

  • 마지막 commit은 commit log에서 제거된 것을 확인할 수 있음 : git status로 확인할 것.
  • 하지만, 변경 내용은 여전히 stage에 남아있음: git diff --staged 로 확인 가능!

4. 다른 테스트를 위한 commit

git commit -m "New Second commit"

위의 명령을 실행시, 현재 stage 의 내용이 repository에 commit 됨.

앞서 soft 모드였으므로 사실상 이전 reset 을 한 이후의 변경사항을 다시 repository에 적용하여 commit한 것임.

이 예에선 하나의 commit이지만, 여러 commit 이었던 경우엔 이들이 하나의 commit으로 합쳐지게 됨.


5. --mixed 모드

다음은 --mixed 모드로 HEAD 포인터를 이전 commit으로 이동시키고, stage를 초기화하지만, working tree에 변경사항을 그대로 보존하게 됨:

git reset --mixed HEAD~1

이 명령을 실행하면 마지막 commit이 사라지고, 변경 내용은 stage에서 제거되지만 여전히 working tree에 남아있음.

"HEAD^" 로 사용해도 됨(cmd.exe 에선 ceret을 쓰려면 따옴표로 묶어줘야 함.)


6. 다른 테스트를 위한 add와 commit

git add .
git commit -m "New New Second commit"

7. --hard 모드

--hard 모드는 HEAD 포인터, stage, 그리고 working tree 모두를 이전 commit 상태로 복원(변경사항이 완전히 제거됨):

git reset --hard HEAD~1

이 명령을 실행하면 마지막 commit을 포함하여 해당 변경 내용이 완전히 제거됨.


7-1. 특정 커밋으로 리셋하기

특정 commit hash를 사용하여 reset을 실행할 수도 있음:

git reset --hard <commit-hash>

<commit-hash>git log로 확인한 커밋 해시입니다.


7-2. 실수로 --hard 리셋했을 때 되돌리기 (advanced)

만약 실수로 --hard 리셋을 실행했다면, git reflog를 사용하여 이전 상태로 되돌릴 수 있음:

git reflog
git reset --hard <reflog-commit-hash>

<reflog-commit-hash>는 reflog로 확인한 이전 commit hash임.


8. remote repository와의 작업을 위한 튜토리얼 부분 시작.

--force option을 테스트하기 위해 remote repository로 연결.

git remote add origin [url_of_remote_repository]
git branch -M main
git push -u origin main

 

반드시, remote repository를 github 등에 새로 만들어 놓아야 함.


9. 테스트를 위한 작업

추가적인 commit 을 생성하고 이를 remote repository에 push.

echo "Hi" >> file.txt
git add .
git commit -m "Third commit"
echo "Korea" >> file.txt
git commit -am "Fourth commit"
git push

10. local repository를 reset!

push가 된 commit이 지워지므로 반드시 팀원들과 충분한 상의를 하고, 다른 충돌이 나지 않도록 정리한 후 해야한다.

git reset --hard HEAD~2
  • 이 명령은 HEAD를 두 개의 커밋 이전으로 이동시키고,
  • 해당 커밋들을 working tree(=작업 디렉토리)와 stage(스테이징 영역)에서 제거함.

11. --force 옵션으로 강제 push

remote repository 에 변경 사항을 강제로 push: --force 옵션을 사용

git push origin main --force
  • origin은 remote repository의 alias이고, main은 branch의 이름

--force-with-lease 옵션을 사용하면,
다른 사용자가 remote repository를 update하지 않은 경우에만 강제 push가 이루어짐.
--force보다 권장되는 방식임.

 

참고로 --force 옵션 없이 push할 경우, 다음과 같이 거절됨.

❯ git push
Enter passphrase for key '/Users/dsaint31/.ssh/id_ed25519':
To github.com:dsaint31x/git_tutorial_reset.git
 ! [rejected]        main -> main (non-fast-forward)
error: failed to push some refs to 'github.com:dsaint31x/git_tutorial_reset.git'
hint: Updates were rejected because the tip of your current branch is behind
hint: its remote counterpart. Integrate the remote changes (e.g.
hint: 'git pull ...') before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.

같이 보면 좋은 자료들

2023.12.30 - [utils/git and github] - [git] revert : 특정 commit 취소하기.

 

[git] revert : 특정 commit 취소하기.

revert : 특정 commit 취소하기.revert: 되돌리다. git revertgit revert [취소할 commit id (hash value)] 는 repository에 반영된 내용을 취소해야 하는 경우 사용됨.취소를 시키고 취소된 상태의 새로운 commit을 추가

ds31x.tistory.com

2024.01.01 - [utils/git and github] - [git] restore : 이전 상태로 되돌리기.

 

[git] restore : 이전 상태로 되돌리기.

restore는 stage와 working tree를 이전으로 되돌리는데 사용됨. reset 과 revert 가 commit이 이루어진 이후 되돌리기에 주로 사용된다면, restore 는 주로staged가 된 파일을 다시 working directory (or working tree)로

ds31x.tistory.com

2024.05.20 - [utils/git and github] - [Git] Git Summary (작성중)

 

[Git] Git Summary (작성중)

git이란2024.05.20 - [utils/git and github] - Git : 소개 git 설치 후 해줘야 하는 작업들[Git] git 설치 후 우선 해줘야 하는 작업들 (tistory.com)local repository 초기화2024.05.20 - [utils/git and github] - [Git] init : local repo

ds31x.tistory.com

 

728x90

'utils > git and github' 카테고리의 다른 글

[Git] merge: branch를 합침  (0) 2024.05.26
[Git] git 에서 branch란?  (0) 2024.05.26
git mv  (0) 2024.05.21
git rm  (0) 2024.05.21
[Git] git 설치 후 우선 해줘야 하는 작업들  (0) 2024.05.21