본문 바로가기
utils/git and github

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

by ds31x 2024. 5. 26.

git reset

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

  • repository, stage, working tree의 상태를 원하는 시점(or commit id)로 복원하는 데 사용하는 명령
  • 단, commit history의 일부를 삭제하기 때문에 remote repository 를 통해 공동 작업자들이 있는 경우엔 revert 를 대신 사용해야함.

3가지 mode

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


--soft : commit을 취소시킴.

  • 최근 commit을 하기 전 상태로 돌아감.
  • 즉, stage 상태까지 복원됨.(commit만 되돌림)→ add 가 이루어진 상태로 commit 하기 바로 직전 상태임.

--mixed (default): commit과 staging을 취소시킴.

  • 최근 commit과 staging을 하기 전 상태로 돌아감.
  • stage 상태는 복원되지 않음. default. → add가 필요함.

--hard : commit, staging, working tree변경 을 모두 취소시킴.

  • 최근 commit, staging, 그리고 파일 변경을 하기전 상태로 돌아감.
  • 즉, --hard 인 경우, 파일등도 삭제됨. (주의할 것)

사용법

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

사용례00

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

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

기본으로 --mixed로 수정되므로, 가장 최근의 commit에 대한 변경사항이 working tree에만 남아있고, repository와 stage에선 삭제된다.


사용례01

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

git reset --hard 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 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"

 

현재 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에 남아있음.

4. 다른 테스트를 위한 commit

git commit -m "New Second commit"

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


5. --mixed 모드

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

git reset --mixed HEAD~1

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


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을 포함하여 해당 변경 내용이 완전히 제거됨.


8. 특정 커밋으로 리셋하기

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

git reset --hard <commit-hash>

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


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

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

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

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


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

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

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

11. 테스트를 위한 작업

추가적인 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

12. local repository를 reset!

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

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

13. --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.

'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