ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Git - 6.1 Git의 원리(part.2) Branch, Reset, Checkout의 원리
    STUDY/Git & Github 2021. 1. 7. 15:56

    #이 글은 "생활코딩" '프로젝트 관리' 강의를 기반으로 정리한 글 입니다. 

     

    이번에는 git의 branch, reset, checkout의 원리에 대해 알아보겠습니다. 

     

    git branch의 원리

    새로운 파일을 생성한 후, git init을 하면 아래와 같은 폴더들이 생성됩니다. 이중에서 오늘은 ./HEAD 폴더에 대해 살펴보겠습니다. 

     

    git init 이후 생성되는 디렉토리들

     

    HEAD 는 아래와 같이 refs/heads/master 를 가리키고 있고, 초기에 아무것도 하지 않은 경우에는 아래와 같이 비어있습니다.  이제 f1.txt 파일을 생성하고, commit 한 이후에는 어떤 변화가 생기는지 확인해보도록 하겠습니다. 

     

    HEAD의 초기 상태

    f1.txt를 commit 한 후에, HEAD 를 보면 가장 최근에 생성한 commit을 가리키고 있습니다. (왼쪽 사진)

    f1.txt을 수정한 후에 새로운 버전의 commit을 만들면, 아래의 오른쪽 사진과 같이 HEAD가 가리키는 commit이 변경된 것을 볼 수 있습니다. 즉, HEAD의 refs/heads/master는 가장 최신 버전의 commit을 가리키고 있습니다. refs/heads/master 는 위에서 말했듯이 최신 버전의 commit 아이디를 가지고 있습니다. 그리고 그 이전 버전의 commit은 parent를 통해 확인 할 수 있기 때문에, git log 명령어를 통해 우리는 현재 버전 뿐 아니라 이전 버전의 commit들 또한 확인할 수 있습니다.

     

    HEAD의 모습

     

    이번에는 branch를 생성하고, 생성 이후에 .git 파일에는 무슨 변화가 생기는지를 확인해보며 branch의 원리에 대해 알아보겠습니다.

    git bracnh exp 로 exp branch를 생성하면, ./refs/heads/exp  라는 디렉토리가 생성되고 안에는 branch를 생성할 당시의 master의 최신 commit 정보가 들어있습니다.

     

    branch 생성시 만들어지는 폴더

     

    사실 알고보면 branch는 그저 하나의 파일일 뿐인 것이죠!  따라서 이런 동작도 실행할 수가 있습니다.

    branch를 삭제하는git branch -d exp 대신, 파일을 삭제하는 명령어를 통해서도 branch를 삭제할 수 있습니다.

     

    rm 명령어를 통해 branch 삭제

    그리고 vi 편집기를 이용해 branch를 생성할 수도 있습니다. branch는 파일이기 때문이죠!

    vi .git/refs/heads/exp 에 최신 commit 버전의 id를 저장해주면 아래처럼 새로운 branch가 생성된답니다!

    vi 편집기를 이용해 branch 생성

     

    지금까지 branch와 HEAD 파일에 대해 알아보았습니다. 그렇다면 git log할 때 보이던 저 HEAD 가 어떤 의미인지 이제 아시겠나요? 

    (HEAD -> master, exp) 는 현재 checkout 한 branch가 어떤 것인가 를 알려주는 약속된 기호라고 할 수 있습니다. 그리고 이 표시가 되어있는 commit이 현재의 최신 commit 이라는 것을 알려줍니다.

     

    (HEAD -> master, exp)의 의미

     

    git reset과 checkout 의 원리

    우선 reset과 checkout의 원리에 대해 실습해보기 이전에 먼저 기본적인 세팅을 좀 해놔야합니다. 새로운 디렉토리를 초기화 하고, f1.txt를 하나 생성하여 4개의 commit 버전을 우선 만들어준 후, 실습을 진행해보도록 하겠습니다. 최종적으로 오른쪽 사진과 같이 만들면 실습 준비 완료입니다.

     

    reset, checkout의 원리 실습 전, 실습 환경 셋팅

    앞서 reset에 대해 잠깐 언급한 적이 있습니다.  Git - 3. 변경사항 확인과 과거의 버전으로 돌아가기(reset), 매뉴얼 보는 법

    이번에는 이 reset의 원리에 대해 조금 더 자세하게 알아보려고 합니다. 

     

    현재 우리의 최신 commit 버전은 'a549af', commit 메세지는 "4"입니다. 이 버전을 버리고 이전 버전으로, 즉 commit 메세지가 "3"인 버전으로 돌아가기 위해선, git reset [commit "3"의 ID]  를 통해 이전 버전으로 갈 수 있습니다. reset을 진행한 이후, refs/heads/master 가 가리키는 commit을 확인하면 아래와 같습니다. 위에서  refs/heads/master는 최신 버전의 commit을 가리킨다는 것을 배웠으니 왜  refs/heads/master가 변경되었는지 이해가 되실거라고 생각합니다.

     

    reset 은 checkout 하고 있는 branch가 가리키는 최신 commit을 바꾸는 행위라고도 할 수 있는 것이지요.

     

    reset 이전의 최신 commit                                                              reset 이후 최신 commit

     

    reset 이전과 이후의  refs/heads/master

    그렇다면 reset 이후에, 4번 버전 commit은 삭제된 것일까요? 사실 그렇지 않습니다. Git은 정말 웬만한 정보들을 실제로 삭제하지는 않습니다. 그렇다면 이 4번 버전에 대한 정보는 어디에서 찾아볼 수 있을까요?

     

    바로 ./ORIG_HEAD  에서 확인할 수 있습니다. ORIG_HEAD 디렉토리는 쉽게 말하면, 위험한 명령을 실행하기 이전에 우선 정보를 기록해두는 디렉토리라고 할 수 있습니다. 그래서 이 ORIG_HEAD 파일을 이용하여 reset을 취소할 수도 있습니다.

    git reset --hard ORIG_HEAD 를 사용하면 됩니다. 

     

    삭제한 정보가 저장되어 있는 ORIG_HEAD(왼), ORIG_HEAD를 통해 reset 취소(오)

     

    또한 ./logs/refs/heads/master 에서도 확인이 가능합니다. ./logs/refs/heads/master는 master branch에서 일어나는 일들을 기록하는 디렉토리입니다. ORIG_HEAD 보다 더 자세한 정보를 알수 있습니다. 또한 ./logs/refs/heads/master는 git reflog 를 통해서도 확인할 수 있습니다.

    ./logs/refs/heads/master
    git reflog

     

    이번에는 checkout에 대해 알아보겠습니다. git checkout [branch명] 을 통해 branch를 바꿀수 있습니다. 하지만 꼭 branch로만 checkout 할 수 있는 것은 아닙니다. git checkout [commit ID] 또한 가능합니다. 동작은 아래의 사진과 같이 이루어집니다. 이 상태는 HEAD가 어떠한 특정 branch를 가리키는 것이 아닌, 특정 commit을 직접 가리키고 있는 상태입니다. gitstory에서 HEAD를 확인해보면 아래와 같이, 특정 branch가 아닌 특정 commit을 가리키고 있음을 볼 수 있습니다.

     

    git checkout [commit ID](왼), 해당 명령 실행시 HEAD의 모습(오)

     

    Reset을 통해 알아보는 working copy, index, repository

    위에서 reset의 원리에 대하여 알아보았습니다. reset도 여러개의 option을 가집니다. 대표적인 것이 --soft, --mixed, --hard 입니다. 따로 지정하지 않는다면 default--mixed로 명령이 실행됩니다. 이 reset 명령어를 통해 working copy, index, repository에 대해 알아보겠습니다. 

     

    Working directory (Working copy, Tree): 실제 작업을 진행하는 곳

    Index (Staging area, cache) : add 시, 포함되는 곳

    Repository (History) : commit 시, 포함되는곳이며 commit 된 버전을 저장함

     

    아래의 색깔있는 박스는 reset의 옵션에 따른 option의 범위를 나타내고 있습니다. 

    git reset --soft [version] : Repository만을 삭제

    git reset --mixed [version] : Default option, Index와 Repository를 삭제

    git reset --hard [version] : Working directory, Inedx, Repository를 모두 삭제

     

    Working directory, index, repository와 reset 옵션 간의 관계

     

    실제 동작을 살펴보며 위의 동작들을 이해해봅시다. 우선 디렉토리를 하나 만들고, f1.txt 파일을 생성합니다

     

    f1.txt의 내용은 "init"으로 하고 , add와 commit을 진행합니다. 그렇다면 현재의 f1.txt의 상태는 아래와 같습니다. 

     

    add, commit

    Working directory의 내용은 터미널에서 cat f1.txt를 통해 확인할수 있고, 

    Index의 내용은 gitstory의 Index 폴더에서 확인할 수 있습니다.

    Repository의 내용은 gistory의 refs/heads/master 폴더에서 확인할 수 있습니다.

     

    index 내의 f1.txt 내용

     

    refs/heads/master 내의 f1.txt의 내용

    이번에는 f1.txt의 내용은 "Repository"으로 하고 , add와 commit을 진행합니다. 그렇다면 현재의 f1.txt의 상태는 아래와 같습니다.

     

     

     

    이번에는 f1.txt의 내용은 "Index"으로 하고 , add만 진행합니다. 그렇다면 현재의 f1.txt의 상태는 아래와 같습니다.

    index로 수정한 f1.txt를 add만 하고, commit은 진행하지 않았기 때문에, 현재 working directory와 index 폴더는 f1.txt의 내용이 "index"이지만, Repository는 여전히 "Repository"인 것을 확인할 수 있습니다. 

     

    index의 f1.txt 내용
    refs/heads/master 의 f1.txt 내용

     

    이번에는 f1.txt의 내용은 "Working copy"으로 하고 ,저장만 합니다. add와 commit을 하지 않습니다!!! 그렇다면 현재의 f1.txt의 상태는 아래와 같습니다. (실제 저장소 사진은 생략하겠습니다.)

     

     

     

    자, 벌써 조금 복잡하죠..! 하지만 중요하고 한번 원리를 익히면 나중에 더 쉽게 사용할 수 있으니 천천히 따라와주세요. 

     

    이제 본격적으로 reset 옵션들을 사용하여 reset을 해보겠습니다. 지금 현재 commit log는 아래와 같습니다. 2개의 commit이 있고, '424b..'로 시작하는 1번 commit은 "init"을 저장하고 있고, '70fe..'로 시작하는 2번 commit은 "Repository"를 가지고 있습니다. 우리는 현재 버전인 2번 버전에서 1번 버전으로 reset을 진행하겠습니다.

     

    reset전 현재 상태

     

    git reset --soft [424b..] 

    이 명령어를 실행한 결과는 어떻게 될까요? 아래의 표를 참고하여 생각해보면, '--soft' 옵션Respository의 내용만을 reset합니다. 

    그렇다면, 결과는 현재 commit을 reset하고 이전 commit인 1번 commit으로 돌아가게 되는 것 입니다.

    즉, Repository 내의 f1.txt의 내용은 1번 commit의 f1.txt 내용인 "Init"으로 돌아가게 되는 것입니다. 

    실제 결과를 확인해보겠습니다. refs/heads/master를 확인하면, 1번 커밋을 가리키고 있는 것을 볼 수 있고, f1.txt의 내용을 보면 "Init"인 것을 확인할 수 있습니다.

    git reset --soft 이후 Repository의 모습

    위와 같이, Repository의 f1.txt의 내용을 바뀌었지만, Index의 f1.txt의 내용은 여전히 "Index"로 바뀌지 않은 것을 확인할 수 있습니다.

     

    git reset --soft 이후,Index의 모습

    git reset --mixed [424b..] 

     

    이제 '--mixed' 옵션을 살펴보기 이전에, index와 repository의 내용을 reset하는 mixed 옵션의 동작을 정확히 보기 위해, 위에서 진행한 git reset --soft를 취소해주겠습니다. git reset --soft ORIG_HEAD 명령을 통해 되돌릴 수 있습니다. (설명의 위의 reset의 원리를 참조)

     

    자 이제 실제로 git reset --mixed 를 실행해보겠습니다. 이제는 어떤 결과일지 예상이 가시나요? 아래의 표와 같이 Index와 Repository 모두 "init"으로 변경됩니다. (gistory index, repository 화면은 생략하겠습니다..) 하지만 여전히 Working directory의 내용은 "Working copy"입니다!

     

    git reset --mixed 이후 실행결과

    git reset --hard [424b..] 

     

    마지막으로 git reset --hard를 살펴보겠습니다. 역시 이번에도  git reset --soft ORIG_HEAD 를 사용하여 git reset --mixed를 취소해주겠습니다.

     

    자 이제 실제로 git reset --hard 를 실행해보겠습니다. 결과는 우리가 생각하는 것과 같이 아래의 표와 같이 Index와 Repository 뿐아니라 Working directory까지 모두 "init"으로 변경됩니다. (gistory index, repository 화면은 생략하겠습니다..)

     

     

     

     

    ____________________

    지금까지 Git의 원리, 이번에는 Branch, Reset, Checkout에 대해 알아보았습니다.

    설명이 부족한 부분이나 틀린 부분이 있다면 알려주세요.

    감사합니다.

    'STUDY > Git & Github' 카테고리의 다른 글

    Git - 7. 원격 저장소 Github  (0) 2021.01.11
    Git - 6.2 Git의 원리(part.2) Merge & Conflict, 3-way Merge  (0) 2021.01.08
    Git - 5.3 Stash  (0) 2021.01.07
    Git - 5.1 Branch 충돌 해결  (0) 2021.01.06
    Git - 5. Branch  (0) 2021.01.06

    댓글

Designed by Tistory.