본문 바로가기

잡다/git

[Git 08] 브랜치

 하나의 프로그램은 다양한 모듈 단위로 구성되는 경우가 많다. 이때 해당 모듈들이 긴밀한 관계를 가지는 것이 아니라면, 이들을 각각 나눠 다른 멤버가 생성하고 규칙에 따라 합병하는 방식으로 코드를 작성할 수도 있을 것이다. 이때 다양한 모듈들이 충돌 및 의존성이 적은 관계라면 굳이 하나의 흐름 내에서 개발할 필요는 없다. 깃은 특정 작업에 따라 구분하고 싶은 경우 branch 명령을 이용하여 흐름 분기를 나눠 해당 분기들이 따로 동작할 수 있게 한다.

 브랜치는 커밋들 사이를 넘나들 수 있는 포인터의 일종으로, 하나의 커밋을 가리키는 SHA-1 체크섬 파일에 불과하다. 프로젝트를 통째로 복사하는 대신 스냅샷 방식으로 동작하므로, 복사 작업에 드는 시간이 짧다.

 프로젝트 생성 최초 시점에 master 브랜치가 생성되는데, 중심이 되는 flow 역할을 한다.

 

브랜치 리스트 보기

$git branch

현재 깃 폴더에 어떤 브랜치가 있는지 보여준다. 자신이 현재 위치한 브랜치에는 * 표시가 붙는다.

 

브랜치 생성

$git branch branch_name

현재 위치 ( 정확히는 HEAD 포인터의 위치 ) 에 대해 브랜치를 생성한다. 말 그대로 생성 하기 때문에, 이동은 switch 혹은 checkout 명령을 이용하여 수행한다.

 

브랜치 이동

$git checkout branch_name
$git switch branch_name

주어진 브랜치로 이동한다. checkout으로 이동할 수도 있기는 하나, checkout 자체의 기능이 워낙 많기도 하고, 브랜치 이동 목적으로 switch 명령이 생겼으니 이왕이면 switch를 쓰자. checkout을 써도 상관은 없다.

 

브랜치의 해시값 보기

언급한대로 브랜치는 SHA-1 체크섬 파일에 불과하다. 이때 rev-parse을 이용하면 해당 해시를 볼 수 있다고 한다.

git rev-parse branch_name

브랜치의 해시 값은 분기를 수행한 시점에 가리키고 있던 커밋의 해시 값과 일치한다. 아마 브랜치가 가리키는 값을 이용하여 차후 분기가 된 시점을 알 수 있을 것으로 보인다.

위 그림을 보면 branch 생성에 의해 master 및 test1의 분기가 발생한 것을 볼 수 있다.

 

포인터 & 브랜치 이동

 Git의 HEAD는 기본적으로 각 브랜치의 마지막 커밋을 가리키는 포인터이다. 현재 브랜치에서 HEAD 포인터가 어떤 위치를 가리키는지는 다음 명령을 통해 볼 수 있다.

$cat .git/HEAD

 

HEAD가 얌전히 각 브랜치의 마지막 커밋을 가리키면, 위와 같이 ref: ~ 형식의 글자가 출력된다. 그런데, 사용자의 명령을 통해 HEAD가 현재 브랜치의 최신 커밋이 아닌 다른 위치를 가리킬 수도 있다. 

$git checkout HEAD^
// 커밋 순서상 앞으로 1칸 거슬러 올라간다.

$git checkout hash~
// hash에 해당하는 커밋으로 이동한다.

$git checkout -
// 최근 커밋 이동을 되돌린다.

 

checkout HEAD^ 전과 후의 모습. HEAD가 가리키는 커밋이 변경되었다.
HEAD 자체도 변경되었다.

위 그림에서는 checkout 전후의 차이를 보여주고 있다.

  • checkout 전: HEAD가 master을 가리키고 있다.
  • checkout 후: HEAD가 baab0e2을 가리키고 있다.

이때 전자를 단순히 HEAD 라고 칭하고, 후자Detached HEAD 라 부른다.

 Detached HEAD 상태에서도 커밋이 가능하다. 그러나 해당 커밋이 우리의 브랜치 상에 자동으로 포함되지는 않는다.

 커밋을 시도한 위치는 우리의 기존 커밋이므로, 이후 연결되는 커밋이 이미 존재한다. 이런 상황에서 우리가 새로운 커밋을 만들면, Detached HEAD가 가리키는 커밋은 여러개의 파생 커밋을 가지게 된다. 이는 기존 커밋 상태와 충돌을 발생시키기 때문에, 깃은 Detached HEAD 상태에서 새로 생성한 커밋이 기존 브랜치와 연결되지 않도록 구성했다.

 새로 생성된 커밋은 기존 브랜치에 포함되는 대신 새로운 브랜치로 분할되어야 한다.  

위 사진의 test3은 Detached HEAD 상태에서 branch 명령을 통해 생성된 브랜치다.

branch 명령을 이용하면 기존 커밋들과 충돌없이 Detached HEAD 상태에서 생성한 커밋을 기존 트리에 추가할 수 있다.

 

원격 브랜치

 협업을 수행하기 위해 원격 저장소를 사용하는 경우, 서버상에 모든 사람이 공유하는 코드가 존재하고 각 유저는 해당 깃 레포지토리를 clone 해서 정보를 가져온다. 로컬에서 작성하는 코드는 수동 과정을 통해 원격 브랜치와 동기화된다.

 원격 저장소 상의 브랜치와 로컬 영역의 브랜치를 동기화할 때, 둘의 이름이 같을 수도 있으나 꼭 같을 필요는 없다. 이름이 다른 경우, 로컬 브랜치/원격 브랜치 형태로 이름이 나타난다.

위 그림의 경우, fdda6cd 커밋에 대해 로컬의 master 브랜치가 위치하고 있다. 로컬 영역의 깃 폴더에서 원격 저장소의 별칭(remote add를 통해 정한 이름)은 origin이며, 원격 저장소 상에 존재하는 브랜치 "test"에 대응된다.

다른 이름으로 push

$git push nickName branch_name:new_name

nickName의 이름을 가진 원격 저장소 ( remote add ) 에 로컬 브랜치 branch_name 을 new_name 이라는 이름으로 push한다. 로컬 영역의 branch_name 브랜치와 원격 저장소 상의 new_name 브랜치가 동기화된다.

다른 이름으로 clone

$git clone url dest

url 주소로부터 깃 레포지토리를 받아와 dest라는 폴더 이름으로 로컬에 저장한다. dest 를 명시하지 않으면, 원격 저장소 상에 저장된 이름으로 가져온다.

브랜치 정보 보기

$git branch -v // 커밋 정보와 함께 보기
$git branch -r // 원격 저장소에 대한 브랜치 목록 보기
$git branch -a // 모든 브랜치 보기
$git branch -vv // upstream 브랜치 보기

원격 브랜치 등록

 git clone 명령은 해당 url에 해당하는 깃 레포지토리의 master 브랜치만을 복사한다. 이런 이유로 master 브랜치 이외의 브랜치들은 로컬 깃 폴더와 동기화되지 않은 상태이므로 ( 위 사진의 붉은색 글씨로 된 브랜치들 ), 해당 브랜치를 사용하기 위해서는 동기화 과정이 필요하다.

$git checkout -t 원격저장소이름/브랜치이름

-t ( 혹은 --track ) 옵션을 빼먹으면 원격 저장소 위치로 HEAD 포인터를 단순히 이동하여 Detached HEAD 상태가 되므로, 동기화를 원하는 것이라면 -t 옵션을 잊지 말자.

-t 옵션 사용시 -b 옵션이 기본적으로 적용되며, 브랜치이름 으로 브랜치가 생성된다.

$git checkout -b 로컬브랜치이름 원격저장소이름/브랜치이름

-b 옵션은 브랜치를 생성하고, 해당 브랜치에 대해 checkout을 진행해준다. 원격 저장소의 브랜치와 로컬 브랜치를 연결해주며, 로컬 브랜치 이름과 브랜치 이름이 같다면 -t 옵션과 다를게 없는 것 같다.

원격 브랜치와 로컬 브랜치 동기화

$git branch -u 원격저장소이름/브랜치이름

원격 저장소에 새로운 브랜치가 있고, 로컬에 대응시킬 브랜치가 존재한다면 branch -u 명령으로 두 브랜치를 연결할 수 있다. 굳이 사용할 것 같지는 않은데, 서로간의 upstream을 이어준다.

tt와 origin/test4가 연결되었다.

브랜치 삭제

$git branch [-d|-D] branch_name

-D 옵션은 강제로 브랜치를 삭제할 때 사용된다.

-d 옵션은 병합된 브랜치에 대해서만 사용 가능하다.

$git push 원격저장소 -d 원격브랜치

push를 이용하여 원격 저장소 상의 원격 브랜치를 삭제할 수도 있다.

'잡다 > git' 카테고리의 다른 글

[git] WSL2 환경에서의 글로벌 .gitconfig  (0) 2022.02.23
[Git 09] Stash  (0) 2021.12.28
[Git 07] 서버  (0) 2021.12.27
[Git 06] Alias  (0) 2021.10.31
[Git 05] remote  (0) 2021.10.30