Git Branch

    1. Git Branch

    • 브랜치는 원본 폴더와 분리하여 독립적으로 개발 작업을 수행하는 개념으로 이해하면 된다. 그리고 Git을 이용하면, 독립적으로 개발한 코드를 원본 폴더에 손쉽게 Merge할 수 있다. 
    • 브랜치는 Commit의 특정 시점을 가리키는 별칭으로 이해할 수 있다.
    • 브랜치는 HEAD 포인터를 가지고 있으며, 각 브랜치의 HEAD 포인터는 그 브랜치가 가리키는 가장 최신의 커밋을 의미한다. 
    • 각 브랜치는 Commit 이력을 가지고 있으며, Commit으로 자유롭게 이동할 수 있다.

     

    2. Branch 생성

    • 브랜치는 기준이 되는 브랜치 또는 커밋이 하나 있어야 한다. 
    • 브랜치를 생성하면, 현재 커밋을 가리키는 HEAD를 기준으로 새로운 브랜치를 생성한다.
    • 생성된 브랜치는 독립된 공간을 할당받는다. 따라서 기존 작업 영역에는 영향을 주지 않는다.

     

    2-1. 브랜치 생성

    # 커밋 ID를 기준으로 새로운 브랜치 생성
    $ git branch <브랜치_이름> <커밋_ID>
    
    # 현재 HEAD Point를 기준으로 새로운 브랜치 생성
    $ git branch <브랜치_이름>
    • 위 명령어를 이용하면 브랜치를 만들 수 있다. 어떤 인자를 주느냐에 따라 특정 시점을 기준으로 브랜치를 만들거나, 현재 HEAD 값으로 브랜치를 만든다. 
    • 생성된 브랜치가 현재 브랜치로 자동 지정되지는 않는다.

    • Argument가 어떤 값이 주어지느냐에 따라 다음 형태로 각각이 생성되는 것을 볼 수 있다.
    # 파일을 하나 만든다.
    $ vim branch.html
    
    # commit
    $ git commit -m "first"
    
    # 브랜치 생성 (HEAD 포인터 기준으로 생성)
    $ git branch footer
    • 위 명령어를 이용해서 커밋을 하고, 커밋 지점을 바탕으로 브랜치를 만들 수 있다. 

    • main 브랜치가 존재하는 가운데, footer 브랜치가 만들어진 것을 볼 수 있다. 그렇지만 현재 브랜치는 main 브랜치라는 것을 알 수 있다. 

     

    3. Branch 확인

    $ git branch
    $ git branch -v
    • 하나의 Git Repository에는 여러 브랜치가 존재할 수 있다. 위 명령어를 이용해서 Local Git Repository에 존재하는 Branch를 찾아볼 수 있다.

    • * 표시가 된 브랜치는 현재 브랜치를 가리킨다. 그리고 실제 사용자 이름 뒷쪽에 (main)이라고 되어있어서, 현재 브랜치 상태를 잘 표현해주고 있는 것을 볼 수 있다.
    • 또한, 현재 각 브랜치가 가리키고 있는 Commit 값 + Commit 메세지를 확인할 수 있다. 

     

    3-1 브랜치 Hash 확인

    $ git rev-parse <브랜치_이름>
    • 각 브랜치는 특정 커밋 시점을 가리키는 별칭이다. 따라서 각 브랜치는 특정 커밋의 해쉬 값을 가리키고 있고, 위 명령어를 이용해서 확인할 수 있다.

    • 위 명령어를 이용해보면 확인할 수 있다. rev-Parse로 얻은 해시 값과 git branch 명령어로 불러온 hash 값이 같은 것을 볼 수 있다. 

     

    4. 브랜치 이동

    $ git checkout <이동할_브랜치_이름>
    • 브랜치를 생성한다해 생성된 브랜치로 이동하지 않는다. 따라서 해당 브랜치에서 작업을 하고 싶다면, 브랜치로 이동을 해야한다.
    • Git은 하나의 Working Directory만 가진다. 모든 작업은 Working Directory에서 하는데, Working Directory는 현재 선택된 브랜치만 연결이 된다. 따라서 다른 브랜치에서 작업하려면 반드시 브랜치를 변경해서 워킹 디렉토리를 재설정해야한다. 

    • git checkout 명령어를 이용해서 main → footer로 브랜치로 이동했다. 

    4.1 브랜치 동작 원리

    • HEAD 정보는 항상 변경된 브랜치의 마지막 커밋을 가리킨다. 따라서 브랜치가 이동하면 HEAD 포인터도 함께 이동된다.
    • 변경된 브랜치로 새로운 작업을 할 수 있도록 워킹 디렉토리를 변경한다. 브랜치를 변경하려면 기존 브랜치의 워킹 디렉토리를 정리해야만 한다.

     

    4.2 이전 브랜치 

    $ git checkout -
    • Git은 이전 브랜치로 손쉽게 이동하는 기능을 제공한다. 위 명령어를 이용하면 이전 브랜치로 이동한다. 

     

    4.3 워킹 디렉토리 정리

    • 체크아웃 전에 현재 작업하고 있는 워킹 디렉토리를 정리하고 넘어가야 한다. 
    • 만약 워킹 디렉토리를 정리하지 않고 넘어가면, 브랜치 변경 시 경고 문구가 나오는 것을 볼 수 있다. 
    # branch.html 파일 수정
    $ vim branch.html
    
    # main 브랜치의 현재 상태 확인
    $ git status
    
    # footer로 브랜치 변경
    $ git checkout footer
    • 위의 명령대로 수행을 해본다. branch.html 파일을 수정하고 Commit 하지 않은 채로 브랜치를 변경하는 작업이다.

    • 브랜치가 변경은 되지만, M branch.html이라는 문구가 추가된 것을 볼 수 있다. branch.html 파일이 변경된 상태라는 것을 알려준다. 

    • 이 상태에서 footer 브랜치의 상태를 확인해보면, main 브랜치에서 변경하고 commit 하지 않은 "branch.html" 파일의 상태가 modified가 된 것을 볼 수 있다. 즉, 이전 변경 사항이 넘어온 것으로 이해할 수 있다. 
    • 이 상황에서 add를 하고 commit을 하게 되면 main 브랜치의 변경점이 main에는 반영되지 않고, footer 브랜치에 반영되게 된다. 즉, Working Directory는 하나만 존재하고 모든 브랜치가 함께 사용하기 때문에 변경점이 이상한 브랜치에 반영될 수 있다는 것을 의미한다. 
    • 따라서 브랜치 변경 시점에는 반드시 git status를 확인해서 Working Directory가 깔끔한 상태에서 이동한다.
    $ git checkout -
    $ gid add branch.html
    $ git commit -m "master-working"
    $ git checkout footer
    • 위 명령어를 이용해서 main 브랜치로 돌아가서 변경점을 반영 및 commit 한 후 footer로 넘어간다. 이렇게 되면 작업 디렉토리가 정리되어서 넘어갈 수 있다. 

    • 만약 각 브랜치의 상태가 달라서, 현재 브랜치의 변경 시점이 다른 브랜치로 넘어갔을 때 영향을 준다면 checkout을 아예 막아버린다.
    • 예를 들어서 main 브랜치와 footer가 서로 다른 커밋을 가리고 있는 상황이다. 이 때, main 브랜치는 branch.html에 hello! branch! 라고 하는 파일을 가지고 있다. 이 때, footer가 branch.html의 파일을 abc로 수정을 하고, 변경 내용을 반영하지 않고 checkout을 시도하면 반드시 문제가 발생한다. 따라서 git은 checkout을 막아버린다.

     

    5. 브랜치 공간

    • git log --graph --all 명령어를 이용하면 다음과 같이 각 브랜치에 대한 commit 로그를 볼 수 있다.
    • 현재 main / footer 브랜치는 각각 서로 다른 commit을 가리키고 있다. 

    5-1. 각 브랜치 Working Directory 확인하기 

    • main 브랜치로 넘어가서 branch.html을 확인하면 다음과 같이 두 줄을 확인할 수 있다. 마지막 커밋 내용을 잘 가리키고 있다. 

    • footer 브랜치로 넘어가서 branch.html을 확인하면 다음과 같이 한 줄만 있는 것을 볼 수 있다. 
    • 브랜치를 이동하면 변경된 각자 브랜치의 마지막 워킹 디렉토리 상태로 변경된다.

     

    6. HEAD 포인터

    • Git은 마지막 커밋 정보를 기반으로 새로운 커밋을 생성한다. 그리고 Git은 HEAD라는 포인터로 마지막 커밋이 어딘지 알려준다.
    $ git log --graph --all
    • 위 명령어를 이용하면 현재 각 브랜치가 어떤 Header를 가지고 있는지 볼 수 있다.

    • 위 명령어를 이용하면 다음 화면을 볼 수 있다. 여기서 footer / main 브랜치가 존재하는 것을 알 수 있다.
    • 현재는 footer 브랜치이고, footer 브랜치의 HEAD가 어딘지 잘 표현되어있다 (5bf commit)

    • main 브랜치로 checkout 하고 다시 확인해보면, 현재 HEAD 포인터가 어디를 가리키고 있는지를 볼 수 있다.
    • 결론은 브랜치를 이동할 때 마다 HEAD 포인터는 변경된다는 것이다. 

     

    6-1. 상대적 위치

    • HEAD 포인터는 커밋을 만드는데 사용된다. 그런데 다양한 명령어의 기준점으로 사용되기도 한다.
    • HEAD- / HEAD^를 하면 HEAD 포인터를 기준으로 이전 커밋을 가리킨다.
    • HEAD^^^은 HEAD 포인터를 기준으로 3개 전 커밋을 가리킨다. 그런데 이게 불편하니 HEAD^3으로 사용한다.

     

    6-2. AHEAD / BHEAD

    원격 저장소도 브랜치가 존재하고, 로컬 저장소도 브랜치가 존재한다. 서로 브랜치가 업스트림으로 연결되었다고 하더라도, 각 브랜치는 다른 HEAD 포인터를 가지고 관리된다. 왜냐하면 원격 저장소의 특정 브랜치에 다른 개발자가 push를 하게 되면 HEAD 포인터는 이동한다. 그렇다고 내 로컬 저장소의 브랜치가 변경되지는 않는다. 왜냐하면 내 로컬 저장소는 나만의 HEAD 포인터를 가지고 있기 때문이다. 

    즉, 원격지 / 로컬 저장소의 브랜치는 각각의 HEAD 포인터를 가지고 있다. 그리고 이 HEAD 포인터의 상대적인 차이를 가리키는 상태 값으로 AHEAD / BHEAD 라는 명령어를 사용한다. 

    AHEAD

    서버로 전송되지 않은 로컬 Commit이 존재함.

    BHEAD

    로컬 저장소로 내려받지 않은 로컬 Commit이 존재함.

     

    7. 생성과 이동

    브랜치는 특정 Hash 값을 가리킨다. 

    7-1. 커밋 해쉬키로 이동하기

    • 브랜치는 특정 커밋에 별명을 부여한 것과 동일하다. 
    • 일반적으로 브랜치를 생성할 때는 마지막 커밋을 기준으로 한다. 
    • 따라서 브랜치를 이동할 때, "커밋 해쉬키"로 이동할 수 있다. → 이동하면 그 값이 HEAD 포인터가 된다. 
    # 커밋 해시키로 이동하기
    $ git checkout <커밋_해쉬키>
    • 위 명령어를 이용하면 해당 해쉬키로 이동할 수 있다.

    • master 브랜치에서 "21c409..." 브랜치로 이동하도록 했다.
    • 이동이 정상적으로 이루어진 것을 볼 수 있고, 현재 가리키는 곳이 "21c409c..." 형태가 된 것을 볼 수 있다. 

    7-2. HEAD를 활용한 이동

    • HEAD는 기준이 되는 위치라고 했다. 따라서 HEAD를 기준으로 이동할 수 있다.
    # HEAD 기준으로 얼마 전 커밋까지 돌아갈 것인지
    $ git checkout HEAD~<숫자>
    • 위 명령어를 이용하면 HEAD 포인터를 기준으로 몇 번째 이전 커밋까지 이동할 수 있다. 

    • HEAD 포인터를 기준으로 1번 이전에 했었던 커밋으로 이동했다. 

    7-3 돌아오기

    # 이전 브랜치로 복귀
    $ git checkout -
    
    # 특정 브랜치로 복귀
    $ git checkout <브랜치 이름>
    • 위 명령어를 이용하면 이전의 브랜치로 복귀할 수 있다.
    • 이 때, 현재를 가리키는 HEAD 포인터가 바뀌게 된다. 

     

    8. 원격 브랜치

    • 원격 저장소 / 로컬 저장소에 각각 브랜치가 생성될 수 있다. 
    • 원격 저장소에 브랜치 생성 / 로컬 저장소에 브랜치를 생성한다고 해서 각각 대응되는 곳에 동기화 된 브랜치가 생성되지 않는다.
    • 따라서 리모트 브랜치 / 로컬 브랜치를 연결시켜주는 작업이 필요하다. 

    8.1 브랜치 추척

    • 로컬 브랜치가 원격 브랜치를 가리키도록 하는 것을 추적 브랜치라고 한다. 추적 브랜치는 원격 브랜치의 마지막 커밋 해시값을 가리킨다.
    • 로컬 브랜치가 가리키는 원격 브랜치의 포인터 정보는 .git/refs 폴더 안에 저장되어있다. 

    8-2 브랜치 업로드

    • 로컬 저장소에서만 브랜치를 생성했다면, 원격 저장소에는 어떠한 브랜치도 존재하지 않는다.
    • 따라서 로컬 저장소의 브랜치를 원격 저장소에 업로드해주는 과정이 필요하다. 

    • 현재 origin 리포지토리를 살펴보면, 어떠한 브랜치도 존재하지 않는 것을 볼 수 있다. (unknown)
    # u : upstream
    $ git push <원격 저장소> -u <로컬 브랜치 이름>
    • 위 명령어를 이용하면, 로컬 브랜치가 원격지에 생성되는 것을 볼 수 있다. 
    • 현재 브랜치가 아닌 "로컬 브랜치 이름"을 가진 로컬 브랜치가 원격지에 동일한 이름으로 업로드 되는 것을 볼 수 있다.(branch 'master' set up to track 'origin/master'.

    • 위 명령어를 이용해서 master 브랜치를 원격지에 등록해주었다. 

    • 정상 등록된 것을 다시 확인해본다.  (git remote show <브랜치 이름>)
    • 확인해본 결과, 현재 HEAD branch는 master이고, remote의 master를 바라보고 있는 것을 알 수 있다. 

    • hotfix 브랜치를 한번 더 원격지에 추가한 후, 현재 로컬의 브랜치 상태를 확인했다. 
    • 각각의 브랜치가 원격지를 바라보고 있는 것을 알 수 있다. 

    8-3 이름이 다른 브랜치

    • 서로 다른 개발자가 개발하다보니 브랜치 이름이 달라질 수 있다.
    • 이 경우, " : "을 이용해서 해결할 수 있다. 
    # 브랜치 푸쉬하기
    $ git push origin [로컬 브랜치 명 : 푸시 할 원격 브랜치]
    • 위 명령어를 이용해서 해결할 수 있다. 

    • 다음과 같이 로컬의 featur 브랜치는 origin repository의 function 브랜치로 트래킹하는 것을 알 수 있다. 

    • origin repository에 function 브랜치가 새로 생긴 것을 볼 수 있다. 

    8.4 업스트림 브랜치

    • git clone으로 폴더를 가져오면, 모든 upstream 브랜치를 가져오지는 않는다.

    • 실제로 보면 master 브랜치만 가져온 것을 볼 수 있다. 
    # 브랜치 목록
    $ git branch -vv
    $ git branch -a
    $ git branch -r
    • 위 명령어를 이용하면 모든 브랜치를 볼 수 있다. 
    • 그렇다면 원격에 있는 브랜치를 로컬에서 트래킹 하도록 할 수 있는 방법은 없을까?
    # 원격지 브랜치 트랙하는 브랜치 만들기
    $ git checkout -- track <원격지/브랜치이름>
    • 위 명령어를 이용하면 해당 원격지 + 브랜치 이름을 트래킹하는 브랜치가 로컬에 만들어진다. 

    • 명령어를 수행하면, 명령 결과는 다음과 같이 처리 된다.

    • 실제로 만들어진 브랜치를 살펴보면, function 브랜치가 생겼고 "origin/function"을 바라보고 있는 것을 알 수 있다. 

    • 이 때, clone 폴더의 branch.txt 값을 변경한다. 변경하고, commit 하고 원격지에 push까지 한다.

    • 기존 폴더의 branch.txt를 읽어보면 현재는 hello만 나온다. 

    • pull 해서 가져와보면, feature 브랜치에 정상적으로 받아지는 것을 볼 수 있고 "git clone 6 modify" 라는 문구가 추가 된 것을 볼 수 있다. 

    • 이 때, 다시 한번 값을 수정해보면, origin/function 대비 feature가 ahead 1이라는 값을 볼 수 있다. 즉 한번의 커밋을 더 했다는 뜻이다. 

     

    8.5 원격 브랜치 복사

    • 원격 저장소와 로컬 저장소의 브랜치 목록은 서로 다를 수 있다. 왜냐하면 다른 개발자도 원격 저장소를 함께 사용하기 때문이다.
    # 원격지 브랜치를 로컬에 생성하기
    $ git checkout -b <새 브런치 이름> <원격지 브런치 이름>
    • 위 명령어를 이용하면, 원격지 브랜치를 로컬에 생성할 수 있다. 

    • 먼저 github에서 mynewbranch라는 새로운 브랜치를 만든다.

    • 이 때, 원격지의 정보를 확인해보면 새로운 브랜치가 생긴 것을 알 수 없다. 왜냐하면 로컬 저장소와 원격 저장소는 항상 통신을 하고 있는 것이 아니기 때문이다.
    • 따라서 원격지의 정보를 가져와야한다. 
    # 브랜치 정보 가져오기
    $ git fetch
    • 위 명령어는 원격지의 commit 정보를 가져오는 역할을 한다. (merge는 하지 않음) 

    • 다시 mynewbranch가 생긴 것을 볼 수 있다. 

    • git checkout -b 명령어를 이용해서 원격지의 있는 브랜치를 가져와서 만들었다. 

    • 이 때, 현재 브랜치에서 branch.txt의 값을 바꾼 후 커밋을 한다. 그리고 현재 차이(ahead 1)가 나는 것을 볼 수가 있는데 이걸 push까지 한다.

    • 이 때, 브랜치를 확인해보면 다음과 같이 mynewbranchlocal로 푸시가 되는 것을 확인할 수 있고, push 결과도 확인할 수 있다.

     

    8.6 업스트림 브랜치 연결하기

    # 로컬 브랜치 / 업스트림 브랜치 연결하기
    $ git branch -u [업스트림 브랜치]
    • 새롭게 만들어진 업스트림 브랜치를 연결하는 방법이 존재한다. 
    • 위 명령어를 이용하면 기존 브랜치와 특정 원격 브랜치가 연결된다. 

    • bbb 원격 브랜치 생성, bug 로컬 브랜치를 생성한 다음 git branch -u를 이용해서 bug - bbb를 연결해주었다.
    • 연결 결과는 git branch -vv를 통해서 확인할 수 있다. 

     

    9. 브랜치 전송

    로컬 저장소의 브랜치를 원격 저장소로 전송하는 방법을 확인한다.

    9-1  브랜치 푸시

    $ git push -u <원격지> <브랜치 이름>
    • 원격 저장소를 등록하는 것만으로 브랜치가 자동으로 설정되지는 않는다. 따라서 직접 등록해야한다.
    • 이 때, -u(--set-upstream-branch) 명령어를 이용하면 브랜치를 푸쉬하면서 업스트림 브랜치를 설정할 수 있다. 

    9-2 브랜치 Fetch

    $ git fetch
    $ git merge <원격저장소별칭/브랜치 이름>
    • 브랜치 Fetch는 커밋 Fetch와 동일하게 동작한다. 단순히 결과를 임시 저장소에 내려받을 뿐, Merge는 하지 않는다. 즉, 새로운 로컬 브랜치가 생성되지 않는다.
    • 따라서 Merge 명령어를 이용해서 병합시켜줘야한다. 

    9-3 브랜치 Pull

    브랜치 정보는 Pull을 이용해도 자동으로 Merge가 되지는 않는다. 

     

    10. 브랜치 삭제

    • 브랜치를 삭제하는 것은 해당 브랜치 내용과 커밋을 모두 삭제하는 것이다. 
    • 현재 자신이 있는 브랜치는 삭제 할 수 없다. 

    10.1 일반적인 삭제 방법

    $ git branch -d <브랜치 이름>
    • -d 옵션은 스테이지 상태가 깨끗할 때만 삭제를 허용한다.
    • 워킹 디렉토리에 작업한 기록이 있거나, add 명령어로 스테이지의 인덱스가 변경된 상태라면 삭제하지 않음. 

    10.2 강제 삭제 방법

     

    $ git branch -D <브랜치 이름>
    • 워킹 디렉토리 / 스테이지에 추가 컷밋 작업이 남아있는 경우 일반적인 방법으로는 브랜치 삭제가 안됨.
    • 이 경우는 -D 명령어를 이용해서 삭제해야한다. 

    • hotfix 브랜치에서 branch.txt를 수정한 다음, -d 옵션으로 삭제를 해봤는데 삭제가 되지 않는다. 
    • 이 때, -D 옵션을 사용하면 삭제할 수 있다.

    10.3 원격지의 브랜치 삭제

    # 원격지 브랜치 삭제
    $ git push <원격지 별칭> --delete <원격지 브랜치 이름>
    • 원격지에 push 명령어를 보내는데, 이 때 --delete 옵션으로 보내면 된다. 

    • 위 명령어를 보내면 정상적으로 브랜치가 삭제된 것을 볼 수 있다.

    '기타 Tool > Git' 카테고리의 다른 글

    Git 복귀  (1) 2022.08.29
    Git 병합 / 충돌  (0) 2022.08.29
    Git Remote Repository  (0) 2022.08.27
    Git의 Commit  (0) 2022.08.26
    Git Repository 복사  (0) 2022.08.26

    댓글

    Designed by JB FACTORY