/
(4)-6.GIT reset+의+역할

(4)-6.GIT reset+의+역할

[Git & Gerrit Home으로 돌아가기]

reset 의 역할

reset은 옵션에 따라 이해가 매우 힘듭니다. 유심히 잘  따져봐야 합니다.
게다가 git답지 않게 위험하기도 합니다.

  • 애매하기 때문에 정확히 알아야 git의 가장 큰 장점인 맘대로 커밋하고, 맘대로 푸쉬하는 장점을 제대로 활용할 수 있습니다.
  • reset은 복잡해 보이지만, 정해지고, 예측 가능한 방식으로 커밋 트리를 직접 조작합니다. 
  • reset은 --soft , --mixed, --hard 세 가지 옵션으로 작업을 수행합니다.

Step 1: Moving HEAD killing me --soft ly

  • reset이 가장 먼저 하는 일은 HEAD가 가리키는 포인터를 이동하는 것 입니다. 참고) checkout은 HEAD가 가르키는 커밋에 대한 포인터를 이동하는 대신'Detached HEAD' state로 이동.
  • reset은 직접적으로 HEAD가 가르키는 커밋을 변경하고, 이에 따라 SHA가 바뀌게 됩니다
  • 즉, HEAD가 'master'브랜치를 가르키고 있다면(다른 브랜치에 있지 않다면) git reset 9e5e6a4 을 수행하면, master가 9e5e6a4를 가르키게 됩니다.

    Diagram 1

    설명

    • 세번의 커밋이 있었음.
  • 그 때마다 file.txt를 수정하여 커밋 세번에
  • file.txt가 변경되어
  • 각각을 v1,v2,v3 라 하자.
  • 이때, git reset --soft HEAD~
  • 를 수행하면,
  • HEAD와 master는 9e5e6a4 (2번째 커밋)으로 이동
  • HEAD는 v2의 file.txt를 가지고 있고
  • 반면 스테이징된 파일은 아직 v3이다.
  • 또한 Working Directory에 있는 내용도 v3임.
  • 참고) git checkout HEAD~ 이면

    checkout은 HEAD가 가르키는 커밋에 대한 포인터를 이동하는 대신'Detached HEAD' state로 이동.
    이 상태는 별도의 브랜치를 만들어서 과거에 돌아간 것. git checkout -b <new-branch-name> 으로 분기하여 개발 진행 가능|
  • reset 뒤에 어떤 옵션이 붙던 reset 명령어가 수행될 때 처음하는 일은 HEAD를 옮기는 것입니다.  만약 --soft 옵션을 붙여 reset 을 수행하면 reset은 HEAD를 v2 커밋으로 옮기고, 거기서 멈출 것입니다.
  • Diagram 1을 유심히 보세요.  reset --soft는 최종 커밋을 취소합니다. 그러나 staging된 내용과 현재 작업하고 있는 내역은 최종커밋의 내용입니다.
  • 결과적으로 당신은 스테이징 영역 또는 작업 디렉토리를 변경하지 않고 HEAD만 이전 커밋 지점을 이동하고있다는 것을 의미합니다 .
  • reset HEAD~(HEAD의 부모)로 최종커밋을 취소했지만 스테이징 영역과 작업 디렉토리는 그대로 입니다.
  • 이제는 할 일은 돌아간 커밋에서 수정하고 싶은 부분을 수정하고 git commit --amend 를 수행하면 최종 커밋 수정이 완료됩니다.
  • file.txt를 수정하지 않고 git commit --amend 를 수행하면 v3내용이 커밋됩니다. (결론 : 커밋 히스토리는 v1과 v3만 남음, 내용은 v3)

Step 2: Updating the Index having --mixed feelings

  • git reset --mixed HEAD~ 를 수행하면, HEAD를 v2 커밋으로 옮깁니다.
  • 그리고, Staging안의 내용을 v2로 변경합니다. 이 상태에서 git status 실행 하면 현재 Staging된 내용을 볼 수 있습니다. INDEX와 새로운 HEAD의 차이점이 녹색으로 표시됩니다. 

    Diagram 2

    설명

     

  • 이때, git reset --mixed HEAD~
  • 를 수행하면,
  • HEAD와 master는 9e5e6a4 (2번째 커밋)으로 이동
  • HEAD는 v2의 file.txt를 가르키고 있음
  • --mixed는 스테이징된 파일을 v2로 롤백
  • 그러나 Working Directory에 있는 내용도 v3임.|
  • --mixed옵션 을 지정하면 reset이 HEAD를 옮기고(최종 커밋을 취소하고) , 이전 커밋내용을 INDEX에 이전 커밋 내용으로 롤백됩니다, 하지만 여기서 멈춥니다.
  • --mixed가 reset의 default이기 때문에 옵션을 주지 않으면 reset의 결과는 이렇게 됩니다.

Step 3: Updating the Working Directory math is --hard, let's go shopping

  • git reset --hard HEAD~ 를 수행하면, HEAD를 v2 커밋으로 옮깁니다.
  • 그리고, Staging안의 내용을 v2로 변경합니다. 이 상태에서 git status 실행 하면 현재 Staging된 내용을 볼 수 있습니다. 
  • 여기서 그치지 않고 --hard를 수행하면, Working Directory의 내용도 롤백합니다. 결국 INDEX의 내용과 Working Directory의 내용이 같아집니다.

    State

    설명

     

  • 이때, git reset --hard HEAD~
  • 를 수행하면,
  • HEAD와 master는 9e5e6a4 (2번째 커밋)으로 이동
  • HEAD는 v2의 file.txt를 가르키고 있음
  • --hard 는 스테이징된 파일을 v2로 롤백
  • Working Directory에 있는 내용도 v2로 롤백.|
  • 꼭 알아둘 점은 reset명령이 위험한 명령이 될 수 있다는 것입니다. 즉, 작업 디렉토리가 안전하지 않다는 것입니다.
  • 다른 옵션으로  reset명령어를 수행하면 쉽게 돌아갈 수 있지만, --hard 옵션은 작업 디렉토리에있는 파일을 (점검하지 않고) 겹쳐 쓰므로 위헙할 뿐더러 reset을 쉽게 취소할 수도 없습니다.
  • 이 경우 reflog 로 Git DB에 있는 것을 찾아서 롤백을 할 수는 있지만, 이 마저도 commit을 했다면 Git DB에 Overwrite가 일어나므로 복구가 불가합니다.

 

Summary

간단히 reset 명령어가 옵션에 따라 동작하는 것을 정리하면 다음과 같습니다.

  • # 1) 어떤 커밋이든 HEAD가 가리키는 모든 브랜치로 이동 (여기서 멈춤 --soft)
  • # 2) THEN,  INDEX 를  HEAD가 가르키는 커밋 내용으로 롤백 ( --hard 를 쓰지 않으면 여기서 멈춤,  Default, --mixed )
  • # 3) THEN, Working Directory를 HEAD가 가르키는 커밋 내용으로 Overwrite