Skip to content

6. 브랜치 #3

@jaeho214

Description

@jaeho214

브랜치

나뭇가지, 지사, 분점 등 줄기 하나에서 뻗어 나온 갈림길을 의미

저장 공간 하나에서 가상의 또 다른 저장 공간을 만드는 것으로 보면 됨

6.1 새로운 작업

6.1.1 브랜치 작업

커밋은 파일의 수정 이력을 관리하는 데 사용한다면, 브랜치는 프로젝트를 독립적을 관리하는데 사용한다.

잦은 버그 수정과 새로운 기능을 구현할 때마다 작업 폴더를 복사하는 것은 프로젝트 유지 관리 측면에서 좋지 안고 향후 코드 통합에도 어려움이 있다.

깃을 사용하면 프로젝트 작업 폴더를 복사하지 않고 기존 코드와 분리해서 작업할 수 있다.

6.1.2 깃 브랜치 특징

가상 폴더

깃의 브랜치는 작업 폴더를 실제로 복사하지 않고, 가상 폴더로 생성한다.

외부적으로는 물리적인 파일 하나만 있는 것으로 보인다.

개발자는 쉽게 가상 폴더인 브랜치를 이동하면서 프로젝트를 수행할 수 있다.

독립적인 동작

기존에는 소스 코드의 작업 폴더를 별도로 생성해서 사용했는데 브랜치를 이용하면 원본 폴더와 분리하여 독립적으로 개발 작업을 수행할 수 있다.

빠른 동작

다양한 버전 관리 도구도 브랜치 기능을 지원하지만 브랜치를 생성할 때 내부 파일 전체를 복사하기 때문에 시간이 오래 걸린다.

하지만 깃의 브랜치는 다른 벚전 관리 도구보다 가볍고 브랜치 전환이 빠르다.

깃은 Blob 개념을 도입하여 내부를 구조화한다.

💡 Blob은 포인트와 유사한 객체로, 깃은 브랜치를 변경할 때 포인터를 이동하여 빠르게 전환한다.

브랜치 명령을 사용하면 내부적으로 커밋을 하나 생성하여 브랜치로 할당한다.

다른 버전 관리 시스템은 폴더의 파일 전체를 복사하는 반면, 깃은 41바이트를 가지는 해시(SHA1) 파일 하나만 만들면 되기 때문에 빠르다.

6.2 실습 준비

깃은 기본적으로 master 브랜치를 하나 가지고 있다.

그리고 브랜치는 HEAD 포인터를 가지고 있다.

6.2.1 저장소 생성 및 초기화

깃 배시에 초기화 명령어를 실행하면 아래와 같이 현재 브랜치 이름이 같이 출력이 된다.

Untitled

6.2.2 기본 브랜치

모든 커밋과 이력은 브랜치에 기록된다.

깃은 최소한 브랜치가 1개 이상 필요하기 때문에 저장소를 처음 초기화하면 master 브랜치 하나가 자동으로 생성된다.

Untitled

status 명령어를 실행하면 현재 작업하는 위치와 상태를 확인할 수 있다.

branch 명령어로 현재 브랜치를 확인할 수도 있다.

branch 명령어는 생성된 모든 브랜치를 출력한다.

6.3 브랜치 생성

브랜치는 가상의 작업 폴더다.

처음 깃을 초기화할 때 워킹 디렉터리는 master 브랜치를 생성한다.

브랜치는 공통된 커밋을 가리키는 지점이다.

그리고 브랜치는 커밋처럼 SHA1 해시키를 가리킨다.

하지만 커밋의 SHA1 해시키는 기억하기 어렵기 때문에 특정 커밋을 가리키는 별칭을 만드는 것이다.

즉. 브랜치를 생성한다는 의미는 기존 브랜치 또는 커밋에 새로운 연결 고리를 하나 더 만드는 것과 같다.

Untitled

새 브랜치를 생성하면 포인터만 있는 브랜치가 생성된다.

일반적으로 브랜치 생성 명령을 실행하면 현재 커밋을 가리키는 HEAD(현재 마지막 커밋)를 기준으로 생성된다.

💡 브랜치는 마지막 커밋 위치를 가리키는 역할만 할 뿐 실제 브랜치는 아니다. 실제 브랜치는 실제 커밋이 추가될 때 만든다.

예를 들어 브랜치를 생성 후 새로운 브랜치에서 파일을 수정하고 커밋한다.
그리고 새로운 브랜치에 추가 커밋이 발생할 때, 브랜치는 새로운 커밋으로 브랜치의 포인터를 이동한다.

새롭게 브랜치가 생성되면 독립된 공간을 할당한다. 기존 작업 영역에는 영향을 주지 않는 새로운 가상 공간이다.

6.3.1 브랜치 생성

처음 생성되는 기본 master 브랜치 외의 브랜치는 사용자가 직접 branch 명령어를 입력하여 생성(사용자 브랜치)해야 한다.

브랜치는 깃에서 또 하나의 개발 분기점을 의미한다.

새로운 개발 분기점이 필요할 때는 브랜치를 추가로 생성할 수 있다.

브랜치 생성은 브랜치 명령어를 사용한다.

git branch 브랜치이름 커밋ID

branch 명령어 뒤에 브랜치 이름을 인자 값으로 추가한다.

브랜치 이름만 입력하면 현재 HEAD 포인터를 기준으로 새로운 브랜치를 생성하고, 직접 커밋 ID를 인자 값으로 지정하면 지정된 커밋 ID를 기준으로 브랜치를 생성한다.

Untitled

6.3.2 브랜치 이름

브랜치 이름을 지을 때 사전 예약된 명칭은 없지만 알기 쉬운 이름으로 짓는 것이 좋다.

또, 깃 플로에서 정의한 브랜치 이름을 적용하는 것도 좋은 방법이다.

Git TextBook

브랜치 이름은 슬래시를 사용하여 계층적인 구조로 만들어서 사용할 수 있다.

  • 기호(-)로 시작할 수 없다.
  • 마침표(.)로 시작할 수 없다.
  • 연속적인 마침표(..)를 포함할 수 없다.
  • 빈칸, 공백 문자, 물결, 캐럿(^), 물음표, 별표, 대괄호 등은 포함할 수 없다.
  • 아스키 제어 문자는 포함할 수 없다.

저의할 점은 브랜치 이름은 중복해서 사용하지 않아야 한다는 것이다.

6.4 브랜치 확인

6.4.1 간단 브랜치 목록

깃 배시에서 브랜치 목록을 확인하는 방법은 branch 명령어를 사용하는 것이다.

branch 명령어는 브랜치를 만들때 뿐만 아니라 브랜치 목록을 확인하기 위해 단독으로 사용할 수 있다.

Untitled

브랜치명 앞에 별표가 붙은 브랜치는 현재 선택된 브랜치를 의미한다.

6.4.2 브랜치 해시

브랜치는 특정한 커밋의 해시 값(SHA1)을 가리킨다.

깃의 저수준 명령어인 rev-parse를 사용하면 현재 브랜치가 어떤 커밋 해시값을 가리키는지 확인할 수 있다.

Untitled

6.4.3 브랜치 세부 사항 확인

기본적인 branch 명령어는 간단한 브랜치 이름만 출력하지만 옵션을 추가하면 좀 더 상세한 정보를 얻을 수 있다.

branch 명령어 뒤에 -v 또는 -verbose 옵션을 함께 사용하면 브랜치 이름, 커밋 ID, 커밋 메시지를 같이 볼 수 있다.

Untitled

6.5 브랜치 이동

브랜치를 생성했다고 해서 자동으로 생성된 브랜치로 이동하지는 않는다.

6.5.1 체크아웃

현재 브랜치를 떠나 새로운 브랜치로 들어간다는 의미로 체크아웃이라는 용어를 사용한다.

Untitled

깃은 하나의 워킹 디렉터리만 가지고 있기 때문에 다른 브랜치에서 작업하려면 반드시 브랜치를 변경하여 워킹 디렉터리를 재설정해야한다.

💡 워킹 디렉터리에 커밋하지 않은 내용이 있다면 브랜치를 변경할 수 없다.

6.5.2 브랜치 동작 원리

checkout 명령어로 브랜치가 변경되면 깃은 내부적으로 몇가지 동작을 수행한다.

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

6.5.4 이전 브랜치

브랜치를 이동하려면 브랜치의 이름을 적어주어야 하지만 새로운 브랜치가 아닌 이전 브랜치로 좀 더 편하게 이동하려면 대시(-)를 사용하면 된다.

Untitled

6.5.5 워킹 디렉터리 정리

체크아웃을 사용하여 브랜치를 이동할 때는 현재 작업하고 있는 워킹 디렉터리를 정리하고 넘어가야 한다.

브랜치가 변경되면 워킹 디렉터리도 같이 변환이 되기 때문에 워킹 디렉터리 안에서 작성하던 내용이 있고 커밋을 하지 않았다면 체크아웃할 때 경고가 발생한다.

깃은 향후 충돌을 방지하려고 워킹 디렉터리에 작업이 남아 있다면 경고메시지를 보여주고 브랜치를 변경할 수 없게 제한한다.

작업된 워킹 디렉터리를 커밋하지 않고 브랜치를 변경할 때는 스태시 기능을 사용하는 것이 좋다.

6.6 브랜치 공간

6.6.1 브랜치 로그

로그를 출력할 때 브랜치 흐름도 같이 보려면 --graph 옵션을 함께 사용한다.

--graph --all 옵션을 사용하면 모든 로그를 출력한다.

Untitled

6.6.2 브랜치 소스 확인

브랜치를 이동하면 변경된 각자 브랜치의 마지막 워킹 디렉터리 상태로 빠르게 변경되기 때문에 브랜치 간의 소스 코드에 차이가 있을 수 있다.

6.7 HEAD 포인터

깃은 객체의 포인터 개념을 사용한다.

6.7.1 마지막 커밋

깃은 마지막 커밋 정보를 기반으로 새로운 커밋을 생성한다.

마지막 커밋은 새로운 커밋의 부모 커밋이다.

시스템이 커밋을 할 때마다 마지막 커밋 정보를 찾으면 부하가 발생하기 때문에 깃은 마지막 커밋을 쉽게 확인할 수 있도록 HEAD라는 특수한 참조 포인터를 사용하고 HEAD 포인터를 사용하여 빠르게 스냅샷을 생성할 수 있다.

Untitled

6.7.2 브랜치 HEAD

브랜치를 이동하면 HEAD 포인트도 이동된다.

각각의 브랜치마다 마지막 커밋이 다르기 때문에 브랜치가 여러 개면 HEAD 포인트도 여러 개가 된다.

Untitled

6.7.4 상대적 위치

깃의 HEAD 포인터는 내부적으로 커밋을 생성하고 브랜치를 관리하는 데 매우 유용하다.

또 깃의 다양한 명령어를 입력할 때도 기준점으로 사용한다.

HEAD를 기준으로 캐럿(^)과 물결 기호를 사용하여 상대적 커밋 위치를 지정할 수 있다.

^과 ~은 HEAD를 기준으로 몇 번째인지 상대적인 위치를 지정한다.

예를 들어 HEAD 포인터 바로 이전의 커밋을 가리킨다면 HEAD^ 또는 HEAD~처럼 사용한다.

HEAD 기준으로 이전 3개의 위치를 지정하고 싶다면 HEAD^^^, HEAD~~~ 또는 HEAD^3, HEAD~3으로 표현한다.

6.7.5 AHEAD, BHEAD

원격 저장소와 연동하여 깃을 관리한다면 브랜치마다 HEAD가 2개 있다.

  • 로컬 저장소 브랜치의 HEAD 포인터
  • 원격 저장소 브랜치의 HEAD 포인터

원격 저장소와 로컬 저장소를 물리적으로 서로 다른 저장소이다. 따라서 두 저장소의 마지막 커밋 위치는 일치하지 않을 수 있다.

AHEAD와 BHEAD는 서로 다른 저장소 간 HEAD 포인터의 위치 차이를 의미한다.

깃은 항상 원격 저장소의 HEAD와 로컬 저장소의 HEAD를 비교한다.

HEAD는 브랜치마다 다르기 때문에 브랜치를 여러개 운영한다면 다수의 AHEAD와 BHEAD가 생길 수 있다.

AHEAD

서버로 전송되지 않은 로컬 커밋이 있는 것이다.

로컬 저장소의 HEAD 포인터를 기준으로 로컷 브랜치에 있는 커밋이 서버의 커밋 개수보다 많은 경우다.

Untitled

BHEAD

로컬 저장소로 내려받지 않은 커밋이 있는 것이다.

다른 개발자가 코드를 수정하여 원격 저장소의 커밋이 자신의 로컬 저장소보다 더 최신 상태인 것을 의미한다.

Untitled

6.8 생성과 이동

6.8.1 자동 이동 옵셥

브랜치를 생성하는 동작과 이동하는 동작은 별개로 따로 두번 입력해주어야 한다.

체크아웃할 때 -b 옵션을 같이 사용하면 브랜치 생성과 이동을 한번에 할 수 있다.

Untitled

6.8.2 커밋 이동

브랜치 이름은 커밋 해시키와 동일하다.

따라서 브랜치로 이동할 때 꼭 브랜치 이름을 사용할 필요는 없고, 커밋 해시키를 사용하여 체크아웃할 수도 있다.

브랜치 중간에 작업한 특정 커밋으로 직접 이동하여 상태를 확인할 수도 있다.

6.8.3 HEAD를 활용한 이동

HEAD 포인터를 사용하여 체크아웃할 수도 있다.

바로 이전 커밋으로 체크아웃하고 싶을 때는 아래와 같이 하면 된다.

Untitled

Untitled

6.8.4 돌아오기

다시 현재 시점으로 돌아오는 가장 간단한 방법은 대시(git checkout -)를 사용하는 것이다.

브랜치 이름으로 체크아웃할 수도 있다.

브랜치 이름으로 체크아웃하면 브랜치의 HEAD 포인트로 복귀한다.

6.9 원격 브랜치

6.9.1 리모트 브랜치

원격 저장소에 생성한 브랜치를 리모트 브랜치라고 한다.

로컬 저장소에 생성한 브랜치는 서버로 공유할 수 있다.

원격 저장소와 연결된 로컬 저장소에서 새로운 브랜치를 생성한다고 해서 자동으로 원격 저장소에도 브랜치가 생성되는 것은 아니다. (그 반대도 아니다.)

별도 명령을 실행하여 저장소를 동기화해야 한다.

6.9.3 브랜치 추적

깃의 브랜치는 특정 커밋 해시 값을 가리키는 포인터고 리모트 브랜치 또한 원격 저장소의 브랜치를 가리키는 포인터다.

원격 저장소의 브랜치를 가리키는 것을 **브랜치 추적(트래킹 브랜치)**이라고 한다.

트래킹 브랜치는 원격 브랜치를 가리키는 북마크와 같다.

추적 브랜치는 원격 브랜치의 마지막 커밋 해시 값을 가리킨다.

이 포인터 정보는 .git/refs 폴더 안에 저장되어 있다.

로컬 저장소가 원격 저장소와 연결될 때 원격 브랜치의 트래킹 정보는 자동으로 갱신된다.

로컬 저장소는 마지막으로 연결된 리모트 브랜치의 커밋 해시 값을 항상 가지고 있다.

6.9.4 브랜치 업로드

등록된 원격 저장소의 리모트 브랜치는 remote show 명령어로 확인할 수 있다.

Untitled

아직 원격 저장소 등록만 했기 때문에 리모트 브랜치는 없고, 리모트 브랜치는 서버 간의 통신을 하고 나서 생성된다.

로컬 저장소의 브랜치를 원격 저장소에 동기화하려면 푸시 작업을 해야한다.

6.9.5 이름이 다른 브랜치

일반적으로 로컬과 원격의 브랜치 이름은 동일하게 사용하지만 가끔은 동일한 브랜치 이름을 사용하기 어려울 때가 있다.

이때 깃은 서로 다른 로컬 브랜치와 리모트 브랜치를 수동으로 지정하여 연결할 수 있는 기능을 제공한다.

브랜치를 직접 수동으로 지정할 때는 콜론(:)으로 구분한다.

Untitled

Untitled

6.9.6 업스트림 트래킹

업스트림은 브랜치 추적을 다르게 표현한 것이다.

리모트 브랜치는 브랜치 이름을 동일하게 생성할 수도 있고, 다른 이름으로 생성할 수도 있다.

이처럼 로컬 저장소의 브랜치와 원격 저장소의 브랜치는 업로드할 수 있도록 매칭되어 있다.

이러한 매칭을 업스트림 트래킹이라고 한다.

Untitled

트래킹 브랜치는 리모트 브랜치와 로컬 브랜치를 연결해주는 중간 다리 역할을 한다.

clone 명령어로 저장소를 복제할 때 원격 저장소에 등록된 트래킹 브랜치들을 자동으로 함께 설정한다.

clone 명령어는 원격 저장소의 모든 브랜치 정보를 한 번에 다 가지고 오지 않지만(master만 가져옴) branch 명령어에 -r 옵션을 사용하면 원격 저장소의 리모트 브랜치 목록을 확인할 수 있다.

Untitled

모든 브랜치 정보를 확인하고 싶다면 -a 옵션을 사용한다.

Untitled

트래킹 브랜치는 -vv 옵션으로 확인할 수 있다.

Untitled

우리는 원본 로컬 저장소에서 feature 브랜치를 function 리모트 브랜치로 등록하여 사용하였는데 checkout 명령어에 --track 옵션을 사용하면 새로운 업스트림을 만들 수 있다.

Untitled

트래킹을 위해 새로운 function 브랜치를 생성한 후 원격 저장소는 origin/function으로 업스트림을 설정한다.

Untitled

function 브랜치의 파일을 수정하고 커밋하여 브랜치를 확인해보았다.

function 브랜치 정보에 AHEAD 1이 표시되었다.

원격 저장소로 전송되지 않은 커밋이 하나 있다는 의미다.

6.9.7 원격 브랜치 복사

원격 저장소와 로컬 저장소의 브랜치 목록은 서로 다를 수 있다.

다른 개발자가 원격 저장소에 새로운 리모트 브랜치를 생성할 수도 있기 때문이다.

이렇게 생성된 원격 저장소의 리모트 브랜치를 이용해서 로컬 저장소에도 새로운 브랜치를 생성하여 동기화 할 수 있다.

Untitled

6.9.8 업스트림 연결

기존에 있는 브랜치를 업스트림으로 직접 설정할 수도 있다.

브랜치를 생성한 후 직접 트래킹 브랜치를 지정했다.

업스트림을 직접 설정하면 원격 저장소로 트래킹 브랜치가 설정된다.

Untitled

6.10 브랜치 전송

6.10.1 브랜치 푸시

깃의 푸시 작업은 로컬 저장소의 파일들을 원격 저장소로 전송한다.

파일뿐만 아니라 브랜치 정보와 커밋까지 모두 전송한다.

처음으로 로컬 저장소에 새로운 원격 저장소가 등록되면 아래와 같이 git push 명령어를 사용할 때 오류 메세지가 출력된다.

Untitled

처음에는 커밋과 브랜치를 푸시하는 데 업스트림 설정이 필요하다.

원격 저장소 연결만으로 업스트림이 자동으로 설정되지는 않는다.

따라서 처음에는 아래와 같이 수동으로 트래킹 브랜치와 업스트림 설정을 해야 한다.

git push --set-upstream origin master

6.10.2 브랜치 페치

리모트 브랜치 페치는 일반적인 커밋 페치와 동일하다.

리모트 브랜치를 페치한다고 해서 자동으로 로컬 저장소에 새로운 브랜치가 생성되지는 않는다.

원격 저장소에서 리모트 브랜치 내용을 내려받기만 할 뿐이지 자동으로 병합하지 않는다.

리모트 브랜치가 페치되면 깃은 단순히 원격저장소별핑/브랜치 포인터만 생성한다.

원격 저장소에서 페치된 커밋들을 새로운 로컬 브랜치로 반영하려면 병합 명령을 실행해야 한다.

git merge 원격저장소별칭/브랜치이름

병합하지 않고 테스트만 할때는 임시 브랜치를 생성하거나 직접 체크아웃할 수도 있다.

git checkout -b 임시브랜치명 origin/브랜치이름

6.11 브랜치 삭제

브랜치를 삭제하는 것은 해당 브랜치 내용과 커밋을 모두 삭제하는 것이다.

현재 자신이 있는 브랜치는 삭제할 수 없고 삭제하려면 다른 브랜치로 이동 후 삭제해야 한다.

6.11.1 일반적인 삭제 방법

git branch -d 브랜치명

Untitled

-d 옵셥은 스테이지 상태가 깨끗할 때만 삭제를 허용한다.

워킹 디렉터리에 작업한 기록이 있거나 add 명령어로 스테이지의 인덱스가 변경된 상태라면 삭제하지 않는다.

6.11.2 강제로 삭제하는 방법

워킹 디렉터리 또는 스테이지에 추가 커밋 작업이 남아 있다면 -D 옵션을 통해서 강제로 삭제해야 한다.

6.11.4 리모트 브랜치를 삭제하는 방법

원격 브랜치를 삭제하려면 삭제 명령을 푸시해야 한다.

git push origin --delete 리모트브랜치명

Untitled

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions